~valavanisalex/ubuntu/maverick/scidavis/fix-604811

« back to all changes in this revision

Viewing changes to scidavis/src/future/core/AbstractAspect.h

  • Committer: Bazaar Package Importer
  • Author(s): Ruben Molina
  • Date: 2009-09-06 11:34:04 UTC
  • Revision ID: james.westby@ubuntu.com-20090906113404-4awaey82l3686w4q
Tags: upstream-0.2.3
ImportĀ upstreamĀ versionĀ 0.2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    File                 : AbstractAspect.h
 
3
    Project              : SciDAVis
 
4
    --------------------------------------------------------------------
 
5
    Copyright            : (C) 2007 by Knut Franke, Tilman Benkert
 
6
    Email (use @ for *)  : knut.franke*gmx.de, thzs*gmx.net
 
7
    Description          : Base class for all persistent objects in a Project.
 
8
 
 
9
 ***************************************************************************/
 
10
 
 
11
/***************************************************************************
 
12
 *                                                                         *
 
13
 *  This program is free software; you can redistribute it and/or modify   *
 
14
 *  it under the terms of the GNU General Public License as published by   *
 
15
 *  the Free Software Foundation; either version 2 of the License, or      *
 
16
 *  (at your option) any later version.                                    *
 
17
 *                                                                         *
 
18
 *  This program is distributed in the hope that it will be useful,        *
 
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 
21
 *  GNU General Public License for more details.                           *
 
22
 *                                                                         *
 
23
 *   You should have received a copy of the GNU General Public License     *
 
24
 *   along with this program; if not, write to the Free Software           *
 
25
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 
26
 *   Boston, MA  02110-1301  USA                                           *
 
27
 *                                                                         *
 
28
 ***************************************************************************/
 
29
#ifndef ABSTRACT_ASPECT_H
 
30
#define ABSTRACT_ASPECT_H
 
31
 
 
32
#include <QObject>
 
33
#include <QDateTime>
 
34
 
 
35
class AspectPrivate;
 
36
class Project;
 
37
class QUndoStack;
 
38
class QString;
 
39
class QDateTime;
 
40
class QUndoCommand;
 
41
class QIcon;
 
42
class QMenu;
 
43
namespace future{
 
44
class Folder;
 
45
}
 
46
class XmlStreamReader;
 
47
#ifdef Q_OS_MAC32
 
48
// A hack in Qt 4.4 and later forces us to include QXmlStream* headers on MacOS instead of simple
 
49
// forward declarations. See
 
50
// http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html
 
51
#include <QXmlStreamWriter>
 
52
#else
 
53
class QXmlStreamWriter;
 
54
#endif
 
55
class QAction;
 
56
 
 
57
//! Base class of all persistent objects in a Project.
 
58
/**
 
59
 * Before going into the details, it's useful to understand the ideas behind the
 
60
 * \ref aspect "Aspect Framework".
 
61
 *
 
62
 * Aspects organize themselves into trees, where a parent takes ownership of its children. Usually,
 
63
 * though not necessarily, a Project instance will sit at the root of the tree (without a Project
 
64
 * ancestor, project() will return 0 and undo does not work). Children are organized using
 
65
 * addChild(), removeChild(), child(), indexOfChild() and childCount() on the parent's side as well
 
66
 * as the equivalent convenience methods index() and remove() on the child's side.
 
67
 * 
 
68
 * AbstractAspect manages for every Aspect the properties #name, #comment, #caption_spec and
 
69
 * #creation_time. All of these translate into the caption() as described in the documentation
 
70
 * of setCaptionSpec().
 
71
 *
 
72
 * If an undoStack() can be found (usually it is managed by Project), changes to the properties
 
73
 * as well as adding/removing children support multi-level undo/redo. In order to support undo/redo
 
74
 * for problem-specific data in derived classes, make sure that all changes to your data are done
 
75
 * by handing appropriate commands to exec().
 
76
 *
 
77
 * Optionally,
 
78
 * you can supply an icon() to be used by different views (including the ProjectExplorer)
 
79
 * and/or reimplement createContextMenu() for a custom context menu of views.
 
80
 *
 
81
 * The private data of AbstractAspect is contained in a separate class AbstractAspect::Private. 
 
82
 * The write access to AbstractAspect::Private should always be done using aspect commands
 
83
 * to allow undo/redo.
 
84
 */
 
