| Home · All Namespaces · All Classes |
00001 /*************************************************************************** 00002 ** 00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00004 ** All rights reserved. 00005 ** Contact: Nokia Corporation (directui@nokia.com) 00006 ** 00007 ** This file is part of mhome. 00008 ** 00009 ** If you have questions regarding the use of this file, please contact 00010 ** Nokia at directui@nokia.com. 00011 ** 00012 ** This library is free software; you can redistribute it and/or 00013 ** modify it under the terms of the GNU Lesser General Public 00014 ** License version 2.1 as published by the Free Software Foundation 00015 ** and appearing in the file LICENSE.LGPL included in the packaging 00016 ** of this file. 00017 ** 00018 ****************************************************************************/ 00019 00020 #include "launcher.h" 00021 #include "launcherbutton.h" 00022 #include "launcherdatastore.h" 00023 #include "applicationpackagemonitorlistener.h" 00024 00025 #include <MWidgetCreator> 00026 M_REGISTER_WIDGET(Launcher) 00027 00028 const QString Launcher::LOCATION_IDENTIFIER = "launcher"; 00029 const char Launcher::SECTION_SEPARATOR = '/'; 00030 const QString Launcher::PLACEMENT_TEMPLATE = LOCATION_IDENTIFIER + SECTION_SEPARATOR + "%1" + SECTION_SEPARATOR + "%2"; 00031 00039 static Launcher::Placement buttonPlacementInLauncherPages(const QString &desktopFileEntry, QList<QSharedPointer<LauncherPage> > &pages) 00040 { 00041 int pageNum = -1; 00042 int position = -1; 00043 00044 int pageIndex = 0; 00045 foreach (QSharedPointer<LauncherPage> page, pages) { 00046 position = page->launcherButtonPosition(desktopFileEntry); 00047 if (position > -1 ) { 00048 pageNum = pageIndex; 00049 break; 00050 } 00051 pageIndex++; 00052 } 00053 00054 return Launcher::Placement(pageNum, position); 00055 } 00056 00057 Launcher::Launcher(QGraphicsItem *parent) : 00058 MWidgetController(new LauncherModel, parent), 00059 dataStore(NULL), 00060 packageMonitorListener(NULL), 00061 maximumPageSize(-1) 00062 { 00063 } 00064 00065 Launcher::~Launcher() 00066 { 00067 } 00068 00069 void Launcher::setLauncherDataStore(LauncherDataStore *dataStore) 00070 { 00071 if (this->dataStore != NULL) { 00072 disconnect(dataStore, SIGNAL(dataStoreChanged()), this, SLOT(updatePagesFromDataStore())); 00073 } 00074 this->dataStore = dataStore; 00075 connect(dataStore, SIGNAL(dataStoreChanged()), this, SLOT(updatePagesFromDataStore())); 00076 } 00077 00078 void Launcher::setApplicationPackageMonitorListener(ApplicationPackageMonitorListener *packageMonitorListener) 00079 { 00080 this->packageMonitorListener = packageMonitorListener; 00081 } 00082 00083 void Launcher::setMaximumPageSize(int maximumPageSize) 00084 { 00085 this->maximumPageSize = maximumPageSize; 00086 00087 if (maximumPageSize >= 0) { 00088 foreach (QSharedPointer<LauncherPage> page, model()->launcherPages()) { 00089 page->setMaximumButtonCount(maximumPageSize); 00090 } 00091 } 00092 } 00093 00094 void Launcher::updateButtonState(const QString &desktopEntryPath, LauncherButtonModel::State state, int progress) 00095 { 00096 // Check that button is not stored in some other location before adding/updating placeholder and setting state 00097 Launcher::Placement buttonPlacementInDatastore = entryPlacementInDatastore(desktopEntryPath); 00098 if (buttonPlacementInDatastore.location.isEmpty() || buttonPlacementInDatastore.location == Launcher::LOCATION_IDENTIFIER) { 00099 QSharedPointer<LauncherButton> button = placeholderButton(desktopEntryPath); 00100 // Remove old placement from store 00101 // This is needed in case path to used desktop entry has changed between applications and extra directory 00102 removeButtonPlacementFromStore(button->desktopEntry()); 00103 00104 button->setState(state, progress, desktopEntryPath); 00105 00106 updateButtonPlacementInStore(desktopEntryPath); 00107 00108 if (!QFileInfo(desktopEntryPath).exists()) { 00109 // In error case that package doesn't have desktop entry yet, 00110 // just remove button from launcher and let launcher data store 00111 // to handle button addition when/if desktop entry comes available 00112 removeLauncherButton(desktopEntryPath); 00113 } 00114 } 00115 } 00116 00117 Launcher::Placement Launcher::entryPlacementInDatastore(const QString &desktopEntryPath) 00118 { 00119 Launcher::Placement placement; 00120 QString entryFileName = QFileInfo(desktopEntryPath).fileName(); 00121 QHash<QString, QVariant> allDesktopEntryPlacements = dataStore->dataForAllDesktopEntries(); 00122 foreach (const QString &desktopEntryPath, allDesktopEntryPlacements.keys()) { 00123 if (QFileInfo(desktopEntryPath).fileName() == entryFileName) { 00124 placement.setPlacement(allDesktopEntryPlacements.value(desktopEntryPath).toString()); 00125 } 00126 } 00127 return placement; 00128 } 00129 00130 QSharedPointer<LauncherButton> Launcher::placeholderButton(const QString& desktopEntryPath) 00131 { 00132 QSharedPointer<LauncherButton> button; 00133 Launcher::Placement placement(buttonPlacement(desktopEntryPath)); 00134 if (!placement.isNull()) { 00135 // If button for package is already found in launcher, then just return the button as placeholder. 00136 QSharedPointer<LauncherPage> page = model()->launcherPages().at(placement.page); 00137 button = page->model()->launcherButtons().at(placement.position); 00138 } else { 00139 // If there is no button yet for the application, then we need to create a placeholder 00140 button = createLauncherButton(desktopEntryPath); 00141 QList<QSharedPointer<LauncherPage> > pages = model()->launcherPages(); 00142 appendButtonToPages(button, pages); 00143 model()->setLauncherPages(pages); 00144 } 00145 00146 return button; 00147 } 00148 00149 void Launcher::removePlaceholderButton(const QString &desktopEntryPath) 00150 { 00151 Launcher::Placement placement(buttonPlacement(QFileInfo(desktopEntryPath).fileName())); 00152 if (!placement.isNull()) { 00153 QSharedPointer<LauncherPage> page = model()->launcherPages().at(placement.page); 00154 QSharedPointer<LauncherButton> buttonForDesktopEntry = page->model()->launcherButtons().at(placement.position); 00155 00156 // Only remove button if the paths match so that we don't remove installed buttons 00157 if (buttonForDesktopEntry->desktopEntry() == desktopEntryPath) { 00158 removeButtonPlacementFromStore(desktopEntryPath); 00159 removeLauncherButton(desktopEntryPath); 00160 } 00161 } 00162 } 00163 00164 void Launcher::updatePagesFromDataStore() 00165 { 00166 if (dataStore != NULL) { 00167 // Stop listening to dataStoreChanged() and start listening to individual updates instead. 00168 disconnect(dataStore, SIGNAL(dataStoreChanged()), this, SLOT(updatePagesFromDataStore())); 00169 connect(dataStore, SIGNAL(desktopEntryAdded(QString)), this, SLOT(addLauncherButton(QString)), Qt::UniqueConnection); 00170 connect(dataStore, SIGNAL(desktopEntryRemoved(QString)), this, SLOT(removeLauncherButton(QString)), Qt::UniqueConnection); 00171 connect(dataStore, SIGNAL(desktopEntryChanged(QString)), this, SLOT(updateLauncherButton(QString)), Qt::UniqueConnection); 00172 } 00173 00174 // Update the pages 00175 QList<QSharedPointer<LauncherPage> > pages; 00176 addDesktopEntriesWithKnownPlacements(pages); 00177 addDesktopEntriesWithUnknownPlacements(pages); 00178 removeEmptyPages(pages); 00179 model()->setLauncherPages(pages); 00180 00181 // After updating launcher from launcher data store we can connect package listener and update the states 00182 if (packageMonitorListener != NULL) { 00183 connect(packageMonitorListener, SIGNAL(packageStateChanged(QString, LauncherButtonModel::State, int)), 00184 this, SLOT(updateButtonState(QString, LauncherButtonModel::State, int)), Qt::UniqueConnection); 00185 connect(packageMonitorListener, SIGNAL(installExtraEntryRemoved(QString)), 00186 this, SLOT(removePlaceholderButton(QString)), Qt::UniqueConnection); 00187 00188 packageMonitorListener->updatePackageStates(); 00189 } 00190 } 00191 00192 void Launcher::addDesktopEntriesWithKnownPlacements(QList<QSharedPointer<LauncherPage> > &pages) 00193 { 00194 // Put the desktop entries with known placements in the desired pages 00195 QMapIterator<Placement, QString> iterator(createPlacementMap(dataStore->dataForAllDesktopEntries())); 00196 while (iterator.hasNext()) { 00197 iterator.next(); 00198 Placement placement(iterator.key()); 00199 QString desktopEntryPath(iterator.value()); 00200 00201 if (placement.page >= 0) { 00202 while (placement.page >= pages.count()) { 00203 // Create pages until the desired page exists. This may create empty pages which must be removed in the end 00204 QSharedPointer<LauncherPage> page = QSharedPointer<LauncherPage>(new LauncherPage); 00205 setMaximumPageSizeIfNecessary(page); 00206 pages.append(page); 00207 } 00208 00209 // Create a launcher button for the desktop entry 00210 int insertedIndex = pages.at(placement.page)->insertButton(createLauncherButton(desktopEntryPath), placement.position); 00211 00212 // If real button position is different than in store, update the new position to store 00213 if (insertedIndex != placement.position && dataStore != NULL) { 00214 dataStore->updateDataForDesktopEntry(desktopEntryPath, PLACEMENT_TEMPLATE.arg(placement.page).arg(insertedIndex)); 00215 } 00216 } 00217 } 00218 } 00219 00220 void Launcher::addDesktopEntriesWithUnknownPlacements(QList<QSharedPointer<LauncherPage> > &pages) 00221 { 00222 if (dataStore != NULL) { 00223 // Put the desktop entries with no known placement on the last page 00224 QHash<QString, QVariant> allDesktopEntryPlacements = dataStore->dataForAllDesktopEntries(); 00225 foreach (const QString &desktopEntryPath, allDesktopEntryPlacements.keys()) { 00226 Placement placementInDatastore(allDesktopEntryPlacements.value(desktopEntryPath).toString()); 00227 if (placementInDatastore.location.isEmpty() || placementInDatastore.location == LOCATION_IDENTIFIER) { 00228 // Check that desktop entry doesn't already have a button in launcher 00229 Placement placementInPages = buttonPlacementInLauncherPages(desktopEntryPath, pages); 00230 if (placementInDatastore.isNull() && placementInPages.isNull()) { 00231 Placement placementInPages = appendButtonToPages(createLauncherButton(desktopEntryPath), pages); 00232 dataStore->updateDataForDesktopEntry(desktopEntryPath, placementInPages.toString()); 00233 } 00234 } 00235 } 00236 } 00237 } 00238 00239 void Launcher::removeEmptyPages(QList<QSharedPointer<LauncherPage> > &pages) 00240 { 00241 // Remove empty pages if they exist 00242 int firstRemovedPage = -1; 00243 for (int page = 0; page < pages.count();) { 00244 if (pages.at(page)->model()->launcherButtons().count() == 0) { 00245 // The page is empty: remove it 00246 pages.removeAt(page); 00247 if (firstRemovedPage < 0) { 00248 // Keep track of the first removed page 00249 firstRemovedPage = page; 00250 } 00251 } else { 00252 page++; 00253 } 00254 } 00255 00256 if (dataStore != NULL) { 00257 // Locations of launcher buttons on subsequent pages have changed so update all of them 00258 if (firstRemovedPage >= 0) { 00259 for (int page = firstRemovedPage; page < pages.count(); page++) { 00260 const QList<QSharedPointer<LauncherButton> > &launcherButtons = pages.at(page)->model()->launcherButtons(); 00261 for (int position = 0; position < launcherButtons.count(); position++) { 00262 dataStore->updateDataForDesktopEntry(launcherButtons.at(position)->desktopEntry(), PLACEMENT_TEMPLATE.arg(page).arg(position)); 00263 } 00264 } 00265 } 00266 } 00267 } 00268 00269 QSharedPointer<LauncherButton> Launcher::createLauncherButton(const QString &desktopEntryPath) 00270 { 00271 QSharedPointer<LauncherButton> button = QSharedPointer<LauncherButton> (new LauncherButton(desktopEntryPath)); 00272 button->setObjectName("LauncherButton"); 00273 connect(button.data(), SIGNAL(clicked()), this, SIGNAL(launcherButtonClicked())); 00274 return button; 00275 } 00276 00277 void Launcher::addLauncherButton(const QString &desktopEntryPath) 00278 { 00279 Launcher::Placement placement = buttonPlacement(desktopEntryPath); 00280 if (placement.isNull()) { 00281 QList<QSharedPointer<LauncherPage> > pages = model()->launcherPages(); 00282 appendButtonToPages(createLauncherButton(desktopEntryPath), pages); 00283 model()->setLauncherPages(pages); 00284 00285 updateButtonPlacementInStore(desktopEntryPath); 00286 } 00287 } 00288 00289 Launcher::Placement Launcher::appendButtonToPages(QSharedPointer<LauncherButton> button, QList<QSharedPointer<LauncherPage> > &pages) 00290 { 00291 QSharedPointer<LauncherPage> page; 00292 00293 bool added = false; 00294 if (!pages.isEmpty()) { 00295 page = pages.last(); 00296 added = page->appendButton(button); 00297 } 00298 00299 if (!added) { 00300 page = QSharedPointer<LauncherPage>(new LauncherPage()); 00301 setMaximumPageSizeIfNecessary(page); 00302 pages.append(page); 00303 //We created a page so update the model 00304 model()->setLauncherPages(pages); 00305 page->appendButton(button); 00306 } 00307 00308 int pageIndex = pages.count() - 1; 00309 int position = page->launcherButtonPosition(button->desktopEntry()); 00310 return Placement(pageIndex, position); 00311 } 00312 00313 void Launcher::removeLauncherButton(const QString &desktopEntryPath) 00314 { 00315 QList<QSharedPointer<LauncherPage> > pages = model()->launcherPages(); 00316 00317 int pageIndex = 0; 00318 foreach (QSharedPointer<LauncherPage> page, pages) { 00319 if (page->removeButton(desktopEntryPath)) { 00320 00321 QList<QSharedPointer<LauncherButton> > buttons = page->model()->launcherButtons(); 00322 if (buttons.count() == 0) { 00323 // remove empty page 00324 pages.removeOne(page); 00325 model()->setLauncherPages(pages); 00326 } else if (dataStore != NULL) { 00327 // Update new locations for other launcher buttons on page (when button is removed other buttons get shifted) 00328 int buttonIndex = 0; 00329 foreach (QSharedPointer<LauncherButton> button, buttons) { 00330 dataStore->updateDataForDesktopEntry(button->desktopEntry(), PLACEMENT_TEMPLATE.arg(pageIndex).arg(buttonIndex++)); 00331 } 00332 } 00333 break; 00334 } 00335 pageIndex++; 00336 } 00337 } 00338 00339 bool Launcher::updateLauncherButton(const QString &desktopEntryPath) 00340 { 00341 bool found = false; 00342 foreach (QSharedPointer<LauncherPage> page, model()->launcherPages()) { 00343 if (page->updateButton(desktopEntryPath)) { 00344 found = true; 00345 break; 00346 } 00347 } 00348 return found; 00349 } 00350 00351 QMap<Launcher::Placement, QString> Launcher::createPlacementMap(const QHash<QString, QVariant> &desktopEntryPlacements) 00352 { 00353 QMap<Launcher::Placement, QString> placementMap; 00354 00355 foreach (const QString &desktopEntryPath, desktopEntryPlacements.keys()) { 00356 Placement placement(desktopEntryPlacements.value(desktopEntryPath).toString()); 00357 if (placement.location == LOCATION_IDENTIFIER) { 00358 placementMap.insert(placement, desktopEntryPath); 00359 } 00360 } 00361 00362 return placementMap; 00363 } 00364 00365 int Launcher::focusToButton(const QString &desktopFileEntry) 00366 { 00367 int page = buttonPlacement(desktopFileEntry).page; 00368 if (page >= 0) { 00369 emit focusToButtonRequested(desktopFileEntry); 00370 } 00371 return page; 00372 } 00373 00374 void Launcher::setPage(uint page) 00375 { 00376 emit focusToPageRequested(page); 00377 } 00378 00379 void Launcher::setMaximumPageSizeIfNecessary(QSharedPointer<LauncherPage> &page) 00380 { 00381 if (maximumPageSize >= 0) { 00382 page->setMaximumButtonCount(maximumPageSize); 00383 } 00384 } 00385 00386 Launcher::Placement Launcher::buttonPlacement(const QString &desktopFileEntry) 00387 { 00388 if (!desktopFileEntry.isEmpty()) { 00389 QList<QSharedPointer<LauncherPage> > pages = model()->launcherPages(); 00390 return buttonPlacementInLauncherPages(desktopFileEntry, pages); 00391 } 00392 00393 return Placement(); 00394 } 00395 00396 00397 void Launcher::updateButtonPlacementInStore(const QString &desktopEntryPath) 00398 { 00399 Placement placement = buttonPlacement(desktopEntryPath); 00400 00401 dataStore->updateDataForDesktopEntry(desktopEntryPath, placement.toString()); 00402 } 00403 00404 void Launcher::removeButtonPlacementFromStore(const QString &desktopEntryPath) 00405 { 00406 dataStore->removeDataForDesktopEntry(desktopEntryPath); 00407 } 00408 00409 Launcher::Placement::Placement() : page(-1), position(-1) { 00410 } 00411 00412 Launcher::Placement::Placement(const QString &placementString) : page(-1), position(-1) { 00413 setPlacement(placementString); 00414 } 00415 00416 Launcher::Placement::Placement(int page, int position) 00417 : location(LOCATION_IDENTIFIER), page(page), position(position) { 00418 } 00419 00420 void Launcher::Placement::setPlacement(const QString &placementString) 00421 { 00422 location = placementString.section(SECTION_SEPARATOR, 0, 0); 00423 if (location == LOCATION_IDENTIFIER) { 00424 page = placementString.section(SECTION_SEPARATOR, 1, 1).toInt(); 00425 position = placementString.section(SECTION_SEPARATOR, 2, 2).toInt(); 00426 } 00427 } 00428 00429 QString Launcher::Placement::toString() 00430 { 00431 return PLACEMENT_TEMPLATE.arg(page).arg(position); 00432 } 00433 00434 inline bool operator<(const Launcher::Placement &p1, const Launcher::Placement &p2) 00435 { 00436 if (p1.page != p2.page) { 00437 return p1.page < p2.page; 00438 } 00439 00440 return p1.position < p2.position; 00441 }
| Copyright © 2010 Nokia Corporation | Generated on Thu Nov 4 2010 18:20:42 Doxygen 1.7.1 |
MeeGo Touch |