00001 /* 00002 * The information in this file is 00003 * Copyright(c) 2007 Ball Aerospace & Technologies Corporation 00004 * and is subject to the terms and conditions of the 00005 * GNU Lesser General Public License Version 2.1 00006 * The license text is available from 00007 * http://www.gnu.org/licenses/lgpl.html 00008 */ 00009 00010 #ifndef __SUBJECT_H 00011 #define __SUBJECT_H 00012 00013 #include "TypeAwareObject.h" 00014 00015 #include <string> 00016 00017 class SafeSlot; 00018 class Slot; 00019 00020 /** 00021 * This macro simplifies and standardizes creation of signal methods. This 00022 * macro will create a static method to use when attaching, detaching 00023 * and notifying. The full body of the method is created. For example: 00024 * @code 00025 * SIGNAL_METHOD(MyClass, MySignal) 00026 * @endcode 00027 * will create the following method: 00028 * @code 00029 * static const std::string &signalMySignal() { ... } 00030 * @endcode 00031 * 00032 * @param type 00033 * The class that the signal is emitted by 00034 * @param name 00035 * The unique name for the signal. 00036 */ 00037 #define SIGNAL_METHOD(type,name) \ 00038 static const std::string &signal##name() \ 00039 { \ 00040 static std::string signalName(#type "::" #name); \ 00041 return signalName;\ 00042 } 00043 00044 /** 00045 * This macro simplifies specifying a particular signal. For example: 00046 * @code 00047 * notify(SIGNAL_NAME(MyClass, MySignal)); 00048 * @endcode 00049 * notifies with the signal created with 00050 * @code 00051 * SIGNAL_METHOD(MyClass, MySignal) 00052 * @endcode 00053 * 00054 * @param type 00055 * The class that the signal is emitted by 00056 * @param name 00057 * The unique name for the signal. 00058 */ 00059 #define SIGNAL_NAME(type,name) type::signal##name() 00060 00061 /** 00062 * Base class for objects to send notification when their data changes 00063 * 00064 * Generalized interface for objects that can notify observers 00065 * when changes have been made. It provides a uniform means for 00066 * letting other objects register an interest in the contents 00067 * of this object's contents. 00068 * 00069 * Each %Subject has signals that it will emit under certain circumstances. 00070 * When a signal is emitted, all slots attached to that signal on the %Subject 00071 * will be called. For example: 00072 * @code 00073 * pSubject->attach(SIGNAL_NAME(Subject, Modified), Slot(pObj, &Obj::mySlot)); 00074 * @endcode 00075 * This will cause pObj->mySlot(*pSubject, "Subject::Modified", v) to be called 00076 * whenever pSubject emits SIGNAL_NAME(Subject, Modified). 00077 * 00078 * Whenever a signal other than Subject::Modified or Subject::Deleted is 00079 * emitted, Subject::Modified will also be emitted. 00080 * This means that all slots attached to Subject::signalModified on a 00081 * %Subject of type MyClass will be called when that MyClass object 00082 * emits SIGNAL_NAME(MyClass, MySignal). 00083 * 00084 * Signals for a particular instance of a %Subject can be supressed by using 00085 * either the SignalBlocker or SignalEnabler classes. 00086 * 00087 * The notification of slots is done in two passes. 00088 * First, all slots attached to the specific signal are notified in FIFO 00089 * order (First In == first attached, and First Out == first notified). 00090 * Then, assuming the specific signal is not Subject::Deleted or 00091 * Subject::Modified, all slots attached to Subject::Modified 00092 * are notified in FIFO order. 00093 00094 * @see TypeAwareObject, Slot, SafeSlot, AutoSlot, Signal, SignalBlocker, SignalEnabler 00095 */ 00096 class Subject : public TypeAwareObject 00097 { 00098 public: 00099 /** 00100 * Emitted when a %Subject is deleted. This will always be emitted, it CANNOT 00101 * be blocked using SignalBlocker or SignalEnabler. 00102 */ 00103 SIGNAL_METHOD(Subject, Deleted) 00104 /** 00105 * Emitted when a %Subject is modified. Anytime a signal other than deleted 00106 * or modified is notified, signalModified will be notified as well. 00107 */ 00108 SIGNAL_METHOD(Subject, Modified) 00109 00110 /** 00111 * Allow another object to register an interest in specific changes on 00112 * this %Subject. 00113 * 00114 * @param signal 00115 * The name of the signal to attach to. If signal is empty, the 00116 * Slot will be called on all signals from this %Subject. 00117 * 00118 * @param slot 00119 * An object that contains the object and method to call when the 00120 * specified signal is notified. This can be a Slot, SafeSlot or 00121 * AutoSlot. 00122 * 00123 * @return true if the Slot was valid and was not already attached to 00124 * the signal on the subject and false otherwise. 00125 * 00126 * @notify This method will call Observer::attached on the object in 00127 * the slot, if the object inherits Observer. 00128 */ 00129 virtual bool attach(const std::string& signal, const Slot& slot) = 0; 00130 00131 /** 00132 * Allow a Slot to be deregistered from a signal on this %Subject. 00133 * 00134 * @param signal 00135 * The name of the signal the Slot is attached to. If signal is 00136 * empty, the specified Slot will be detached from all signals on 00137 * this %Subject. 00138 * 00139 * @param slot 00140 * The Slot to detach from the specified signal. If the Slot is 00141 * empty, all slots will be detached from the specified signal. 00142 * If the slot was originally attached as a SafeSlot or AutoSlot, 00143 * it needs to be detached as same type. 00144 * 00145 * @return true if the Slot was attached to the specified signal on the 00146 * subject. 00147 * 00148 * @notify This method will call Observer::detached on the object in 00149 * the slot, if the object inherits Observer. 00150 */ 00151 virtual bool detach(const std::string& signal, const Slot& slot) = 0; 00152 00153 /** 00154 * Indicates whether the Subject's notification mechanism is enabled or not. 00155 * If signals are disabled, then only SIGNAL_NAME(Subject, Deleted) will be 00156 * emitted when requested, all other signals will be suppressed. 00157 * 00158 * To disable signals, either the SignalBlocker or SignalEnabler classes 00159 * must be used. 00160 * 00161 * @warning Disabling signals can be very dangerous as it hides details from 00162 * any attached slots which may depend on being notified to 00163 * function properly. 00164 * 00165 * @see SignalBlocker, SignalEnabler 00166 * @return true if the Subject's notification is enabled, or false otherwise. 00167 */ 00168 virtual bool signalsEnabled() const = 0; 00169 00170 protected: 00171 /** 00172 * This should not be deleted directly. It should be deleted according to 00173 * the instructions provided for the relevant subclass. 00174 */ 00175 virtual ~Subject() {} 00176 00177 private: 00178 /** 00179 * Allows the notification of signals by a Subject to be enabled or disabled. 00180 * 00181 * @param enabled 00182 * Controls whether the Subject will notify or not when its notify 00183 * method is called. 00184 */ 00185 virtual void enableSignals(bool enabled) = 0; 00186 00187 friend class SignalEnabler; 00188 friend class SignalBlocker; 00189 #ifdef CPPTESTS 00190 friend class SubjectObserverTest; 00191 #endif 00192 }; 00193 00194 #endif