85
class AbstractAspect : public QObject
 
86
{
 
87
        Q_OBJECT
 
88
 
 
89
        public:
 
90
                class Private;
 
91
                friend class Private;
 
92
 
 
93
                AbstractAspect(const QString &name);
 
94
                virtual ~AbstractAspect();
 
95
 
 
96
                //! Return my parent Aspect or 0 if I currently don't have one.
 
97
                AbstractAspect * parentAspect() const;
 
98
                //! Return the folder the Aspect is contained in or 0 if not.
 
99
                /**
 
100
                 * The returned folder may be the aspect itself if it inherits Folder.
 
101
                */
 
102
                future::Folder * folder();
 
103
                //! Return whether the there is a path upwards to the given aspect
 
104
                /**
 
105
                 * This also returns true if other==this.
 
106
                 */
 
107
                bool isDescendantOf(AbstractAspect *other);
 
108
 
 
109
                //! Add the given Aspect to my list of children.
 
110
                void addChild(AbstractAspect* child);
 
111
                //! Insert the given Aspect at a specific position in my list of children.
 
112
                void insertChild(AbstractAspect *child, int index);
 
113
                //! Remove the given Aspect from my list of children.
 
114
                /**
 
115
                 * Usually, the ownership of the child is transfered to the undo command,
 
116
                 * i.e., the aspect is deleted by the undo command. But by setting detach
 
117
                 * to true, you can remove a child from the Aspect tree without deleting
 
118
                 * it. Of course, that means whovere detaches an Aspect in responsible
 
119
                 * for deleting it (or re-attaching it somewhere in the tree).
 
120
                 * \sa reparentChild()
 
121
                 */
 
122
                void removeChild(AbstractAspect* child, bool detach=false);
 
123
                //! Remove the Aspect at the given index from my list of children.
 
124
                /**
 
125
                 * The ownership of the child is transfered to the undo command,
 
126
                 * i.e., the aspect is deleted by the undo command.
 
127
                 * \sa reparentChild()
 
128
                 */
 
129
                void removeChild(int index);
 
130
                //! Get a child by its position in my list of children.
 
131
                AbstractAspect* child(int index) const;
 
132
                //! Return the number of child Aspects.
 
133
                int childCount() const;
 
134
                //! Return the position of child in my list of children.
 
135
                int indexOfChild(const AbstractAspect * child) const;
 
136
                //! Return my position in my parent's list of children.
 
137
                int index() const { return parentAspect() ? parentAspect()->indexOfChild(this) : 0; }
 
138
                //! Change the positon of a child in my list of children.
 
139
                void moveChild(int from, int to);
 
140
                //! Move a child to another aspect and transfer ownership.
 
141
                void reparentChild(AbstractAspect *new_parent, AbstractAspect *child, int d_new_index);
 
142
                //! Move a child to another aspect and transfer ownership.
 
143
                void reparentChild(AbstractAspect *new_parent, AbstractAspect *child);
 
144
                //! Get all descendents that inherit the given class
 
145
                QList<AbstractAspect *> descendantsThatInherit(const char *class_name);
 
146
                //! Remove all child aspects
 
147
                virtual void removeAllChildAspects();
 
148
 
 
149
                //! Return the Project this Aspect belongs to, or 0 if it is currently not part of one.
 
150
                virtual const Project *project() const { return parentAspect() ? parentAspect()->project() : 0; }
 
151
                //! Return the Project this Aspect belongs to, or 0 if it is currently not part of one.
 
152
                virtual Project *project() { return parentAspect() ? parentAspect()->project() : 0; }
 
153
                //! Return the path that leads from the top-most Aspect (usually a Project) to me.
 
154
                virtual QString path() const { return parentAspect() ? parentAspect()->path() + "/" + name() : "";  }
 
155
 
 
156
                //! Return an icon to be used for decorating my views.
 
157
                virtual QIcon icon() const;
 
158
                //! Return a new context menu.
 
159
                /**
 
160
                 * The caller takes ownership of the menu.
 
161
                 */
 
162
                virtual QMenu *createContextMenu() const;
 
163
 
 
164
                QString name() const;
 
165
                QString comment() const;
 
166
                //! Return the specification string used for constructing the caption().
 
167
                /**
 
168
                 * See setCaptionSpec() for format.
 
169
                 */
 
170
                QString captionSpec() const;
 
171
                QDateTime creationTime() const;
 
172
                QString caption() const;
 
173
 
 
174
                //! \name undo related
 
175
                //@{
 
176
                //! Return the undo stack of the Project, or 0 if this Aspect is not part of a Project.
 
177
                /**
 
178
                 * It's also possible to construct undo-enabled Aspect trees without Project.
 
179
                 * The only requirement is that the root Aspect reimplements undoStack() to get the
 
180
                 * undo stack from somewhere (the default implementation just delegates to parentAspect()).
 
181
                 */
 
182
                virtual QUndoStack *undoStack() const { return parentAspect() ? parentAspect()->undoStack() : 0; }
 
183
                //! Execute the given command, pushing it on the undoStack() if available.
 
184
                void exec(QUndoCommand *command);
 
185
                //! Begin an undo stack macro (series of commands)
 
186
                void beginMacro(const QString& text);
 
187
                //! End the undo stack macro
 
188
                void endMacro();
 
189
                //@}
 
190
 
 
191
                //! Retrieve a global setting.
 
192
                static QVariant global(const QString &key);
 
193
                //! Update a global setting.
 
194
                static void setGlobal(const QString &key, const QVariant &value);
 
195
                //! Set default value for a global setting.
 
196
                static void setGlobalDefault(const QString &key, const QVariant &value);
 
197
 
 
198
                //! \name serialize/deserialize
 
199
                //@{
 
200
                //! Save as XML
 
201
                virtual void save(QXmlStreamWriter *) const {};
 
202
                //! Load from XML
 
203
                /**
 
204
                 * XmlStreamReader supports errors as well as warnings. If only
 
205
                 * warnings (non-critial errors) occur, this function must return 
 
206
                 * the reader at the end element corresponding to the current 
 
207
                 * element at the time the function was called. 
 
208
                 *
 
209
                 * This function is normally intended to be called directly 
 
210
                 * after the ctor. If you want to call load on an aspect that
 
211
                 * has been altered, you must make sure beforehand that
 
212
                 * it is in the same state as after creation, e.g., remove
 
213
                 * all its child aspects.
 
214
                 *
 
215
                 * \return false on error
 
216
                 */
 
217
                virtual bool load(XmlStreamReader *) { return false; };
 
218
        protected:
 
219
                //! Load name, creation time and caption spec from XML
 
220
                /**
 
221
                 * \return false on error
 
222
                 */
 
223
                bool readBasicAttributes(XmlStreamReader * reader);
 
224
                //! Save name, creation time and caption spec to XML
 
225
                void writeBasicAttributes(QXmlStreamWriter * writer) const;
 
226
                //! Save the comment to XML
 
227
                void writeCommentElement(QXmlStreamWriter * writer) const;
 
228
                //! Load comment from an XML element
 
229
                bool readCommentElement(XmlStreamReader * reader);
 
230
                //@}
 
231
 
 
232
        public slots:
 
233
                void setName(const QString &value);
 
234
                void setComment(const QString &value);
 
235
                //! Set the specification string used for constructing the caption().
 
236
                /**
 
237
                 * The caption is constructed by substituting some magic tokens in the specification:
 
238
                 *
 
239
                 * - \%n - name()
 
240
                 * - \%c - comment()
 
241
                 * - \%t - creationTime()
 
242
                 *
 
243
                 * Additionally, you can use the construct %C{<text>}. <text> is only shown in the caption
 
244
                 * if comment() is not empty (name and creation time should never be empty).
 
245
                 *
 
246
                 * The default caption specification is "%n%C{ - }%c".
 
247
                 */
 
248
                void setCaptionSpec(const QString &value);
 
249
                //! Remove me from my parent's list of children.
 
250
                virtual void remove() { if(parentAspect()) parentAspect()->removeChild(parentAspect()->indexOfChild(this)); }
 
251
                //! Make the specified name unique among my children by incrementing a trailing number.
 
252
                QString uniqueNameFor(const QString &current_name) const;
 
253
 
 
254
        public:
 
255
                void importV0x0001XXCreationTime(const QString& str)
 
256
                {
 
257
                        setCreationTime(QDateTime::fromString(str, Qt::LocalDate));
 
258
                }
 
259
 
 
260
 
 
261
        signals:
 
262
                //! Emit this before the name, comment or caption spec is changed
 
263
                void aspectDescriptionAboutToChange(const AbstractAspect *aspect);
 
264
                //! Emit this when the name, comment or caption spec changed
 
265
                void aspectDescriptionChanged(const AbstractAspect *aspect);
 
266
                //! Emit this when a parent aspect is about to get a new child inserted
 
267
                void aspectAboutToBeAdded(const AbstractAspect *parent, int index);
 
268
                //! Emit this from a newly added aspect
 
269
                void aspectAdded(const AbstractAspect *aspect);
 
270
                //! Emit this from a parent after adding a new child to it
 
271
                void aspectAdded(const AbstractAspect *parent, int index);
 
272
                //! Emit this from an aspect about to be removed from its parent's children
 
273
                void aspectAboutToBeRemoved(const AbstractAspect *aspect);
 
274
                //! Emit this from a parent before removing its child
 
275
                void aspectAboutToBeRemoved(const AbstractAspect *parent, int index);
 
276
                //! Emit this from the parent after removing a child
 
277
                void aspectRemoved(const AbstractAspect *parent, int index);
 
278
                //! Emit this to give status information to the user.
 
279
                void statusInfo(const QString &text);
 
280
 
 
281
        protected:
 
282
                //! Set the creation time
 
283
                /**
 
284
                 * The creation time will automatically be set when the aspect object
 
285
                 * is created. This function is usually only needed when the aspect
 
286
                 * is loaded from a file.
 
287
                 */
 
288
                void setCreationTime(const QDateTime& time);
 
289
                //! Called after a new child has been inserted or added.
 
290
                /**
 
291
                 * Unlike the aspectAdded() signals, this method does not get called inside undo/redo actions;
 
292
                 * allowing subclasses to execute undo commands of their own.
 
293
                 */
 
294
                virtual void completeAspectInsertion(AbstractAspect * aspect, int index) { Q_UNUSED(aspect); Q_UNUSED(index); }
 
295
                //! Called before a child is removed.
 
296
                /**
 
297
                 * Unlike the aspectAboutToBeRemoved() signals, this method does not get called inside undo/redo actions;
 
298
                 * allowing subclasses to execute undo commands of their own.
 
299
                 */
 
300
                virtual void prepareAspectRemoval(AbstractAspect * aspect) { Q_UNUSED(aspect); }
 
301
                //! Implementations should call this whenever status information should be given to the user.
 
302
                /**
 
303
                 * This will cause statusInfo() to be emitted. Typically, this will cause the specified string
 
304
                 * to be displayed in a status bar, a log window or some similar non-blocking way so as not to
 
305
                 * disturb the workflow.
 
306
                 */
 
307
                void info(const QString &text) { emit statusInfo(text); }
 
308
 
 
309
        private:
 
310
                Private * d_aspect_private;
 
311
};
 
312
 
 
313
#endif // ifndef ABSTRACT_ASPECT_H