/***************************************************************** Copyright (c) 2000 Bill Nagel Copyright (c) 2004 Dan Bullok Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "configdlg.h" #include "popularity.h" #include "quicklauncher.h" #include "quickbutton.h" #include "quickaddappsmenu.h" #include "quickbuttongroup.h" typedef ButtonGroup::iterator ButtonIter; const ButtonGroup::Index NotFound=ButtonGroup::NotFound; const ButtonGroup::Index Append=ButtonGroup::Append; #ifdef DEBUG #define DEBUGSTR kdDebug() #else #define DEBUGSTR kndDebug() #endif extern "C" { KDE_EXPORT KPanelApplet* init(TQWidget *parent, const TQString& configFile) { KGlobal::locale()->insertCatalogue("quicklauncher"); return new QuickLauncher(configFile, KPanelApplet::Normal, KPanelApplet::Preferences, parent, "quicklauncher"); } } QuickLauncher::QuickLauncher(const TQString& configFile, Type type, int actions, TQWidget *parent, const char *name) : KPanelApplet(configFile, type, actions, parent, name) { DCOPObject::setObjId("QuickLauncherApplet"); DEBUGSTR << endl << endl << endl << "------------" << flush; DEBUGSTR << "QuickLauncher::QuickLauncher(" << configFile << ",...)" << endl << flush; m_settings = new Prefs(sharedConfig()); m_settings->readConfig(); m_needsSave = false; m_needsRefresh = false; m_refreshEnabled = false; m_configDialog = 0; m_popup = 0; m_appletPopup = 0; m_removeAppsMenu = 0; m_dragAccepted = false; m_buttons = new ButtonGroup; m_manager = new FlowGridManager; m_newButtons = 0; m_oldButtons = 0; m_dragButtons = 0; m_configAction = new KAction(i18n("Configure Quicklauncher..."), "configure", KShortcut(), TQT_TQOBJECT(this), TQT_SLOT(slotConfigure()), TQT_TQOBJECT(this)); m_saveTimer = new TQTimer(this, "m_saveTimer"); connect(m_saveTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(saveConfig())); m_popularity = new PopularityStatistics(); setBackgroundOrigin(AncestorOrigin); loadConfig(); buildPopupMenu(); m_minPanelDim = std::max(16, m_settings->iconDimChoices()[1]); refreshContents(); setRefreshEnabled(true); setAcceptDrops(true); //TQToolTip::add(this, i18n("Drop applications here")); DEBUGSTR << " QuickLauncher::QuickLauncher(" << configFile << ",...) END" << endl << flush; DCOPClient *dcopClient = KApplication::dcopClient(); dcopClient->connectDCOPSignal(0, "appLauncher", "serviceStartedByStorageId(TQString,TQString)", "QuickLauncherApplet", "serviceStartedByStorageId(TQString,TQString)", false); kdDebug() << "Quicklauncher registered DCOP signal" << endl; } //TODO:? Drag/drop more than one item at a time QuickLauncher::~QuickLauncher() { KGlobal::locale()->removeCatalogue("quicklauncher"); setCustomMenu(0); delete m_popup; delete m_appletPopup; delete m_removeAppsMenu; delete m_popularity; clearTempButtons(); if (m_buttons) { m_buttons->deleteContents(); delete m_buttons; } } // Builds, connects _popup menu void QuickLauncher::buildPopupMenu() { QuickAddAppsMenu *addAppsMenu = new QuickAddAppsMenu(this, this); m_popup = new TQPopupMenu(this); m_popup->insertItem(i18n("Add Application"), addAppsMenu); m_configAction->plug(m_popup); m_appletPopup = new TQPopupMenu(this); m_appletPopup->insertItem(i18n("Add Application"), addAppsMenu); m_removeAppsMenu = new TQPopupMenu(this); connect(m_removeAppsMenu, TQT_SIGNAL(aboutToShow()), TQT_SLOT(fillRemoveAppsMenu())); connect(m_removeAppsMenu, TQT_SIGNAL(activated(int)), TQT_SLOT(removeAppManually(int))); m_appletPopup->insertItem(i18n("Remove Application"), m_removeAppsMenu); m_appletPopup->insertSeparator(); m_appletPopup->setCheckable( true ); m_appletPopup->insertItem(i18n("About"), this, TQT_SLOT(about())); setCustomMenu(m_appletPopup); } // Fill the remove apps menu void QuickLauncher::fillRemoveAppsMenu() { m_removeAppsMenu->clear(); ButtonIter iter(m_buttons->begin()); int i = 0; while (iter != m_buttons->end()) { TQString text = TQToolTip::textFor(*iter); if (text.isEmpty()) { text = (*iter)->url(); if (text.isEmpty()) { text = i18n("Unknown"); } } m_removeAppsMenu->insertItem((*iter)->icon(), text, i); ++iter; ++i; } } void QuickLauncher::slotSettingsDialogChanged() { // Update conserve space setting setConserveSpace(m_settings->conserveSpace()); m_popularity->setHistoryHorizon(m_settings->historyHorizon()/100.0); slotAdjustToCurrentPopularity(); kdDebug() << "Icon size: " << m_settings->iconDim() << endl; refreshContents(); saveConfig(); } void QuickLauncher::action(Action a) { if (a == KPanelApplet::Preferences) { slotConfigure(); } else { KPanelApplet::action(a); } } void QuickLauncher::slotConfigure() { if (!m_configDialog) { m_configDialog = new ConfigDlg(this, "configdialog", m_settings, SIZE_AUTO, KDialogBase::Plain, KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Apply | KDialogBase::Default); connect(m_configDialog, TQT_SIGNAL(settingsChanged()), this, TQT_SLOT(slotSettingsDialogChanged())); } m_configDialog->show(); } int QuickLauncher::findApp(QuickButton *button) { if (m_buttons->empty()) { return NotFound; } int pos = m_buttons->findValue(button); return pos; } int QuickLauncher::findApp(TQString url) { if (m_buttons->empty()) { return NotFound; } int pos=m_buttons->findDescriptor(url); return pos; } void QuickLauncher::removeAppManually(int index) { removeApp(index, true); } void QuickLauncher::removeApp(int index, bool manuallyRemoved) { if (m_buttons->empty()) { return; } if (!m_buttons->isValidIndex(index)) { kdWarning() << " removeApp (" << index << ") *******WARNING****** index=" << index << "is out of bounds." << endl << flush; return; } DEBUGSTR << "Removing button. index=" << index << " url='" << (*m_buttons)[index]->url() << "'" << endl << flush; TQString removeAppUrl = (*m_buttons)[index]->url(); TQString removeAppMenuId = (*m_buttons)[index]->menuId(); if (removeAppUrl == "SPECIAL_BUTTON__SHOW_DESKTOP") { m_settings->setShowDesktopEnabled(false); } delete (*m_buttons)[index]; m_buttons->eraseAt(index); refreshContents(); if (int(m_buttons->size()) < m_settings->autoAdjustMinItems() && manuallyRemoved) { m_settings->setAutoAdjustMinItems(m_buttons->size()); } if (manuallyRemoved) { m_popularity->moveToBottom(removeAppMenuId); slotAdjustToCurrentPopularity(); } saveConfig(); } void QuickLauncher::removeApp(TQString url, bool manuallyRemoved) { int index = findApp(url); if (index == NotFound) { kdDebug() << "removeApp: Not found: " << url << endl; return; } removeApp(index, manuallyRemoved); } void QuickLauncher::removeAppManually(QuickButton *button) { int index = findApp(button); if (index == NotFound) { return; } removeApp(index, true); } int QuickLauncher::widthForHeight(int h) const { FlowGridManager temp_manager = *m_manager; temp_manager.setFrameSize(TQSize(h,h)); temp_manager.setOrientation(Qt::Horizontal); // ??? probably not necessary if (temp_manager.isValid()) { return temp_manager.frameSize().width(); } return m_minPanelDim; } int QuickLauncher::heightForWidth(int w) const { FlowGridManager temp_manager=*m_manager; temp_manager.setFrameSize(TQSize(w,w)); temp_manager.setOrientation(Qt::Vertical); // ??? probably not necessary if (temp_manager.isValid()) { return temp_manager.frameSize().height(); } return m_minPanelDim; } int QuickLauncher::dimension() const { if (orientation()==Qt::Vertical) { return size().width(); } return size().height(); } void QuickLauncher::addApp(TQString url, bool manuallyAdded) { assert(m_buttons); TQString newButtonId = QuickURL(url).menuId(); if (m_appOrdering.find(newButtonId) == m_appOrdering.end()) { m_appOrdering[newButtonId] = m_appOrdering.size(); } uint appPos; for (appPos = 0; appPos < m_buttons->size(); ++appPos) { TQString buttonId = (*m_buttons)[appPos]->menuId(); if (m_appOrdering[buttonId] >= m_appOrdering[newButtonId]) { break; } } addApp(url, appPos, manuallyAdded); } QuickButton* QuickLauncher::createButton(TQString url) { QuickButton* newButton=new QuickButton(url, m_configAction, this); connect(newButton, TQT_SIGNAL(executed(TQString)), this, TQT_SLOT(slotOwnServiceExecuted(TQString))); connect(newButton, TQT_SIGNAL(stickyToggled(bool)), this, TQT_SLOT(slotStickyToggled())); newButton->setPopupDirection(popupDirection()); return newButton; } void QuickLauncher::addApp(TQString url, int index, bool manuallyAdded) { DEBUGSTR << endl <<"About to add: url='" << url << "' index=" << index << endl << flush; QuickButton *newButton; if (!m_buttons->isValidInsertIndex(index)) { kdWarning() << " *******WARNING****** index=" << index << "is out of bounds." << endl << flush; index = m_buttons->lastIndex(); } int old = findApp(QuickURL(url).url()); if (old != NotFound) { if (index == old) { return; } if (index > old) { index--; } newButton = (*m_buttons)[old]; m_buttons->eraseAt(old); } else { newButton = createButton(url); } m_buttons->insertAt(index, newButton); DEBUGSTR << "Added: url='"<size(); ++n) { TQString buttonId = (*m_buttons)[n]->menuId(); appList.push_back(buttonId); if (m_appOrdering.find(buttonId) == m_appOrdering.end()) { m_appOrdering[buttonId] = m_appOrdering.size(); } posList.insert(m_appOrdering[buttonId]); //kdDebug() << m_appOrdering[buttonId] << " = " << buttonId << endl; } //kdDebug() << "After:" << endl; while (posList.size() > 0) { assert(appList.size() > 0); m_appOrdering[*appList.begin()] = *posList.begin(); kdDebug() << *posList.begin() << " = " << *appList.begin() << endl; posList.erase(posList.begin()); appList.pop_front(); } //kdDebug() << "Done." << endl; } void QuickLauncher::addAppBeforeManually(TQString url, TQString sender) { if (sender.isNull()) { addApp(url, Append, true); } int pos = findApp(sender); if (pos < 0) { pos = Append; } DEBUGSTR << "QuickLauncher::addAppBefore(" << url << "," << sender << "): pos=" << pos << endl << flush; addApp(url, pos, true); } void QuickLauncher::about() { KAboutData about("quicklauncher", I18N_NOOP("Quick Launcher"), "2.0", I18N_NOOP("A simple application launcher"), KAboutData::License_GPL_V2, "(C) 2000 Bill Nagel\n(C) 2004 Dan Bullok\n(C) 2005 Fred Schaettgen"); KAboutApplication a(&about, this); a.exec(); } void QuickLauncher::mousePressEvent(TQMouseEvent *e) { if (e->button() == Qt::RightButton) { m_popup->popup(e->globalPos()); } } void QuickLauncher::resizeEvent(TQResizeEvent*) { refreshContents(); } void QuickLauncher::dragEnterEvent(TQDragEnterEvent *e) { DEBUGSTR << "QuickLauncher::dragEnterEvent(pos=" << e->pos() << " type=" << e->type() << ")" << endl << flush; m_dragAccepted=false; KURL::List kurlList; if (!isDragEnabled() || !KURLDrag::decode(e, kurlList)) { e->accept(false); return; } if (kurlList.size()<=0) { e->accept(false); return; } m_dragButtons=new ButtonGroup; m_oldButtons=new ButtonGroup(*m_buttons); TQString url; KURL::List::ConstIterator it = kurlList.begin(); for ( ; it != kurlList.end(); ++it ) { url = QuickURL((*it).url()).url(); kdDebug() << " Drag Object='"<findDescriptor(url); if (pos != NotFound) { // if it's already in m_buttons, take it out m_dragButtons->push_back(m_buttons->takeFrom(pos)); } else { // otherwise, create a new one QuickButton* button = createButton(url); button->setSticky(true); m_dragButtons->push_back(button); } } if (m_dragButtons->size() > 0) { //make sure we can drag at least one button. m_dragAccepted=true; m_newButtons=new ButtonGroup(*m_buttons); m_dropPos=NotFound; e->accept(true); return; } e->accept(false); clearTempButtons(); } void QuickLauncher::dragMoveEvent(TQDragMoveEvent *e) { if (!m_dragAccepted) { kdWarning() << "QuickLauncher::dragMoveEvent: Drag is not accepted." << m_dragAccepted << endl << flush; e->accept(false); return; } e->accept(true); int pos=m_manager->indexNearest(e->pos()); if (pos == m_dropPos) { return;// Already been inserted here, no need to update } if (m_newButtons->isValidInsertIndex(pos)) { mergeButtons(pos); m_dropPos=pos; } refreshContents(); } void QuickLauncher::dragLeaveEvent(TQDragLeaveEvent *e) { DEBUGSTR << "QuickLauncher::dragLeaveEvent(type=" << e->type() << ")" << endl << flush; if (!m_dragAccepted) { return; } // No drop. Return to starting state. std::swap(m_buttons,m_oldButtons); clearTempButtons(); refreshContents(); saveConfig(); } void QuickLauncher::dropEvent(TQDropEvent *e) { DEBUGSTR << "QuickLauncher::dropEvent(pos=" << e->pos() << " type=" << e->type() << ")" << endl << flush; if (!m_dragAccepted) { e->accept(false); return; } if (e->source() == 0) { for (uint n=0; nsize(); ++n) { (*m_dragButtons)[n]->setSticky(true); } } clearTempButtons(); refreshContents(); saveConfig(); updateInsertionPosToStatusQuo(); } // insert dragbuttons at index in m_newButtons. Put result in m_buttons void QuickLauncher::mergeButtons(int index) { if (!m_newButtons->isValidInsertIndex(index)) { index=m_newButtons->size(); } m_buttons->clear(); (*m_buttons) = (*m_newButtons); m_buttons->insertAt(index, *m_dragButtons); refreshContents(); } void QuickLauncher::clearTempButtons() { std::set allButtons; //put all the m_buttons in a set (removes duplicates automatically if (m_newButtons) { allButtons.insert(m_newButtons->begin(),m_newButtons->end()); } if (m_oldButtons) { allButtons.insert(m_oldButtons->begin(),m_oldButtons->end()); } if (m_dragButtons) { allButtons.insert(m_dragButtons->begin(),m_dragButtons->end()); } //delete temp ButtonGroups delete m_newButtons; m_newButtons=0; delete m_oldButtons; m_oldButtons=0; delete m_dragButtons; m_dragButtons=0; //if an element allButtons is NOT in m_buttons (the ones we keep), delete it std::set::iterator iter = allButtons.begin(); while (iter != allButtons.end()) { if (findApp(*iter) == NotFound) { delete *iter; } ++iter; } m_dragAccepted = false; m_dropPos = NotFound; } void QuickLauncher::refreshContents() { int idim, d(dimension()); // make sure show desktop setting is honored TQStringList urls, volatileUrls; ButtonIter iter = m_buttons->begin(); while (iter != m_buttons->end()) { if ((*iter)->sticky() == false) { volatileUrls.append((*iter)->menuId()); } urls.append((*iter)->menuId()); ++iter; } if (m_settings->showDesktopEnabled()) { if (!urls.contains("SPECIAL_BUTTON__SHOW_DESKTOP")) { urls.prepend("SPECIAL_BUTTON__SHOW_DESKTOP"); addApp("SPECIAL_BUTTON__SHOW_DESKTOP", 0, true); } } else { if (urls.contains("SPECIAL_BUTTON__SHOW_DESKTOP")) { urls.remove("SPECIAL_BUTTON__SHOW_DESKTOP"); removeApp("SPECIAL_BUTTON__SHOW_DESKTOP", true); } } // determine button size if (m_settings->iconDim() == SIZE_AUTO) { if (d < 18) { idim = std::min(16,d); } else if (d < 64) { idim = 16; } else if (d < 80) { idim = 20; } else if (d < 122) { idim = 24; } else { idim = 28; } } else { idim = std::min(m_settings->iconDim(), d - std::max((d/8)-1, 0) * 2); } m_space = std::max((idim/8)-1, 0); m_border = m_space; m_buttonSize = TQSize(idim, idim); m_manager->setOrientation(orientation()); m_manager->setNumItems(m_buttons->size()); m_manager->setFrameSize(size()); m_manager->setItemSize(m_buttonSize); m_manager->setSpaceSize(TQSize(m_space, m_space)); m_manager->setBorderSize(TQSize(m_border, m_border)); if (!m_refreshEnabled) { m_needsRefresh=true; return; } if (!m_manager->isValid()) { kdDebug()<dump(); return; } unsigned index; TQPoint pos; tqsetUpdatesEnabled(false); m_buttons->tqsetUpdatesEnabled(false); for (index = 0; index < m_buttons->size(); index++) { pos = m_manager->pos(index); QuickButton *button = (*m_buttons)[index]; button->resize(m_manager->itemSize()); button->move(pos.x(), pos.y()); button->setDragging(false); button->setEnableDrag(isDragEnabled()); button->setDynamicModeEnabled(m_settings->autoAdjustEnabled()); } if (m_newButtons) { m_newButtons->setDragging(false); } if (m_dragButtons) { m_dragButtons->setDragging(true); } m_buttons->show(); tqsetUpdatesEnabled(true); update(); m_buttons->tqsetUpdatesEnabled(true); updateGeometry(); emit updateLayout(); updateStickyHighlightLayer(); } void QuickLauncher::setDragEnabled(bool enable) { m_settings->setDragEnabled(enable); } void QuickLauncher::setConserveSpace(bool conserve_space) { m_manager->setConserveSpace(conserve_space); if (conserve_space) { m_manager->setSlack(FlowGridManager::SpaceSlack, FlowGridManager::SpaceSlack); } else { m_manager->setSlack(FlowGridManager::ItemSlack, FlowGridManager::ItemSlack); } refreshContents(); } class SortByPopularity { public: bool operator()(const QuickLauncher::PopularityInfo& a, const QuickLauncher::PopularityInfo& b) { return a.popularity < b.popularity; } }; void QuickLauncher::loadConfig() { DEBUGSTR << "QuickLauncher::loadConfig()" << endl << flush; //KConfig *c = config(); //c->setGroup("General"); setConserveSpace(m_settings->conserveSpace()); setDragEnabled(m_settings->dragEnabled()); /*DEBUGSTR << " IconDim="<size()); ++n) { QuickButton* button = (*m_buttons)[n]; if (volatileButtons.tqcontains(button->menuId()) == false) { button->setSticky(true); } button->setDynamicModeEnabled(m_settings->autoAdjustEnabled()); } m_popularity->readConfig(m_settings); m_popularity->setHistoryHorizon(m_settings->historyHorizon()/100.0); TQStringList serviceNames = m_settings->serviceNames(); TQValueList insPos = m_settings->serviceInspos(); for (int n=std::min(serviceNames.size(),insPos.size())-1; n>=0; --n) { m_appOrdering[serviceNames[n]] = insPos[n]; } } void QuickLauncher::saveConfig() { if (!m_refreshEnabled) { m_needsSave=true; return; } TQStringList urls, volatileUrls; ButtonIter iter = m_buttons->begin(); while (iter != m_buttons->end()) { if ((*iter)->sticky() == false) { volatileUrls.append((*iter)->menuId()); } urls.append((*iter)->menuId()); ++iter; } m_settings->setButtons(urls); kdDebug() << "SetButtons " << urls.join("/") << endl; m_settings->setVolatileButtons(volatileUrls); m_settings->setConserveSpace(m_manager->conserveSpace()); m_settings->setDragEnabled(isDragEnabled()); m_popularity->writeConfig(m_settings); // m_popularity must have written the current service list by now TQStringList serviceNames = m_settings->serviceNames(); TQValueList insertionPositions; for (int n=0; nsetServiceInspos(insertionPositions); m_settings->writeConfig(); } void QuickLauncher::setRefreshEnabled(bool enable) { m_refreshEnabled=enable; if (m_refreshEnabled) { if (m_needsSave) { saveConfig(); } if (m_needsRefresh) { refreshContents(); } } } void QuickLauncher::serviceStartedByStorageId(TQString /*starter*/, TQString storageId) { KService::Ptr service = KService::serviceByStorageId(storageId); if (service->icon() == TQString::null) { kdDebug() << storageId << " has no icon. Makes no sense to add it."; return; } QuickURL url = QuickURL(locate("apps", service->desktopEntryPath())); TQString desktopMenuId(url.menuId()); kdDebug() << "storageId=" << storageId << " desktopURL=" << desktopMenuId << endl; // A service was started somwhere else. If the quicklauncher contains // this service too, we flash the icon QuickButton *startedButton = 0; std::set buttonIdSet; for (uint n = 0; n < m_buttons->size(); ++n) { QuickButton *button = (*m_buttons)[n]; TQString buttonMenuId = button->menuId(); buttonIdSet.insert(buttonMenuId); if (desktopMenuId == buttonMenuId) { kdDebug() << "QuickLauncher: I know that one: " << storageId << endl; button->flash(); startedButton = button; } } // Update popularity info. // We do this even if autoadjust is disabled // so there are sane values to start with if it's turned on. m_popularity->useService(desktopMenuId); if (m_settings->autoAdjustEnabled()) { TQTimer::singleShot(0, this, TQT_SLOT(slotAdjustToCurrentPopularity())); } } void QuickLauncher::slotAdjustToCurrentPopularity() { // TODO: Shrink immediately if buttons->size() > maxItems kdDebug() << "Starting popularity update" << endl; PopularityStatistics* stats = m_popularity; int minItems = m_settings->autoAdjustMinItems(); int maxItems = m_settings->autoAdjustMaxItems(); static const double hysteresisFactor = 0.90; double minAddPopularity = 0; for (int n = 0; n < maxItems; ++n) { // All items with a popularity not less than 0.75 of the average // of the first maxItems apps are included in the list double belowAvgAllowed = 0.75; minAddPopularity += (belowAvgAllowed * stats->popularityByRank(n)) / maxItems; } double minDelPopularity = minAddPopularity * hysteresisFactor; std::map removeableApps; std::set existingApps; int numApps = m_buttons->size(); for (int n = 0; n < int(m_buttons->size()); ++n) { QuickButton *button = (*m_buttons)[n]; if (((stats->popularityByRank(stats->rankByService(button->menuId())) < minDelPopularity) || m_settings->autoAdjustEnabled()==false) && (button->sticky() == false)) { removeableApps[button->menuId()] = button; --numApps; } existingApps.insert(button->menuId()); } for (int n = 0; (numApps < minItems && stats->popularityByRank(n) > 0) || (numApps < maxItems && stats->popularityByRank(n) > minAddPopularity); ++n) { TQString app = m_popularity->serviceByRank(n); if (existingApps.find(app) == existingApps.end()) { addApp(QuickURL(m_popularity->serviceByRank(n)).url(), false); kdDebug() << "Adding app " << app << endl; ++numApps; } else if (removeableApps.find(app) != removeableApps.end()) { removeableApps.erase(app); ++numApps; } } while (removeableApps.size() > 0) { removeApp(findApp(removeableApps.begin()->second), false); kdDebug() << "Removing app " << removeableApps.begin()->first << endl; removeableApps.erase(removeableApps.begin()->first); } kdDebug() << "done popularity update" << endl; m_settings->setAutoAdjustMinItems(minItems); m_settings->setAutoAdjustMaxItems(maxItems); // TODO: Think of something better than that: m_saveTimer->start(10000,true); } void QuickLauncher::slotOwnServiceExecuted(TQString serviceMenuId) { m_popularity->useService(serviceMenuId); if (m_settings->autoAdjustEnabled()) { TQTimer::singleShot(0, this, TQT_SLOT(slotAdjustToCurrentPopularity())); } } void QuickLauncher::updateStickyHighlightLayer() { // Creates a transparent image which is used // to highlight those buttons which will never // be removed automatically from the launcher TQPixmap areaPix(width(), height()); TQPainter areaPixPainter(&areaPix); areaPixPainter.fillRect(0, 0, width(), height(), TQColor(255, 255, 255)); TQSize itemSize = m_manager->itemSize(); TQSize spaceSize = m_manager->spaceSize(); for (uint n=0; nsize(); ++n) { TQPoint pos = m_manager->pos(n); if ((*m_buttons)[n]->sticky() == false) { areaPixPainter.fillRect(pos.x()-(spaceSize.width()+1)/2, pos.y()-(spaceSize.height()+1)/2, itemSize.width()+spaceSize.width()+1, itemSize.height()+spaceSize.height()+1, TQColor(0, 0, 0)); } } TQImage areaLayer = areaPix.convertToImage(); m_stickyHighlightLayer = TQImage(width(), height(), 32); m_stickyHighlightLayer.setAlphaBuffer(true); int pix, tlPix, brPix, w(width()), h(height()); QRgb transparent(tqRgba(0, 0, 0, 0)); for (int y = h-1; y >= 0; --y) { for (int x = w-1; x >= 0; --x) { pix = tqRed(areaLayer.pixel(x, y)); if (pix == 0) { tlPix = (y>0 && x>0) ? tqRed(areaLayer.pixel(x-1,y-1)) : 255; brPix = (yautoAdjustEnabled() && m_settings->showVolatileButtonIndicator()) { TQPainter p(this); p.drawImage(0, 0, m_stickyHighlightLayer); } } void QuickLauncher::slotStickyToggled() { updateStickyHighlightLayer(); saveConfig(); } void QuickLauncher::positionChange(Position) { for (int n=0; nsize()); ++n) { (*m_buttons)[n]->setPopupDirection(popupDirection()); } } #include "quicklauncher.moc"