LunaSysMgr
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
reorderableiconlayout.h
Go to the documentation of this file.
1 /* @@@LICENSE
2 *
3 * Copyright (c) 2010-2012 Hewlett-Packard Development Company, L.P.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * LICENSE@@@ */
18 
19 
20 
21 
22 #include "iconlayout.h"
23 #include "icon.h"
24 
25 #include <QList>
26 #include <QString>
27 #include <QDebug>
28 #include <QMap>
29 #include <QPointer>
30 #include <QUuid>
31 
32 #ifndef REORDERABLEICONLAYOUT_H_
33 #define REORDERABLEICONLAYOUT_H_
34 
35 class ReorderablePage;
36 class PixmapObject;
37 class QAnimationGroup;
38 class IconLayoutAnimationControl;
40 class QStateMachine;
41 class QState;
42 
44 {
45  Q_OBJECT
46 public:
47 
48  friend class ReorderablePage;
49 
51  virtual ~ReorderableIconLayout();
52 
53  virtual void setLayoutRowSpacing(const qreal interRowSpace,
54  const quint32 anchorRowNum=0);
55 
57 
58  virtual void paint(QPainter * painter);
59  // (ScrollableObject-->ScrollingLayoutRenderer-->here)
60  // "clipping", but by only drawing from the source area specified. sourceRect guaranteed to be within
61  // m_geom space
62  virtual void paint(QPainter * painter, const QRectF& sourceRect);
63  virtual void paint(QPainter * painter, const QRectF& sourceRect,qint32 renderOpt);
64  virtual void paint(const QPointF& translate,QPainter * painter);
65 
66  virtual void paintOffscreen(QPainter * painter);
67  virtual void paintOffscreen(PixmapObject * p_pmo);
68  virtual void paintOffscreen(PixmapHugeObject * p_hugePmo);
69 
70  virtual void enableAutoPaint();
71  virtual void disableAutoPaint();
72 
73  //relayout() sets absolute positioning within the item (Page or a Page-subclass) of layout, rows, and cells
74  virtual void relayout(bool force=false);
75  virtual void resizeWidth(const quint32 w);
76  virtual void setPosition(const QPointF& pos);
77  virtual void setUniformCellSize(const QSize& size);
78 
79  // intended to tell a cell that the icon is losing control of an icon (usually for moving/animating it to a new cell)
80  virtual void iconCellReleaseIcon(const QPoint& cellCoordinate);
81 
82  virtual IconCell * iconCellAtLayoutCoordinate(const QPointF& coordinate);
83  virtual IconCell * iconCellAtLayoutCoordinate(const QPointF& layoutCoordinate,QPoint& r_gridCoordinate);
84 
85  //returns the rect area of the row specified, in layout CS (it's the geom of the row, translated to its layout CS position)
86  virtual QRectF rowArea(quint32 rowIndex) const;
87 
88  virtual QPoint lastOccupiedGridPosition() const;
89  virtual QPoint nextAppendGridPosition() const;
90 
91  virtual qint32 rowAtLayoutCoordinate(const QPointF& layoutCoordinate,bool clipMinMax=false);
92  //this variant will ignore the gaps between rows; if the point happens to fall on a gap between the rect or row "i" and row "i+1", "i" will be returned
93  virtual qint32 rowAtLayoutCoordinateFuzzy(const QPointF& layoutCoordinate,bool clipMinMax=false);
94 
95  //these two can only be used with grid coordinates that already exist. e.g. it can't determine coordinates
96  // for a grid that would result if a row needs to be added; This would happen for example, if an icon
97  // add would end up adding a new row for "overflow" of a row with too many icons
98  virtual IconCell * iconCellAtGridCoordinate(const QPoint& gridCoordinate);
99  virtual bool layoutCoordinateForGridCoordinate(const QPoint& gridCoordinate,QPointF& r_layoutCoordinate);
100 
101  virtual IconCell * findIconByUid(const QUuid& iconUid,QPoint& r_gridCoordinate,bool includePendingIconsInCells = false);
102 
103  // all the icon cells, starting with the leftmost cell of the top row, and ending with the rightmost cell in the bottom row
104  //WARNING: DO NOT HOLD REF TO ANYTHING FROM THE RETURN OF THIS FN. It could be invalidated at any time (whenever an add/remove or relayout happens)
105  virtual QList<IconCell *> iconCellsInFlowOrder();
106 
107  // returns 0 (null) if tracking this icon isn't possible at the moment
108  // designed so that iconCellAtLayoutCoordinate() result can be passed right in
109  // (it will correctly handle null (not found) icon cell
110  virtual IconBase * startTrackingIcon(const QPoint& gridCoord,bool includePendingIconsInCells = false);
111  //startTrackingIconFromTransfer(): gridCoord needs to be an empty cell; see addEmptyCell
112  virtual IconBase * startTrackingIconFromTransfer(const QPoint& gridCoord,IconBase * iconTracked);
113  //this variant starts tracking an icon by finding it in the layout by its actual pointer. it is used in the case where the icon
114  // comes back from the quicklaunch during one, continuous tracking operation (the following pattern: move icon to QL, don't let go
115  // of the icon on the QL but immediately move it back to the page). Returns true if the icon was found and can be tracked,
116  // and puts its current grid coord in r_gridCoord.
117  virtual bool startTrackingIcon(IconBase * p_icon,QPoint& r_gridCoord);
118 
119  virtual bool trackedIconMovedTo(IconBase * p_icon,const QPoint& gridCoord,QPoint& r_newGridCoord);
120  virtual void stopTrackingIcon(IconBase * p_icon);
121  virtual void stopTrackingAll();
122  //trackedIconLeavingLayout(): used instead of stopTrackingIcon() when the icon has changed hands;
123  // e.g. been moved to another page/layout
124  virtual bool trackedIconLeavingLayout(const QUuid& trackedIconUid);
125  //convenience function to look up the uid against m_trackedIconLastPosition and retrieve from icon heap
126  virtual IconBase * getTrackedIconByUid(const QUuid& trackedIconUid);
127  virtual bool lastTrackedPosition(const QUuid& iconUid,QPoint& r_lastGridCoord);
128  virtual QList<IconOperation> opListForMove(const QPoint& sourceColumnRow,const QPoint& destColumnRow);
129  //returns the animations to perform the actions described in the opList
130  virtual QAnimationGroup * animationsForOpList(QList<IconOperation>& opList);
131  //uses the op list to set m_reorderPendingCellList which will be needed to commit/finalize the layout;
132  // this must be done regardless of whether or not animations will be used. It's being broken out as a separate function
133  // despite this being a hard requirement, so that this sequence can be better controlled.
134  // it will fail (return false) if attempting to init from a list with a lower id than has already been used
135  virtual bool initializePendingCellListFromOpList(QList<IconOperation>& opList);
136  //this operates on an already populated m_reorderPendingCellList. It's used to finalize a layout
137  virtual bool commitPending();
138  //this one will do all the tracked (floating) icons
139  virtual bool commitTracked(const QUuid& iconUid);
140  //variant to avoid multiple lookups when the caller already did a lookup
141  virtual bool commitTracked(const QUuid& iconUid,const QPoint& lastGridCoord);
142  // essentially the same thing as calling animationsForOpList + commitOpList as an uninterrupted sequence
143  // returns false if the list can't be commited (usually because a list of higher id has already been committed)
144  // The success / failure is all-or-nothing...nothing will be changed by this call of it if return = false
145  virtual bool executeOpList(QList<IconOperation>& opList);
146 
147  //will create and return an animation that is made to return the tracked icon in question to the last cell that
148  // it moved to (see trackedIconMovedTo()). Use this animation IMMEDIATELY, and certainly before any other calls to
149  // trackedIconMovedTo(), or any of the others in that group (that change the grid position of a tracked icon) occur.
150  virtual IconReorderAnimation * animationForTrackedIconFinal(const QUuid& trackedIconUid);
151  virtual IconReorderAnimation * animationForTrackedIconFinal(const QUuid& trackedIconUid,const QPoint& lastGridCoord);
152  //Just like stopTracking__() and commit___() operate under normal circumstances and try to let animations finish,
153  //cancelAllReorder() kills all animations instantly and immediately locks all icons into their final state, as if
154  // the normal reorders were allowed to finish. This is useful in case of some drastic UI change, like an incoming call,
155  // a rotation of the screen, the launcher being dismissed, apps being deleted, etc...
156  // the function has no return value because it cannot fail; if it fails to do anything, then a crash will likely follow
157  // (or at the very least, a very inconsistent, mostly unusable launcher UI state)
158  virtual void cancelAllReorder();
159  virtual void commitPendingImmediately();
160  virtual void commitTrackedImmediately(const QUuid& iconUid);
161  virtual void commitTrackedImmediately(const QUuid& iconUid,const QPoint& lastGridCoord);
162 
163  virtual bool areTherePendingReorderAnimations();
164 
166  friend QDataStream & operator<< (QDataStream& stream, const ReorderableIconLayout& s);
167  friend QDataStream & operator>> (QDataStream& stream, ReorderableIconLayout& s);
168  friend QDebug operator<<(QDebug dbg, const ReorderableIconLayout &s);
169 
170  /*
171  * addIcon(IconBase * p_icon)
172  *
173  * Inserts the icon into the row and column that represents the "end" of the layout
174  * Since ReorderableIconLayout doesn't have any specific ordering (it is arbitrarily ordered by the user),
175  * the end of the layout is just the next available space
176  *
177  * Mostly useful for initializing a layout initially. Generally NOT useful at user-visible runtime since
178  * it will not calculate any of the animations needed to display the "add"
179  *
180  * Also, it will not automatically adjust the layout geoms of the icon cells. It is expected a caller
181  * will be handling this.
182  *
183  * returns either 0 if it inserted into an existing row or took no action, or (row index)+1 if it had to insert a new row
184  * this value helps the caller determine if it needs to run a relayout of rows, and possibly optimize the relayout
185  * over only some rows
186  *
187  * It also sets the m_layoutSync variable if any layout state was modified (this disambiguates return=0)
188  */
189  virtual quint32 addIcon(IconBase * p_icon);
190 
191  //this is its counterpart, used for relayoutExisting()
192  virtual quint32 addIcon(IconCell * p_cell);
193 
194  //returns the grid coordinate of the new cell, or (-1,-1) if no new cell can be added
195  virtual QPoint addEmptyCell();
196 
197  //versions of the above that insert into specific locations. If gridCoordinate is invalid, then it will default to (0,0)
198  // return convention is the same as for addIcon
199  // however, if these return > 0 , relayoutExisting() MUST BE RUN SOMETIME SOON AFTER!
200  // (it's an optimization to avoid having to "ripple down" the right most icon at each row and adding the
201  // final "leftover icon" into the last row or creating a new row at the bottom. relayoutExisting already
202  // does all this so it'll be a waste to do it here. Philosophically, it would be more correct to have this
203  // function at least maintain the rows w.r.t. the ordering and max column count, but like i said, this is an
204  // optimization)
205  virtual quint32 addIconAt(IconBase * p_icon,const QPoint& gridCoordinate);
206  virtual quint32 addIconAt(IconCell * p_cell,const QPoint& gridCoordinate);
207 
208  //(this one also has the same return convention as addEmptyCell, and will default to appending to the end of the layout (same as addEmptyCell)
209  // if gridCoordinate is invalid)
210  virtual QPoint addEmptyCellAt(const QPoint& gridCoordinate);
211 
212  virtual bool removeIconCell(const QPoint& gridCoordinate);
213 
215  /*
216  These are versions of common functions like "insert" which are used
217  at runtime, but these variants should ONLY be used during initialization, as they
218  will likely and frequently omit setting/checking/returning/etc state that is required
219  to make things "look right" in the UI.
220  They are all prefixed with "init" should it should be easy to identify them and keep
221  track of this rule
222  */
224 
226  const IconList iconList);
227 Q_SIGNALS:
228 
229 // These two signals are the overall indicators of when a reordering begins and ends.
230 // reordering here means more than just "reorder pending" (vs moving/float icon tracking),
231 // it means *overall* reorder , i.e. the state is not consistent from the POV of the outside world
232  void signalReorderStarted();
233  void signalReorderEnded();
234 
235 // these are for the FSM !ONLY!
238  void signalFSMLastTrackEndedTrigger(); //TODO: HACK: see slotTrackForIconEnded() below
241 
242 protected Q_SLOTS:
243 
244  virtual void slotReorderAnimationsFinished();
246 
247  //TODO: HACK: TEMP: the FSM should actually count the number of in-flight trackings and switch states accordingly
248  // Qt's guarded (conditional) transitions are kind of weird so i'm holding off on implementing this for now
249  // this function will check the number of in-flights and emit the signalFSMLastTrackEndedTrigger as appropriate
250  // I'm weaving it this way with a signal->slot inside this (same) class - usually a bad idea - to minimize the
251  // changes needed when this gets done correctly
252  virtual void slotTrackForIconEnded();
253 
254  virtual void dbg_reorderFSMStateEntered();
255 
256 protected:
257 
258  //deletes all the rows (but not the cells contained) and re-inits my state variables to reflect the change
260  virtual void destroyAllRows();
261 
262  //TODO: return an error code as appropriate; calculations can fail if either the page width is too small or icon size if too great
264 
265  /*
266  * when resizing the layout when it has already been done, there is a potential that rows may need to be added
267  * (when the width shrinks) or rows may need to be removed (when the width expands)
268  *
269  * This function will handle these adds and removes. It is a counterpart to relayout(); that function is kind of a misnomer
270  * since it doesn't really RE-layout...it is more for initial layouts
271  *
272  * TODO: initially, this will delete all the rows but keep the cells, and then recreate the rows, adding/removing as necessary.
273  * This can be made more efficient, but I don't have time right now, due to Demo-Demo-Demo!
274  */
275  virtual void relayoutExisting();
276 
277  virtual void setupReorderFSM();
278  virtual void startReorderFSM();
279  virtual void stopReorderFSM();
280 
281  virtual bool isReorderStateConsistent() const;
282 
283  virtual void switchIconsToReorderGraphics();
284  virtual void switchIconsToNormalGraphics();
285  virtual void switchIconToReorderGraphics(IconCell * p_iconCell);
286  virtual void switchIconToNormalGraphics(IconCell * p_iconCell);
287  virtual void switchIconToReorderGraphics(IconBase * p_icon);
288  virtual void switchIconToNormalGraphics(IconBase * p_icon);
289 
290 protected:
291 
292  typedef QList<IconRow *> IconRowList;
293  typedef IconRowList::const_iterator IconRowConstIter;
294  typedef IconRowList::iterator IconRowIter;
295 
297 
301 
303 
304  //all units here in pixels
308  quint32 m_interRowSpace; //between two rows
309 
310  // Layout adjustments - all of this comes from IconLayoutSettings
314 
315  quint32 m_anchorRow; //the current anchor row (from which (re)layouts are performed)
316 
317  QSize m_iconCellSize; //calculated from page size and m_maxIconsPerRow...see initLayout...()
318  quint32 m_horizIconSpacing; //(ditto)...takes into account m_horizIconSpacingAdjust
319 
320  QSize m_layoutSizeInPixels; //for rendering offscreen
321 
322 
323  quint32 m_reorderEventSampleRate; //determines when to check a moving icon against the layout to see what
324  // if anything, needs to be reordered. For now, it will count instances
325  // of "move" events (e.g. mouseMove) but I'll add other ways to threshold
326  // This is useful because checking boundaries on icons and rows in very large
327  // layouts could be expensive, as is generating operation lists and animations
330  quint32 m_magFactor;
331  quint64 m_lastTimeUsed;
332 
333  quint64 m_listIdInUse;
334  QList<QPointer<IconCell> > m_reorderPendingCellList;
335  QPointer<QAnimationGroup> m_qp_reorderAnimationGroup;
336  QMap<QUuid,QPointer<IconReorderAnimation> > m_trackedIconAnimations;
337  QMap<QUuid,QPoint> m_trackedIconLastPosition;
338 
340 
346 
347 };
348 
349 QDataStream & operator<< (QDataStream& stream, const ReorderableIconLayout& s);
350 QDataStream & operator>> (QDataStream& stream, ReorderableIconLayout& s);
351 QDebug operator<<(QDebug dbg, const ReorderableIconLayout &s);
352 
353 #endif /* REORDERABLEICONLAYOUT_H_ */