00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <limits>
00011
00012 #include <QCoreApplication>
00013 #include <QGraphicsWidget>
00014 #include <QGraphicsProxyWidget>
00015 #include <QWaitCondition>
00016
00017 #include <KDebug>
00018
00019 #include <Plasma/Animator>
00020
00021 #include "desktoplayout.h"
00022
00023 DesktopLayout::DesktopLayout(QGraphicsLayoutItem *parent)
00024 : QObject(0),
00025 QGraphicsLayout(parent),
00026 autoWorkingArea(true),
00027 temporaryPlacement(false),
00028 visibilityTolerance(0),
00029 m_activated(false)
00030 {
00031 connect(Plasma::Animator::self(), SIGNAL(movementFinished(QGraphicsItem*)),
00032 this, SLOT(movementFinished(QGraphicsItem*)));
00033 }
00034
00035 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QRectF &preferredGeom, const QRectF &lastGeom)
00036 {
00037 int key = newItemKey();
00038
00039 ItemSpace::ItemSpaceItem spaceItem;
00040 spaceItem.pushBack = pushBack;
00041 spaceItem.animateMovement = false;
00042 spaceItem.preferredGeometry = preferredGeom;
00043 spaceItem.lastGeometry = (lastGeom.isValid() ? lastGeom : preferredGeom);
00044 spaceItem.user = QVariant(key);
00045
00046 DesktopLayoutItem desktopItem;
00047 desktopItem.item = item;
00048 desktopItem.temporaryGeometry = QRectF(0, 0, -1, -1);
00049
00050 itemSpace.addItem(spaceItem);
00051 items.insert(key, desktopItem);
00052
00053 invalidate();
00054 }
00055
00056 void DesktopLayout::addItem(QGraphicsLayoutItem *item, bool pushBack, const QSizeF &size)
00057 {
00058 QSizeF itemSize = ( size.isValid() ? size : item->effectiveSizeHint(Qt::PreferredSize) );
00059
00060
00061 QList<QPointF> possiblePositions = itemSpace.positionVertically(itemSize, itemSpace.spaceAlignment, false, true);
00062
00063
00064
00065 QRectF bestGeometry = QRectF();
00066 foreach (const QPointF &position, possiblePositions) {
00067 QRectF geom = QRectF(position, itemSize);
00068 if (itemSpace.positionedProperly(geom)) {
00069 bestGeometry = geom;
00070 break;
00071 }
00072 }
00073
00074 if (!bestGeometry.isValid()) {
00075
00076 QPointF bestPosition = QPointF();
00077 qreal bestVisibility = 0;
00078 foreach (const QPointF &position, possiblePositions) {
00079
00080
00081
00082
00083 ItemSpace tempItemSpace(itemSpace);
00084
00085 ItemSpace::ItemSpaceItem spaceItem;
00086 spaceItem.pushBack = pushBack;
00087 spaceItem.animateMovement = false;
00088 spaceItem.preferredGeometry = QRectF(position, itemSize);
00089 spaceItem.lastGeometry = QRectF(position, itemSize);
00090 spaceItem.user = QVariant(-1);
00091
00092 tempItemSpace.addItem(spaceItem);
00093 tempItemSpace.activate();
00094 int tempGroup, tempItem;
00095 tempItemSpace.locateItemByUser(QVariant(-1), &tempGroup, &tempItem);
00096
00097 QRectF resultingGeom = tempItemSpace.m_groups[tempGroup].m_groupItems[tempItem].lastGeometry;
00098 qreal visibility = tempItemSpace.positionVisibility(resultingGeom);
00099
00100
00101
00102 if (visibility > bestVisibility) {
00103 bestPosition = position;
00104 bestVisibility = visibility;
00105 if (visibility >= 1) {
00106 break;
00107 }
00108 }
00109 }
00110
00111 if (bestVisibility < (1.0-visibilityTolerance)) {
00112 bestPosition = QPointF(itemSpace.screenSpacing, itemSpace.screenSpacing);
00113 }
00114
00115 bestGeometry = QRectF(bestPosition, itemSize);
00116 }
00117
00118 addItem(item, pushBack, bestGeometry);
00119 kDebug() << "Positioned item to" << bestGeometry;
00120 }
00121
00122 bool DesktopLayout::getPushBack(int index)
00123 {
00124 int group;
00125 int item;
00126 itemSpace.locateItemByPosition(index, &group, &item);
00127
00128 return itemSpace.m_groups[group].m_groupItems[item].pushBack;
00129 }
00130
00131 QRectF DesktopLayout::getPreferredGeometry(int index)
00132 {
00133 int group;
00134 int item;
00135 itemSpace.locateItemByPosition(index, &group, &item);
00136
00137 return itemSpace.m_groups[group].m_groupItems[item].preferredGeometry;
00138 }
00139
00140 QRectF DesktopLayout::getLastGeometry(int index)
00141 {
00142 int group;
00143 int item;
00144 itemSpace.locateItemByPosition(index, &group, &item);
00145
00146 return itemSpace.m_groups[group].m_groupItems[item].lastGeometry;
00147 }
00148
00149 void DesktopLayout::setPlacementSpacing(qreal spacing)
00150 {
00151 itemSpace.placementSpacing = spacing;
00152 }
00153
00154 void DesktopLayout::setScreenSpacing(qreal spacing)
00155 {
00156 itemSpace.screenSpacing = spacing;
00157 invalidate();
00158 }
00159
00160 void DesktopLayout::setShiftingSpacing(qreal spacing)
00161 {
00162 itemSpace.shiftingSpacing = spacing;
00163
00164 }
00165
00166 void DesktopLayout::setVisibilityTolerance(qreal part)
00167 {
00168 visibilityTolerance = part;
00169 invalidate();
00170 }
00171
00172 void DesktopLayout::setWorkingArea(QRectF area)
00173 {
00174
00175
00176 itemSpace.offsetPositions(workingStart - area.topLeft());
00177 itemSpace.setWorkingArea(area.size());
00178 workingStart = area.topLeft();
00179 invalidate();
00180 }
00181
00182 void DesktopLayout::setAlignment(Qt::Alignment alignment)
00183 {
00184 itemSpace.spaceAlignment = alignment;
00185 invalidate();
00186 }
00187
00188 void DesktopLayout::setTemporaryPlacement(bool enabled)
00189 {
00190 temporaryPlacement = enabled;
00191 invalidate();
00192 }
00193
00194 void DesktopLayout::setAutoWorkingArea (bool value)
00195 {
00196 autoWorkingArea = value;
00197 }
00198
00199 int DesktopLayout::count () const
00200 {
00201 return items.size();
00202 }
00203
00204 QGraphicsLayoutItem *DesktopLayout::itemAt (int i) const
00205 {
00206 int group = -2, item = -2;
00207 itemSpace.locateItemByPosition(i, &group, &item);
00208 int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
00209
00210 return items[itemKey].item;
00211 }
00212
00213 void DesktopLayout::removeAt (int i)
00214 {
00215 int group, item;
00216 itemSpace.locateItemByPosition(i, &group, &item);
00217 int itemKey = itemSpace.m_groups[group].m_groupItems[item].user.toInt();
00218
00219
00220 itemSpace.removeItem(group, item);
00221
00222 items.remove(itemKey);
00223
00224 invalidate();
00225 }
00226
00227 void DesktopLayout::performTemporaryPlacement(int group, int itemInGroup)
00228 {
00229 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
00230 DesktopLayoutItem &item = items[spaceItem.user.toInt()];
00231
00232 QRectF origGeom = spaceItem.lastGeometry;
00233 spaceItem.lastGeometry = QRectF();
00234
00235 QPointF newPos = QPointF(0, 0);
00236 QList<QPointF> possiblePositions = itemSpace.positionVertically(origGeom.size(), itemSpace.spaceAlignment, true, false);
00237 if (possiblePositions.count() > 0) {
00238 newPos = possiblePositions[0];
00239 }
00240
00241 spaceItem.lastGeometry = origGeom;
00242 item.temporaryGeometry = QRectF(newPos, origGeom.size());
00243 item.item->setGeometry(item.temporaryGeometry.translated(workingStart));
00244 }
00245
00246 void DesktopLayout::revertTemporaryPlacement(int group, int itemInGroup)
00247 {
00248 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[itemInGroup];
00249 DesktopLayoutItem &item = items[spaceItem.user.toInt()];
00250
00251 item.temporaryGeometry = QRectF();
00252 item.item->setGeometry(spaceItem.lastGeometry.translated(workingStart));
00253 }
00254
00255
00256 void DesktopLayout::setGeometry(const QRectF &rect)
00257 {
00258 m_activated = true;
00259 QGraphicsLayout::setGeometry(rect);
00260
00261 if (autoWorkingArea || !itemSpace.workingGeom.isValid()) {
00262 setWorkingArea(rect);
00263 }
00264
00265
00266 itemSpace.activate();
00267
00268 for (int groupId = 0; groupId < itemSpace.m_groups.size(); groupId++) {
00269 ItemSpace::ItemGroup &group = itemSpace.m_groups[groupId];
00270
00271 for (int itemId = 0; itemId < group.m_groupItems.size(); itemId++) {
00272 ItemSpace::ItemSpaceItem &spaceItem = group.m_groupItems[itemId];
00273 DesktopLayoutItem &desktopItem = items[spaceItem.user.toInt()];
00274
00275
00276
00277 if (itemSpace.positionVisibility(spaceItem.lastGeometry) < visibilityTolerance) {
00278 performTemporaryPlacement(groupId, itemId);
00279 } else if (desktopItem.temporaryGeometry.isValid()) {
00280 revertTemporaryPlacement(groupId, itemId);
00281 }
00282
00283
00284 QRectF visibleGeom = (desktopItem.temporaryGeometry.isValid() ? desktopItem.temporaryGeometry : spaceItem.lastGeometry);
00285 QRectF absoluteGeom = visibleGeom.translated(workingStart);
00286 if (desktopItem.item->geometry() != absoluteGeom) {
00287 QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(desktopItem.item);
00288 if (w && spaceItem.animateMovement) {
00289 Plasma::Animator *anim = Plasma::Animator::self();
00290 bool animating = m_animatingItems.contains(w);
00291 if (animating) {
00292 anim->stopItemMovement(m_animatingItems.value(w));
00293 }
00294 int id = Plasma::Animator::self()->moveItem(w, Plasma::Animator::FastSlideInMovement,
00295 absoluteGeom.topLeft().toPoint());
00296 if (id > 0) {
00297 m_animatingItems.insert(w, id);
00298 } else if (animating) {
00299 m_animatingItems.remove(w);
00300 }
00301
00302 spaceItem.animateMovement = false;
00303 } else {
00304 desktopItem.item->setGeometry(absoluteGeom);
00305 }
00306 }
00307 }
00308 }
00309 m_activated = false;
00310 }
00311
00312
00313
00314 void DesktopLayout::itemGeometryChanged(QGraphicsLayoutItem *layoutItem)
00315 {
00316 if (m_activated || m_animatingItems.contains(dynamic_cast<QGraphicsWidget*>(layoutItem))) {
00317 return;
00318 }
00319
00320
00321 int itemKey = -1;
00322 QMapIterator<int, DesktopLayoutItem> i(items);
00323 while (i.hasNext()) {
00324 i.next();
00325 if (i.value().item == layoutItem) {
00326 itemKey = i.key();
00327 break;
00328 }
00329 }
00330 if (itemKey == -1) {
00331 return;
00332 }
00333
00334
00335 int group, item;
00336 itemSpace.locateItemByUser(itemKey, &group, &item);
00337 ItemSpace::ItemSpaceItem &spaceItem = itemSpace.m_groups[group].m_groupItems[item];
00338
00339 QRectF currentRelative = layoutItem->geometry().translated(-workingStart);
00340 if (spaceItem.lastGeometry != currentRelative) {
00341 spaceItem.lastGeometry = currentRelative;
00342 spaceItem.preferredGeometry = currentRelative;
00343
00344 itemSpace.updateItem(group, item);
00345 invalidate();
00346 }
00347 }
00348
00349 QSizeF DesktopLayout::sizeHint (Qt::SizeHint which, const QSizeF &constraint) const
00350 {
00351 Q_UNUSED(which)
00352 Q_UNUSED(constraint)
00353 return QSizeF();
00354 }
00355
00356 void DesktopLayout::movementFinished(QGraphicsItem* item)
00357 {
00358 if (m_animatingItems.contains(item)) {
00359 m_animatingItems.remove(item);
00360 }
00361 }
00362
00363 int DesktopLayout::newItemKey()
00364 {
00365 int from = -1;
00366 QList<int> usedKeys = items.keys();
00367 foreach (int key, usedKeys) {
00368 if (key - from > 1) {
00369 break;
00370 }
00371 from = key;
00372 }
00373 return from+1;
00374 }
00375
00376 #include <desktoplayout.moc>