Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / plasma / containments / desktop / iconloader.cpp
blob13cb8936e11812de192b61f145de45da201c3ce1
1 /*
2 * Copyright 2007 by Christopher Blauvelt <cblauvelt@gmail.com>
3 * Copyright (C) 2007 Matt Broadstone <mbroadst@kde.org>
4 * Copyright (C) 2007 Matias Costa <m.costacano@gmail.com>
5 * Copyright (C) 2007 Montel Laurent <montel@kde.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License version 2,
9 * or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details
16 * You should have received a copy of the GNU Library General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "iconloader.h"
23 #include "desktop.h"
25 #include <QGraphicsScene>
27 #include <KUrl>
28 #include <KGlobalSettings>
29 #include <KDebug>
30 #include <KAuthorized>
31 #include <KToggleAction>
32 #include <KConfigGroup>
34 static const int topBorder = 20;
36 IconLoader::IconLoader(DefaultDesktop *parent)
37 : QObject(parent),
38 m_desktop(parent),
39 m_orientation(Qt::Vertical),
40 m_showIcons(true),
41 m_gridAlign(true),
42 m_enableMedia(false)
44 init();
47 IconLoader::~IconLoader()
51 void IconLoader::init()
53 m_iconMap.clear();
55 //load stored settings
56 KConfigGroup cg(m_desktop->globalConfig());
57 cg = KConfigGroup(&cg, "DesktopIcons");
58 m_showIcons = cg.readEntry("showIcons", m_showIcons);
59 m_gridAlign = cg.readEntry("alignToGrid", m_gridAlign);
60 m_orientation = (Qt::Orientation)cg.readEntry("orientation", (int)m_orientation);
61 setShowDeviceIcons(cg.readEntry("enableMedia", m_enableMedia));
63 setGridSize(QSizeF(150, 125));
65 connect(m_desktop, SIGNAL(appletRemoved(Plasma::Applet*)), this, SLOT(appletDeleted(Plasma::Applet*)));
66 //build list of current icons
67 foreach (Plasma::Applet* applet, m_desktop->applets()) {
68 if (applet->name() == i18n("Icon")) {
69 addIcon(applet);
73 //list ~/Desktop and add new applets
74 m_desktopDir.setAutoUpdate(true);
75 m_desktopDir.setAutoErrorHandlingEnabled(false, 0);
77 connect(&m_desktopDir, SIGNAL(newItems(KFileItemList)), this, SLOT(newItems(KFileItemList)) );
78 connect(&m_desktopDir, SIGNAL(deleteItem(KFileItem)), this, SLOT(deleteItem(KFileItem)));
80 setShowIcons(m_showIcons);
83 void IconLoader::setShowDeviceIcons(bool show)
85 if (m_enableMedia != show) {
86 m_enableMedia = show;
87 configureMedia();
91 bool IconLoader::showDeviceIcons() const
93 return m_enableMedia;
96 void IconLoader::reloadConfig()
98 KConfigGroup cg(m_desktop->globalConfig());
99 cg = KConfigGroup(&cg, "DesktopIcons");
100 setGridAligned(cg.readEntry("alignToGrid", m_gridAlign));
101 setShowIcons(cg.readEntry("showIcons", m_showIcons));
102 m_orientation = (Qt::Orientation)cg.readEntry("orientation", (int)m_orientation);
103 setShowDeviceIcons(cg.readEntry("enableMedia", m_enableMedia));
106 void IconLoader::createMenu()
108 QAction* alignHorizontal = new QAction(i18n("Align Icons Horizontally"), this);
109 connect(alignHorizontal, SIGNAL(triggered(bool)), this , SLOT(slotAlignHorizontal()));
110 actions.append(alignHorizontal);
112 QAction* alignVertical = new QAction(i18n("Align Icons Vertically"), this);
113 connect(alignVertical, SIGNAL(triggered(bool)), this , SLOT(slotAlignVertical()));
114 actions.append(alignVertical);
117 QList<QAction*> IconLoader::contextActions()
119 if (!m_showIcons) {
120 return QList<QAction*>();
123 if (actions.isEmpty()) {
124 createMenu();
127 return actions;
130 void IconLoader::slotAlignHorizontal()
132 m_orientation = Qt::Horizontal;
133 alignIcons();
136 void IconLoader::slotAlignVertical()
138 m_orientation = Qt::Vertical;
139 alignIcons();
142 void IconLoader::configureMedia()
144 if (m_enableMedia) {
145 if (!m_solidEngine) {
146 //m_solidEngine = m_desktop->dataEngine("solidnotifierengine");
147 //connect(m_solidEngine, SIGNAL(newSource(const QString&)),
148 // this, SLOT(sourceAdded(const QString&)));
149 //TODO update it.
151 } else if (m_solidEngine) {
152 m_solidEngine=0;
153 // remove from the lists and delete
154 foreach (Plasma::Applet *icon, m_solidDevices.values()) {
155 icon->destroy();
157 m_solidDevices.clear();
161 void IconLoader::addIcon(const KUrl& url)
163 QVariantList args;
164 args << url.path();
165 Plasma::Applet *newApplet = m_desktop->addApplet(QString("icon"),args,0);
166 if (newApplet) {
167 //kDebug() << "putting" << url.path() << "into the map";
168 //alignToGrid even if m_alignGrid is not set. Otherwise all the applets appear at point 0,0
169 alignToGrid(newApplet);
170 m_iconMap[url.path()] = newApplet;
174 void IconLoader::addIcon(Plasma::Applet *applet)
176 KConfigGroup cg = applet->config();
177 KUrl url = cg.readEntry("Url", KUrl());
178 if (!url.isEmpty()) {
179 m_iconMap[url.path()] = applet;
183 void IconLoader::deleteIcon(const KUrl& url)
185 Plasma::Applet *applet = m_iconMap.value(url.path());
187 if (applet) {
188 m_iconMap.remove(url.path());
189 applet->destroy();
193 void IconLoader::deleteIcon(Plasma::Applet *applet)
195 //we must be careful because this will be entered when the applet is already
196 //in the qobject dtor so we can't invoke any applet methods
197 m_iconMap.remove(m_iconMap.key(applet));
200 void IconLoader::newItems(const KFileItemList& items)
202 if (!m_desktop) {
203 return;
206 foreach (KFileItem item, items) {
207 //kDebug() << "adding item" << item.url();
208 if (!m_iconMap.contains(item.url().path())) {
209 addIcon(item.url());
214 void IconLoader::deleteItem(const KFileItem item)
216 QString path = item.url().path();
217 if (!m_iconMap.contains(path)) {
218 //kDebug() << "Icon " << path << " not found." << endl;
219 return;
221 deleteIcon(item.url());
224 void IconLoader::appletDeleted(Plasma::Applet *applet)
226 deleteIcon(applet);
229 void IconLoader::alignIcons()
231 QList<Plasma::Applet*> icons = m_iconMap.values();
232 if (icons.count() == 0 || !m_showIcons) {
233 return;
236 qreal gridWidth = gridSize().width();
237 qreal gridHeight = gridSize().height();
239 QRectF candidateRect(0, 0, gridWidth, gridHeight);
240 QList<Plasma::Applet*> placedIcons;
242 foreach (Plasma::Applet* icon, icons) {
243 candidateRect = QRectF(QPointF(0.0,0.0),icon->boundingRect().size());
244 //check if any placed icons intersect with the icon placed at various grid locations
246 candidateRect = nextFreeRect(candidateRect, placedIcons);
247 if (!candidateRect.isValid()) {
248 return;
251 //mapToGrid on the center spot to eliminate conversion error
252 setToGrid(icon, mapToGrid(candidateRect.topLeft()));
253 placedIcons << icon;
257 QRectF IconLoader::nextFreeRect(const QRectF itemRect)
259 return nextFreeRect(itemRect, m_iconMap.values());
262 QRectF IconLoader::nextFreeRect(const QRectF itemRect, QList<Plasma::Applet*> placedItems)
264 QRectF newRect = itemRect;
265 while (intersectsWithItems(newRect, placedItems)) {
266 newRect = advanceAlongGrid(newRect);
267 if (!availableGeometry().contains(newRect)) {
268 //we've moved completely off the desktop so we should stop
269 return QRectF();
272 return newRect;
275 bool IconLoader::intersectsWithItems(const QRectF item, const QList<Plasma::Applet*> &items) const
277 foreach (Plasma::Applet* testItem, items) {
278 //do not use testItem->sceneBoundingRect(). If the item is not drawn yet a size of
279 //0x0 is returned which breaks the algorithm
280 if (item.intersects(QRectF(testItem->scenePos(), testItem->size()))) {
281 return true;
284 return false;
287 QRectF IconLoader::advanceAlongGrid(QRectF rect)
289 QRectF newRect = rect;
290 qreal gridWidth = m_gridSize.width();
291 qreal gridHeight = m_gridSize.height();
293 if (m_orientation == Qt::Horizontal) {
294 newRect.translate(gridWidth,0);
295 } else {
296 newRect.translate(0, gridHeight);
298 if (!availableGeometry().contains(newRect)) {
299 //we've moved off of the desktop and need to move back
300 if (m_orientation == Qt::Horizontal) {
301 newRect.moveTo(0,newRect.y()+gridHeight);
302 } else {
303 newRect.moveTo(newRect.x()+gridWidth,0);
306 return newRect;
309 void IconLoader::setToGrid(Plasma::Applet* icon, const QPoint p)
311 //place the center of the icon in the center of the grid if it's smaller than the grid square
312 QPointF newPos = mapFromGrid(p);
313 if (m_gridSize.width() > icon->boundingRect().width()) {
314 newPos.setX(newPos.x() + (m_gridSize.width()/2 - icon->boundingRect().width()/2));
316 if (m_gridSize.height() > icon->boundingRect().height()) {
317 newPos.setY(newPos.y() + topBorder);
319 icon->setPos(newPos);
322 bool IconLoader::isGridAligned() const
324 return m_gridAlign;
327 void IconLoader::setGridAligned(bool align)
329 // if icon alignment is false now and we change
330 // to true then align all icons
331 if (!m_gridAlign && align) {
332 foreach (Plasma::Applet *applet, m_iconMap.values()) {
333 alignToGrid(applet,mapToGrid(applet->scenePos()));
336 m_gridAlign = align;
339 void IconLoader::alignToGrid(Plasma::Applet *item)
341 QRectF freeRect = nextFreeRect(QRectF(QPointF(0.0,0.0),item->boundingRect().size()));
342 QPoint currentGridPos = mapToGrid(freeRect.topLeft());
343 alignToGrid(item, currentGridPos);
346 void IconLoader::alignToGrid(Plasma::Applet *item, const QPoint &pos, bool moveIntersectingItems)
348 if (moveIntersectingItems) {
349 return;
350 } else {
351 setToGrid(item, pos);
355 QSizeF IconLoader::gridSize() const
357 return m_gridSize;
360 QSize IconLoader::gridDimensions() const
362 QSizeF thisSize = m_desktop->contentSizeHint();
363 return QSize( int(thisSize.width() / m_gridSize.width()),
364 int(thisSize.height() / m_gridSize.height()) );
367 void IconLoader::setGridSize(const QSizeF& gridSize)
369 QSizeF desktopSize = m_desktop->contentSizeHint();
370 qreal bestMatchWidth = desktopSize.width()
371 / qRound(desktopSize.width()/gridSize.width());
372 qreal bestMatchHeight = desktopSize.height()
373 / qRound(desktopSize.height()/gridSize.height());
374 m_gridSize = QSizeF(bestMatchWidth, bestMatchHeight);
375 if (m_gridAlign) {
376 foreach (Plasma::Applet *item, m_iconMap.values()) {
377 alignToGrid(item);
382 bool IconLoader::showIcons() const
384 return m_showIcons;
387 void IconLoader::setShowIcons(bool iconsVisible)
389 m_showIcons = iconsVisible;
390 if (m_showIcons) {
391 m_desktopDir.openUrl(KGlobalSettings::desktopPath());
392 } else {
393 m_desktopDir.stop();
394 QString desktopDir = KGlobalSettings::desktopPath();
395 foreach (Plasma::Applet *icon, m_iconMap.values()) {
396 KConfigGroup cg = icon->config();
397 KUrl url = cg.readEntry("Url", KUrl());
399 //kDebug() << "checking" << url.path() << "against" << desktopDir;
400 if (url.path().startsWith(desktopDir)) {
401 icon->destroy(); //the icon will be taken out of m_iconMap by the appletDeleted Slot
407 void IconLoader::sourceAdded(const QString &source)
409 Q_UNUSED(source)
410 kDebug() << "Not yet implemented.";
413 void IconLoader::sourceDeleted(const QString &source)
415 Q_UNUSED(source)
416 kDebug() << "Not yet implemented.";
419 #include "iconloader.moc"