File indexing completed on 2024-04-28 16:08:33

0001 /***************************************************************************
0002  *   Copyright (C) 2013 by Linuxstopmotion contributors;                   *
0003  *   see the AUTHORS file for details.                                     *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 
0021 #include "observernotifier.h"
0022 #include "animation/animationimpl.h"
0023 #include "animation/frame.h"
0024 #include "animation/workspacefile.h"
0025 #include "src/presentation/observer.h"
0026 #include "src/presentation/frontends/frontend.h"
0027 #include "src/foundation/logger.h"
0028 
0029 #include <exception>
0030 
0031 class FileNameVisitor;
0032 class Scene;
0033 class Sound;
0034 
0035 class ObservableOperation {
0036 public:
0037     virtual ~ObservableOperation() {
0038     }
0039     /**
0040      * Performs the operation.
0041      */
0042     virtual void op(AnimationImpl&) = 0;
0043     /**
0044      * Performs the update on the specified observer.
0045      */
0046     virtual void update(Observer&) = 0;
0047 };
0048 
0049 void ObserverNotifier::doOp(ObservableOperation& oo) {
0050     oo.op(*del);
0051     // exceptions must not escape from here, or we might lose an object that
0052     // is of importance to the undo system.
0053     for (observers_t::iterator i = observers.begin();
0054             i != observers.end(); ++i) {
0055         try {
0056             oo.update(**i);
0057         } catch (std::exception& e) {
0058             try {
0059                 if (frontend)
0060                     frontend->reportWarning(e.what());
0061             } catch (...) {
0062             }
0063             for (observers_t::iterator i = observers.begin();
0064                     i != observers.end(); ++i) {
0065                 (*i)->resync();
0066             }
0067         }
0068     }
0069 }
0070 
0071 ObserverNotifier::~ObserverNotifier() {
0072     delete del;
0073 }
0074 
0075 ObserverNotifier::ObserverNotifier(AnimationImpl* delegate, Frontend* fe)
0076         : del(delegate), frontend(fe) {
0077 }
0078 
0079 void ObserverNotifier::addObserver(Observer* newObserver) {
0080     observers.push_back(newObserver);
0081 }
0082 
0083 void ObserverNotifier::removeObserver(Observer* o) {
0084     for (std::vector<Observer*>::iterator i = observers.begin();
0085             i != observers.end(); ++i) {
0086         if (*i == o) {
0087             observers.erase(i);
0088             return;
0089         }
0090     }
0091     Logger::get().logWarning("Failed to find Observer to remove");
0092 }
0093 
0094 class AnimationClearer : public ObservableOperation {
0095 public:
0096     AnimationClearer() {
0097     }
0098     void op(AnimationImpl& del) {
0099         del.clear();
0100     }
0101     void update(Observer& ob) {
0102         ob.updateClear();
0103     }
0104 };
0105 
0106 void ObserverNotifier::clear() {
0107     AnimationClearer ac;
0108     doOp(ac);
0109 }
0110 
0111 int ObserverNotifier::sceneCount() const {
0112     return del->sceneCount();
0113 }
0114 
0115 class SceneAdder : public ObservableOperation {
0116     int n;
0117     Scene* s;
0118 public:
0119     SceneAdder(int where, Scene* sc) : n(where), s(sc) {
0120     }
0121     void op(AnimationImpl& del) {
0122         if (s)
0123             del.addScene(n, s);
0124         else
0125             del.addScene(n);
0126     }
0127     void update(Observer& ob) {
0128         ob.updateNewScene(n);
0129     }
0130 };
0131 
0132 void ObserverNotifier::addScene(int where, Scene* newScene) {
0133     SceneAdder sa(where, newScene);
0134     doOp(sa);
0135 }
0136 
0137 void ObserverNotifier::addScene(int where) {
0138     SceneAdder sa(where, 0);
0139     doOp(sa);
0140 }
0141 
0142 void ObserverNotifier::preallocateScenes(int count) {
0143     del->preallocateScenes(count);
0144 }
0145 
0146 class SceneRemover : public ObservableOperation {
0147     int sc;
0148 public:
0149     Scene* r;
0150     SceneRemover(int from) : sc(from), r(0) {
0151     }
0152     void op(AnimationImpl& del) {
0153         r = del.removeScene(sc);
0154     }
0155     void update(Observer& ob) {
0156         ob.updateRemoveScene(sc);
0157     }
0158 };
0159 
0160 Scene* ObserverNotifier::removeScene(int from) {
0161     SceneRemover sr(from);
0162     doOp(sr);
0163     return sr.r;
0164 }
0165 
0166 class SceneMover : public ObservableOperation {
0167     int f;
0168     int t;
0169 public:
0170     SceneMover(int from, int to) : f(from), t(to) {
0171     }
0172     void op(AnimationImpl& del) {
0173         del.moveScene(f, t);
0174     }
0175     void update(Observer& ob) {
0176         ob.updateMoveScene(f, t);
0177     }
0178 };
0179 
0180 void ObserverNotifier::moveScene(int from, int to) {
0181     SceneMover sm(from, to);
0182     doOp(sm);
0183 }
0184 
0185 const Scene* ObserverNotifier::getScene(int which) const {
0186     return del->getScene(which);
0187 }
0188 
0189 int ObserverNotifier::frameCount(int scene) const {
0190     return del->frameCount(scene);
0191 }
0192 
0193 class FrameAdder : public ObservableOperation {
0194     int sc;
0195     int n;
0196     const std::vector<Frame*>& frs;
0197 public:
0198     FrameAdder(int scene, int where, const std::vector<Frame*>& frames)
0199             : sc(scene), n(where), frs(frames) {
0200     }
0201     ~FrameAdder() {
0202     }
0203     void op(AnimationImpl& del) {
0204         del.addFrames(sc, n, frs);
0205     }
0206     void update(Observer& ob) {
0207         int count = frs.size();
0208         ob.updateAdd(sc, n, count);
0209     }
0210 };
0211 
0212 void ObserverNotifier::addFrame(int scene, int where, Frame* frame) {
0213     std::vector<Frame*> frs;
0214     frs.push_back(frame);
0215     FrameAdder fa(scene, where, frs);
0216     doOp(fa);
0217 }
0218 
0219 void ObserverNotifier::addFrames(int scene, int where,
0220         const std::vector<Frame*>& frames) {
0221     FrameAdder fa(scene, where, frames);
0222     doOp(fa);
0223 }
0224 
0225 void ObserverNotifier::preallocateFrames(int scene, int count) {
0226     del->preallocateFrames(scene, count);
0227 }
0228 
0229 class FrameRemover : public ObservableOperation {
0230     int sc;
0231     int n;
0232     Frame* r;
0233 public:
0234     FrameRemover(int scene, int where)
0235             : sc(scene), n(where), r(0) {
0236     }
0237     ~FrameRemover() {
0238         delete r;
0239     }
0240     Frame* release() {
0241         Frame* v = r;
0242         r = 0;
0243         return v;
0244     }
0245     void op(AnimationImpl& del) {
0246         del.removeFrame(sc, n);
0247     }
0248     void update(Observer& ob) {
0249         ob.updateRemove(sc, n, n);
0250     }
0251 };
0252 
0253 Frame* ObserverNotifier::removeFrame(int scene, int frame) {
0254     FrameRemover fr(scene, frame);
0255     doOp(fr);
0256     return fr.release();
0257 }
0258 
0259 class FramesRemover : public ObservableOperation {
0260     int sc;
0261     int fr;
0262     int c;
0263     std::vector<Frame*>& r;
0264 public:
0265     FramesRemover(int scene, int where, int count, std::vector<Frame*>& out)
0266             : sc(scene), fr(where), c(count), r(out) {
0267     }
0268     ~FramesRemover() {
0269     }
0270     void op(AnimationImpl& del) {
0271         del.removeFrames(sc, fr, c, r);
0272     }
0273     void update(Observer& ob) {
0274         ob.updateRemove(sc, fr, fr + c - 1);
0275     }
0276 };
0277 
0278 void ObserverNotifier::removeFrames(int scene, int frame, int count,
0279         std::vector<Frame*>& out) {
0280     FramesRemover fr(scene, frame, count, out);
0281     doOp(fr);
0282 }
0283 
0284 class FrameMover : public ObservableOperation {
0285     int fromSc;
0286     int fromFr;
0287     int c;
0288     int toSc;
0289     int toFr;
0290 public:
0291     FrameMover(int fromScene, int fromFrame, int count,
0292             int toScene, int toFrame)
0293             : fromSc(fromScene), fromFr(fromFrame), c(count),
0294               toSc(toScene), toFr(toFrame) {
0295     }
0296     ~FrameMover() {
0297     }
0298     void op(AnimationImpl& del) {
0299         del.moveFrames(fromSc, fromFr, c, toSc, toFr);
0300     }
0301     void update(Observer& ob) {
0302         ob.updateMove(fromSc, fromFr, c, toSc, toFr);
0303     }
0304 };
0305 
0306 void ObserverNotifier::moveFrames(int fromScene, int fromFrame, int frameCount,
0307         int toScene, int toFrame) {
0308     FrameMover fm(fromScene, fromFrame, frameCount, toScene, toFrame);
0309     doOp(fm);
0310 }
0311 
0312 class FrameReplacer : public ObservableOperation {
0313     int sc;
0314     int fr;
0315     WorkspaceFile& image;
0316 public:
0317     FrameReplacer(int scene, int where, WorkspaceFile& newImage)
0318             : sc(scene), fr(where), image(newImage) {
0319     }
0320     ~FrameReplacer() {
0321     }
0322     void op(AnimationImpl& del) {
0323         if (image.path())
0324             del.replaceImage(sc, fr, image);
0325     }
0326     void update(Observer& ob) {
0327         ob.updateAnimationChanged(sc, fr);
0328     }
0329 };
0330 
0331 void ObserverNotifier::replaceImage(int sceneNumber, int frameNumber,
0332         WorkspaceFile& otherImage) {
0333     FrameReplacer fr(sceneNumber, frameNumber, otherImage);
0334     doOp(fr);
0335 }
0336 
0337 int ObserverNotifier::soundCount(int scene, int frame) const {
0338     return del->soundCount(scene, frame);
0339 }
0340 
0341 class SoundChanger : public ObservableOperation {
0342     int sc;
0343     int fr;
0344 public:
0345     SoundChanger(int scene, int frame)
0346             : sc(scene), fr(frame) {
0347     }
0348     ~SoundChanger() {
0349     }
0350     void op(AnimationImpl&) {
0351     }
0352     void update(Observer& ob) {
0353         ob.updateSoundChanged(sc, fr);
0354     }
0355     int scene() const {
0356         return sc;
0357     }
0358     int frame() const {
0359         return fr;
0360     }
0361 };
0362 
0363 class SoundAdder : public SoundChanger {
0364     int sn;
0365     Sound* s;
0366 public:
0367     SoundAdder(int scene, int frame, int soundNumber, Sound* sound)
0368             : SoundChanger(scene, frame), sn(soundNumber), s(sound) {
0369     }
0370     void op(AnimationImpl& del) {
0371         del.addSound(scene(), frame(), sn, s);
0372     }
0373 };
0374 
0375 void ObserverNotifier::addSound(int scene, int frame, int soundNumber,
0376         Sound* sound) {
0377     SoundAdder adder(scene, frame, soundNumber, sound);
0378     doOp(adder);
0379 }
0380 
0381 class SoundNamer : public SoundChanger {
0382     int sn;
0383     const char* nm;
0384     const char* r;
0385 public:
0386     SoundNamer(int scene, int frame, int soundNumber, const char* name)
0387             : SoundChanger(scene, frame), sn(soundNumber), nm(name), r(0) {
0388     }
0389     void op(AnimationImpl& del) {
0390         r = del.setSoundName(scene(), frame(), sn, nm);
0391     }
0392     const char* returnValue() const {
0393         return r;
0394     }
0395 };
0396 
0397 const char* ObserverNotifier::setSoundName(int scene, int frame,
0398         int soundNumber, const char* soundName) {
0399     SoundNamer sn(scene, frame, soundNumber, soundName);
0400     doOp(sn);
0401     return sn.returnValue();
0402 }
0403 
0404 class SoundRemover : public SoundChanger {
0405     int sn;
0406     Sound* r;
0407 public:
0408     SoundRemover(int scene, int frame, int soundNumber)
0409             : SoundChanger(scene, frame), sn(soundNumber), r(0) {
0410     }
0411     void op(AnimationImpl& del) {
0412         r = del.removeSound(scene(), frame(), sn);
0413     }
0414     Sound* returnValue() const {
0415         return r;
0416     }
0417 };
0418 
0419 Sound* ObserverNotifier::removeSound(int scene, int frame, int soundNumber) {
0420     SoundRemover sr(scene, frame, soundNumber);
0421     doOp(sr);
0422     return sr.returnValue();
0423 }
0424 
0425 void ObserverNotifier::registerFrontend(Frontend* fe) {
0426     frontend = fe;
0427 }
0428 
0429 class AnimationResynchronizer : public ObservableOperation {
0430 public:
0431     AnimationResynchronizer() {
0432     }
0433     void op(AnimationImpl&) {
0434     }
0435     void update(Observer& ob) {
0436         ob.resync();
0437     }
0438 };
0439 
0440 void ObserverNotifier::resync() {
0441     AnimationResynchronizer resyncher;
0442     doOp(resyncher);
0443 }
0444 
0445 int ObserverNotifier::soundCount() const {
0446     return del->soundCount();
0447 }
0448 
0449 void ObserverNotifier::playSounds(int scene, int frame, AudioDriver* audioDriver) const {
0450     del->playSounds(scene, frame, audioDriver);
0451 }
0452 
0453 void ObserverNotifier::accept(FileNameVisitor& v) const {
0454     del->accept(v);
0455 }