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 ATTACHMENTPTR_H 00011 #define ATTACHMENTPTR_H 00012 00013 #include "SafePtr.h" 00014 00015 #include <string> 00016 #include <vector> 00017 #include <utility> 00018 00019 /** 00020 * Smart pointer used to simplify Subject attachment lifetimes. 00021 * 00022 * This class handles a number of issues relating to the management of 00023 * Subject attachment lifetimes: 00024 * - Detaching from the Subject upon destruction. 00025 * - Changing attachments when the observed instance changed, including 00026 * attachments made within subclasses of the observer. 00027 * - Detecting when the Subject is deleted to prevent stale pointers. 00028 * 00029 * This class is intended to be used as a member variable, in place of a raw 00030 * pointer to the observed Subject. If subclasses are to be allowed to attach 00031 * to the Subject, the variable should be made protected. 00032 * 00033 * Note that this class will not cause any kind of callback in the case 00034 * that its Subject has been deleted. It will simply NULLify the pointer. 00035 * If you require any special handling for when the Subject has been deleted, 00036 * You should separately attach to SIGNAL_NAME(Subject, Deleted) with 00037 * AttachmentPtr::addSignal(). 00038 * 00039 * When used in conjunction with a SafeSlot, the attachments will additionally be 00040 * automatically detached when the SafeSlot's invalidator object is destroyed. 00041 */ 00042 template<typename T> 00043 class AttachmentPtr : public SafePtr<T> 00044 { 00045 public: 00046 /** 00047 * Default constructor. 00048 * 00049 * No Subject is observed. 00050 */ 00051 AttachmentPtr() : SafePtr<T>(NULL) 00052 { 00053 } 00054 00055 /** 00056 * Construct with a subject to observe. 00057 * 00058 * @param pSubject 00059 * The subject to observe. 00060 */ 00061 AttachmentPtr(T* pSubject) : 00062 SafePtr<T>(pSubject) 00063 { 00064 } 00065 00066 /** 00067 * Construct with a single signal/slot connection registered, 00068 * no Subject observed. 00069 * 00070 * @param signalName 00071 * The signal to register interest in. 00072 * @param slot 00073 * The slot to call when the signal is emitted. 00074 */ 00075 AttachmentPtr(const std::string& signalName, const Slot& slot) : SafePtr<T>(NULL), 00076 mSignalSlots(1, std::make_pair(signalName, slot)) 00077 { 00078 } 00079 00080 /** 00081 * Construct with a subject to observe, and a single signal/slot 00082 * connection registered. 00083 * 00084 * @param pSubject 00085 * The subject to observe. 00086 * @param signalName 00087 * The signal to register interest in. 00088 * @param slot 00089 * The slot to call when the signal is emitted. 00090 */ 00091 AttachmentPtr(T* pSubject, const std::string& signalName, const Slot& slot) : SafePtr<T>(pSubject), 00092 mSignalSlots(1, std::make_pair(signalName, slot)) 00093 { 00094 SafePtr<T>::attach(signalName, slot); 00095 } 00096 00097 /** 00098 * Destructor. 00099 * 00100 * This will take care of detaching from any signals. 00101 */ 00102 virtual ~AttachmentPtr() 00103 { 00104 reset(NULL); 00105 } 00106 00107 /** 00108 * Add a new signal to be observed. 00109 * 00110 * The attachment will be made immediately if there is currently a valid 00111 * Subject. The attachment will automatically be made whenever the 00112 * observed Subject is changed. 00113 * 00114 * @param signalName 00115 * The signal to register interest in. 00116 * @param slot 00117 * The slot to call when the signal is emitted. 00118 */ 00119 void addSignal(const std::string& signalName, const Slot& slot) 00120 { 00121 mSignalSlots.push_back(std::make_pair(signalName, slot)); 00122 00123 SafePtr<T>::attach(signalName, slot); 00124 } 00125 00126 /** 00127 * Change what Subject to observe. 00128 * 00129 * This will automatically detach from the old Subject, and attach to 00130 * the new one. 00131 * 00132 * @param pSubject 00133 * The subject to begin observing. 00134 */ 00135 void reset(T* pSubject = NULL) 00136 { 00137 if (pSubject != SafePtr<T>::get()) 00138 { 00139 for (std::vector<std::pair<std::string, Slot> >::const_iterator iter = mSignalSlots.begin(); 00140 iter != mSignalSlots.end(); ++iter) 00141 { 00142 SafePtr<T>::detach(iter->first, iter->second); 00143 } 00144 SafePtr<T>::reset(pSubject); 00145 for (std::vector<std::pair<std::string, Slot> >::const_iterator iter = mSignalSlots.begin(); 00146 iter != mSignalSlots.end(); ++iter) 00147 { 00148 SafePtr<T>::attach(iter->first, iter->second); 00149 } 00150 } 00151 } 00152 00153 private: 00154 AttachmentPtr(const AttachmentPtr&); 00155 AttachmentPtr& operator=(const AttachmentPtr&); 00156 00157 std::vector<std::pair<std::string, Slot> > mSignalSlots; 00158 }; 00159 00160 #endif