/*************************************************************************** * Copyright (C) 2006-2007 by Marco Martin * * notmart@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the Lesser GNU General Public * * License as published by the Free Software Foundation; * * either version 2 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "menuhandler.h" #include "buttons.h" MenuHandler::MenuHandler( TQWidget *parent, Prefs *prefs, char *name, WFlags fl) :TQFrame(parent, name, fl ), searchMode(false) { prefSkel = prefs; //make a KServiceGroup to iterate the menu entries KServiceGroup::Ptr service = KServiceGroup::root(); //Kicker config TQString kickerConfPath = locate("config", "kickerrc"); kickerConf = new TDEConfig(kickerConfPath); kickerConfWatch = new KDirWatch( this ); kickerConfWatch->addFile(kickerConfPath); connect( kickerConfWatch, SIGNAL(dirty(const TQString&)), this, SLOT(slotModKickerConf()) ); connect( kickerConfWatch, SIGNAL(dirty(const TQString&)), this, SIGNAL(kickerConfChanged()) ); if( _newAppsNotification = prefSkel->newAppsNotification() ) { //init the old and new installed list oldInstalledList = prefSkel->oldInstalledApps(); loadNewInstalledApps(); initOldInstalledApps(service); //save the creation time prefSkel->setOldInstalledAppsAge(time(0)); initNewInstalledApps(service); if( newInstalledList.count() > 0 ) emit(newApplications(newInstalledList.count())); prefSkel->setOldInstalledApps(oldInstalledList); prefSkel->setNewInstalledApps( newInstalledList ); prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps ); } //Main widget initialization menu = new Menu(this, "tastyMenu"); MenuHandlerLayout = new TQVBoxLayout( this, 0, 0, "MenuHandlerLayout"); MenuHandlerLayout->addWidget(menu); readConfig(); setupColumns(); //Searchline... iconLoader = TDEGlobal::iconLoader(); TQPixmap icon; if( TQApplication::reverseLayout() ) icon = iconLoader->loadIcon("locationbar_erase", TDEIcon::Small); else icon = iconLoader->loadIcon("clear_left", TDEIcon::Small); menu->clearButton->setIconSet(icon); connect(menu->clearButton, SIGNAL(clicked()), menu->searchLine, SLOT (clear()) ); menu->detachButton->setIconSet(TQPixmap(uic_findImage("detach.png"))); connect(menu->detachButton, SIGNAL(clicked()), this, SLOT (switchWindowMode()) ); menu->searchLine->setContextMenuEnabled(false); //event filters for keyboard navigation menu->clearButton->installEventFilter(this); menu->searchLine->installEventFilter(this); menu->menuModes->installEventFilter(this); menu->runButton->installEventFilter(this); menu->switchButton->installEventFilter(this); menu->lockButton->installEventFilter(this); menu->logoutButton->installEventFilter(this); //action buttons icon = iconLoader->loadIcon("system-log-out", TDEIcon::Toolbar); menu->logoutButton->setIconSet(icon); icon = iconLoader->loadIcon("system-lock-screen", TDEIcon::Toolbar); menu->lockButton->setIconSet(icon); icon = iconLoader->loadIcon("system-run", TDEIcon::Toolbar); menu->runButton->setIconSet(icon); icon = iconLoader->loadIcon("locationbar_erase", TDEIcon::Toolbar); menu->clearRecentButton->setIconSet(icon); setCaption("Tasty Menu"); setIcon(iconLoader->loadIcon("kmenu", TDEIcon::Panel)); //user icon and login KUser *user = new KUser (); TQString loginName (user->loginName ()); TQImage userImage (locate ("data", "/home/" + loginName + "/.face.icon")); if( !userImage.isNull() ) { userImage = userImage.smoothScale (TDEIcon::SizeSmallMedium, TDEIcon::SizeSmallMedium); menu->switchButton->setIconSet(TQPixmap(userImage)); } menu->switchButton->setText(loginName); sessionsMenu = new TQPopupMenu(); menu->switchButton->setPopup(sessionsMenu); initializeRecentlyUsed( ); populateList( service, menu->rootList, NULL, false ); //left/middle mouse button connect (menu->dynamicList, SIGNAL (activated(TQListViewItem *, const TQPoint & , int )), this, SLOT (dynListClicked(TQListViewItem *, const TQPoint &, int))); connect (menu->rootList, SIGNAL (activated(TQListViewItem *, const TQPoint & , int )), this, SLOT (rootListClicked(TQListViewItem *, const TQPoint &, int))); connect (menu->childList, SIGNAL (activated(TQListViewItem *, const TQPoint & , int )), this, SLOT (childListClicked(TQListViewItem *, const TQPoint &, int))); //right mouse button connect (menu->dynamicList, SIGNAL (contextMenuRequested(TQListViewItem *, const TQPoint & , int )), this, SLOT (slotContextMenu(TQListViewItem *, const TQPoint &, int))); connect (menu->rootList, SIGNAL (contextMenuRequested(TQListViewItem *, const TQPoint & , int )), this, SLOT (slotContextMenu(TQListViewItem *, const TQPoint &, int))); connect (menu->childList, SIGNAL (contextMenuRequested(TQListViewItem *, const TQPoint & , int )), this, SLOT (slotContextMenu(TQListViewItem *, const TQPoint &, int))); //don't open categories on mouseover on childlist //menu->childList->setEasyOpen( true ); connect (menu->clearRecentButton, SIGNAL (clicked()), this, SLOT (clearDynList())); connect (menu->logoutButton, SIGNAL (clicked()), this, SLOT (doLogout())); connect (menu->lockButton, SIGNAL (clicked()), this, SLOT (doLock())); connect (menu->runButton, SIGNAL (clicked()), this, SLOT (runDialog())); connect( sessionsMenu, SIGNAL(aboutToShow()), SLOT(slotPopulateSessions()) ); connect( sessionsMenu, SIGNAL(activated(int)), SLOT(slotSessionActivated(int)) ); connect( menu->menuModes, SIGNAL(activated(int)), SLOT(menuModeChanged(int)) ); menuModeChanged(_menuMode); } MenuHandler::~MenuHandler() { } void MenuHandler::loadNewInstalledApps() { //Notification for newly installed apps xdgMenuLister = new KDirLister( ); TDEStandardDirs *standardDir=new TDEStandardDirs(); TQStringList appDirs = standardDir->findDirs("xdgdata-apps", "."); firstListing = 0; for(TQStringList::Iterator it = appDirs.begin(); it != appDirs.end(); ++it) { xdgMenuLister->openURL(*it, true); /*HACK: links to kde programs are often installed in a kde subdirectory of one of these, so i duplicate all the entries with entry+"tde/"*/ TQString appDirWithTde = (*it)+"tde/"; if( TQFile::exists(appDirWithTde) ) { xdgMenuLister->openURL(appDirWithTde, true); firstListing++; } } firstListing += appDirs.count(); connect( xdgMenuLister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(slotApplicationsAdded(const KFileItemList &)) ); connect( xdgMenuLister, SIGNAL(deleteItem( KFileItem *)), this, SLOT(slotApplicationRemoved()) ); xdgMenuWatch = new KDirWatch(this); xdgMenuWatch->addFile(locateLocal("xdgconf-menu", "applications-kmenuedit.menu")); //connect with slotApplicationRemoved() because we need to wait a while... connect( xdgMenuWatch, SIGNAL(dirty(const TQString&)), this, SLOT(slotApplicationRemoved()) ); newInstalledList = prefSkel->newInstalledApps(); newInstalledTimeStamps = prefSkel->newInstalledAppsTimeStamps(); //expire old apps for(uint i=0; i 127800 ) { newInstalledTimeStamps.remove(newInstalledTimeStamps.at(i)); newInstalledList.remove(newInstalledList.at(i)); } } } void MenuHandler::setupColumns() { menu->dynamicList->header()->hide(); menu->dynamicList->setResizeMode(TQListView::AllColumns); menu->dynamicList->addColumn("name"); menu->dynamicList->setShowToolTips(true); menu->dynamicList->setSortColumn(-1); menu->dynamicList->header()->setResizeEnabled(false); menu->dynamicList->setHScrollBarMode(TQScrollView::AlwaysOff); menu->dynamicList->setActionIconSize( _actionIconSize ); menu->dynamicList->setRootIsDecorated( _showExpander ); //manage drag'n drop menu->dynamicList->setAcceptDrops(true); menu->dynamicList->setDragEnabled(true); connect( menu->dynamicList, SIGNAL(moved()), this, SLOT(dynListElemMoved()) ); menu->rootList->header()->hide(); menu->rootList->setResizeMode(TQListView::AllColumns); menu->rootList->addColumn("name"); menu->rootList->setSortColumn(-1); menu->rootList->header()->setResizeEnabled(false); menu->rootList->setHScrollBarMode(TQScrollView::AlwaysOff); menu->rootList->setHighLightGroups( false ); menu->rootList->setActionIconSize( _actionIconSize ); menu->rootList->setDragEnabled(true); menu->childList->header()->hide(); menu->childList->setResizeMode(TQListView::AllColumns); menu->childList->addColumn("name"); menu->childList->setSortColumn(_alphabetical?0:-1); menu->childList->header()->setResizeEnabled(false); menu->childList->setHScrollBarMode(TQScrollView::AlwaysOff); menu->childList->setActionIconSize( _actionIconSize ); menu->childList->setRootIsDecorated( _showExpander ); menu->childList->setDragEnabled(true); } void MenuHandler::dynListElemMoved( ) { //very stupid: iterate the entire list and rewrite the favouriteList favouriteList.clear(); TQListViewItemIterator it( menu->dynamicList ); while ( it.current() ) { TastyListViewItem *li = dynamic_cast(it.current()); if( !li ) return; favouriteList.append( li->getDeskopEntryPath() ); it++; } prefSkel->setFavouriteApps(favouriteList); prefSkel->writeConfig(); } bool MenuHandler::eventFilter( TQObject *o, TQEvent * e ) { if ( e->type() == TQEvent::KeyPress ) { TQKeyEvent *keyEvent = (TQKeyEvent *)e; TQFocusData *fData = focusData(); fData->home(); switch( keyEvent->key() ) { case TQt::Key_Up: if( dynamic_cast(o) ) return false; fData->prev()->setFocus(); break; case TQt::Key_Down: { if( dynamic_cast(o) ) return false; //this is a workaround in order to set the focus on the //right widget when the combobox is disabled TQWidget *nextWidget = fData->next(); if( nextWidget->isEnabled() ) nextWidget->setFocus(); else fData->next()->setFocus(); } break; case TQt::Key_Right: if( dynamic_cast(o) ) return false; fData->next()->setFocus(); break; case TQt::Key_Left: if( dynamic_cast(o) ) return false; fData->prev()->setFocus(); break; case TQt::Key_Enter: case TQt::Key_Return: { //only filter enter on search line if( o != menu->searchLine ) return false; TQListViewItem *listItem = NULL; //execute the only list item when there is exactly one TQListViewItemIterator it( menu->dynamicList, TQListViewItemIterator::Visible); //listItem = it.current(); int count = 0; //ensure the first level have only one result while ( it.current() ) { if( it.current()->childCount() == 0 ) { count++; listItem = it.current(); } kdDebug() << "current: " << count << " " << it.current()->text(0); if( count > 1 ) return false; it++; } if( listItem ) { dynListClicked(listItem, TQPoint(0,0), 0); menu->searchLine->clear(); } break; } default: return false; break; } return true; } //for some reasons clicking with the right mouse button on the searchline everything crashes... /* else if( e->type() == TQEvent::MouseButtonPress && o == menu->searchLine ) {return true; TQMouseEvent *mouseEvent = (TQMouseEvent *)e; if( mouseEvent->button() != TQMouseEvent::RightButton ) return true; if( menu->searchLine->text().length() < 4 ) return true; else return false; }*/ else return false; } void MenuHandler::readConfig() { _menuMode = prefSkel->menuMode(); if( _menuMode < 0 ) _menuMode = 0; menu->menuModes->setCurrentItem(_menuMode); _currentCategory = prefSkel->currentCategory(); kickerConf->setGroup("menus"); _numRecentEntries = kickerConf->readNumEntry("NumVisibleEntries", 5); _hideOneChild = prefSkel->hideOneChild(); _alphabetical = prefSkel->alphabetical(); favouriteList = prefSkel->favouriteApps(); if( favouriteList.isEmpty() ) { favouriteList.append(locate("xdgdata-apps","tde/konqbrowser.desktop")); favouriteList.append(locate("xdgdata-apps","tde/KMail.desktop")); favouriteList.append(locate("xdgdata-apps","tde/Help.desktop")); } _showExpander = prefSkel->showExpander(); _alwaysCollapsed = prefSkel->alwaysCollapsed(); _displaySubText = prefSkel->displaySubText(); _iconSize1 = prefSkel->iconSize1(); if( _iconSize1 < 16 || _iconSize1 > 64 ) _iconSize1 = 22; _iconSize2 = prefSkel->iconSize2(); if( _iconSize2 < 16 || _iconSize2 > 64 ) _iconSize2 = 22; _iconSize3 = prefSkel->iconSize3(); if( _iconSize3 < 16 || _iconSize3 > 64 ) _iconSize3 = 22; _actionIconSize = prefSkel->actionIconSize(); if( _actionIconSize > _iconSize1 ) _actionIconSize = _iconSize1; //menu size _menuWidth = 100.0/prefSkel->menuWidth(); _menuHeight = 100.0/prefSkel->menuHeight(); TQRect r = TQDesktopWidget().screenGeometry(this); int w = (int)(r.width()/_menuWidth); int h = (int)(r.height()/_menuHeight); resize(w,h); _strigiIntegration = prefSkel->strigiIntegration(); _isNormalWindow = prefSkel->isNormalWindow(); if( _isNormalWindow ) { menu->detachButton->setIconSet(TQPixmap(uic_findImage("attach.png"))); TQToolTip::add( menu->detachButton, tr2i18n( "Make this window a popup menu" ) ); } else { menu->detachButton->setIconSet(TQPixmap(uic_findImage("detach.png"))); TQToolTip::add( menu->detachButton, tr2i18n( "Make this menu a normal window" ) ); } // disconnect(menu->searchLine, 0, 0, 0); if( !_strigiIntegration ) { //menu->searchLine->setListView((TDEListView *)(menu->dynamicList)); disconnect(menu->searchLine, SIGNAL(returnPressed( const TQString &)), this, SLOT (strigiSearch( const TQString &)) ); connect(menu->searchLine, SIGNAL(textChanged( const TQString &)), this, SLOT (initializeSearch( const TQString &)) ); } else //strigi { menu->searchLine->setListView(NULL); menu->searchLine->setEnabled(true); disconnect(menu->searchLine, SIGNAL(textChanged( const TQString &)), this, SLOT (initializeSearch( const TQString &)) ); connect(menu->searchLine, SIGNAL(returnPressed( const TQString &)), this, SLOT (strigiSearch( const TQString &)) ); menu->searchLine->setContextMenuEnabled(false); } } void MenuHandler::updateConfig() { readConfig(); menu->dynamicList->setActionIconSize( _actionIconSize ); menu->rootList->setActionIconSize( _actionIconSize ); menu->childList->setActionIconSize( _actionIconSize ); menu->dynamicList->setRootIsDecorated( _showExpander ); menu->childList->setRootIsDecorated( _showExpander ); menuModeChanged( _menuMode ); KServiceGroup::Ptr service = KServiceGroup::root(); menu->rootList->clear(); populateList( service, menu->rootList, NULL, false ); } void MenuHandler::mousePressEvent( TQMouseEvent *e) { if(static_cast(parent())->hasMouse()) { close(); } else if(!_isNormalWindow && !(rect().contains(e->pos())) ) { hide(); TQTimer::singleShot(200, this,SLOT(close())); } } void MenuHandler::closeEvent ( TQCloseEvent *e) { e=e; if( _isNormalWindow ) { prefSkel->setNormalWindowWidth(width()); prefSkel->setNormalWindowHeight(height()); prefSkel->setNormalWindowX(x()); prefSkel->setNormalWindowY(y()); prefSkel->writeConfig(); } //HACK: I wait a little bit to permit closing the menu // when user clicks on the menu button again TQTimer::singleShot(50, this, SLOT(hide())); emit(hidden()); } void MenuHandler::popup(TQPoint pos) { if(isVisible()) { close(); return; } menu->searchLine->setFocus(); int w; int h; if( !_isNormalWindow ) { TQRect r = TQDesktopWidget().screenGeometry(this); w = (int)(r.width()/_menuWidth); h = (int)(r.height()/_menuHeight); } else { w = prefSkel->normalWindowWidth(); h = prefSkel->normalWindowHeight(); } //the only way to make things proportioned menu->leftFrame->setMaximumWidth( (int)((w-24)/3) ); menu->allAppsFrame->setMaximumHeight(menu->clearButton->height()); if( !_isNormalWindow ) move(pos); else move(prefSkel->normalWindowX(), prefSkel->normalWindowY()); resize(w,h); show(); } void MenuHandler::initOldInstalledApps(KServiceGroup::Ptr group) { if( !group || !group->isValid() ) return; //expires at 639000 seconds = 10 days if( !prefSkel->oldInstalledApps().empty() || (time(0) - (uint)prefSkel->oldInstalledAppsAge() < 639000 ) ) return; KServiceGroup::List list = group->entries(true, true, true, false); for (KServiceGroup::List::ConstIterator it = list.begin (); it != list.end (); it++) { KSycocaEntry *p = (*it); if( p->isType( KST_KServiceGroup ) ) { KServiceGroup *g = static_cast < KServiceGroup * > ( p ); if( g ->childCount() > 0 ) initOldInstalledApps(g); } else { KService *s = static_cast < KService * >(p); oldInstalledList.append(s->desktopEntryPath()); } } } void MenuHandler::initNewInstalledApps(KServiceGroup::Ptr group) { if( !group || !group->isValid() ) return; if( oldInstalledList.empty() ) return; KServiceGroup::List list = group->entries(true, true, true, false); for (KServiceGroup::List::ConstIterator it = list.begin (); it != list.end (); it++) { KSycocaEntry *p = (*it); if( p->isType( KST_KServiceGroup ) ) { KServiceGroup *g = static_cast < KServiceGroup * > ( p ); if( g ->childCount()>0 ) initNewInstalledApps(g); } else { KService *s = static_cast < KService * > ( p ); TQString path(s->desktopEntryPath()); if( oldInstalledList.findIndex(path) == -1 && newInstalledList.findIndex(path) == -1 ) { newInstalledList.append(path); newInstalledTimeStamps.append(time(0)); oldInstalledList.append(path); } } } } bool MenuHandler::searchNewItems(KServiceGroup::Ptr group) { if( !group || !group->isValid() ) return false; if( newInstalledList.count() <= 0 ) return false; KServiceGroup::List list = group->entries(true, true, true, false); for (KServiceGroup::List::ConstIterator it = list.begin (); it != list.end (); it++) { KSycocaEntry *p = (*it); if( p->isType( KST_KServiceGroup ) ) { KServiceGroup *g = static_cast < KServiceGroup * > ( p ); if( g ->childCount()<=0 ) continue; if(searchNewItems(g)) return true; } else { KService *s = static_cast < KService * >(p); /*kdDebug() << group->relPath() << ": "<< s->desktopEntryPath() <<(( newInstalledList.findIndex(s->desktopEntryPath()) != -1 ) ?" present":" not present")<< endl;*/ if( newInstalledList.findIndex(s->desktopEntryPath()) != -1 ) return true; } } return false; } /*KServiceGroup::List MenuHandler::getServiceGroupList( KServiceGroup *serviceGroup ) { TQString key(serviceGroup->directoryEntryPath()); if( sListMap.contains(key) ) return sListMap[key]; else { KServiceGroup::List list = serviceGroup->entries(true, true, true, false); sListMap[key] = list; return list; } }*/ void MenuHandler::populateList( KServiceGroup *serviceGroup, TastyListView *listView, TastyListViewItem *listItemFather, bool recursive, const TQString & query ) { if( !serviceGroup || !serviceGroup->isValid() ) return; serviceGroup->setShowEmptyMenu(false); //KServiceGroup::List list = serviceGroup->entries(true, true, true, false); KServiceGroup::List list = serviceGroup->entries(true, true, true, false); TastyListViewItem *prevListItem = NULL; for (KServiceGroup::List::ConstIterator it = list.begin (); it != list.end (); it++) { KSycocaEntry *p = (*it); int iconSize; if( listView && listView == menu->rootList || listItemFather && listItemFather->listView() == menu->rootList ) iconSize = _iconSize2; else if( listView && listView == menu->childList || listItemFather && listItemFather->listView() == menu->childList) iconSize = _iconSize3; else iconSize = _iconSize1; if( p->isType( KST_KServiceGroup ) ) { //KServiceGroup::Ptr g (static_cast < KServiceGroup * >(p)); KServiceGroup *g = static_cast < KServiceGroup * > ( p ); if( g ->childCount()<=0 || (g->name().at(0) == '.') ) continue; g->setShowEmptyMenu(false); int numChilds = g->childCount(); //FIXME: useless? if(numChilds == 0) continue; TQPixmap iconPix = iconLoader->loadIcon(g->icon(), TDEIcon::Toolbar,iconSize); if ( iconPix.height () != iconSize) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( iconSize, iconSize); iconPix = TQPixmap (img); } } TastyListViewItem *listItem; if( listView ) listItem = new TastyListViewItem( listView, prevListItem, !g->caption().isEmpty()?g->caption() :g->name().section('/', -2)); else listItem = new TastyListViewItem( listItemFather, prevListItem, !g->caption().isEmpty()?g->caption() :g->name().section('/', -2)); listItem->setPath( g->relPath() ); listItem->setType( TastyListViewItem::ServiceGroup ); //OpenGrup only on menu->rootList if( listView == menu->rootList ) listItem->setActionType( TastyListViewItem::OpenGroup ); else listItem->setActionType( TastyListViewItem::Collapse ); prevListItem = listItem; listItem->setPixmap(0, iconPix); //avoiding to display empty categories or with only one child (very common in SUSE) if( (!_hideOneChild && numChilds > 0) || numChilds > 1 ) { if( listView ) { listView->insertItem( listItem ); if( _currentCategory == listItem->text(0) && listView == menu->rootList ) { listView->setCurrentItem(listItem); listView->setOpenItem(static_cast(listItem)); rootListClicked(listItem, TQPoint(0,0), 0); } if(searchNewItems(g)) listItem->setHighLight(true); } else if(listItemFather) listItemFather->insertItem( listItem ); if( recursive ) populateList( g, NULL, listItem, true, query); //the left column is always open if( listView == menu->dynamicList || (listItemFather && listItemFather->listView()==menu->dynamicList)) listItem->setOpen( true ); else listItem->setOpen( !_alwaysCollapsed ); if( listItem->getActionType() == TastyListViewItem::Expand && listItem->isOpen() ) listItem->setActionType( TastyListViewItem::Collapse ); else if( listItem->getActionType() == TastyListViewItem::Collapse && !listItem->isOpen() ) listItem->setActionType( TastyListViewItem::Expand ); } else if( recursive ) { if( listView ) populateList( g, listView, NULL, true, query); else if(listItemFather) populateList( g, NULL, listItemFather, true, query); delete listItem; } } else //The entry is a Service { KService *s = static_cast < KService * >(p); if( s->name().at(0) == '.' ) continue; const bool isSeparator = s->name() == "separator"; //Name and comment TQString itemName = s->name(); TQString subText= TQString(); if( !isSeparator ) { if( !s->comment().isNull() && !s->comment().isEmpty() ) subText = s->comment(); else if( !s->genericName().isNull() && !s->genericName().isEmpty() ) subText = s->genericName(); } //Have we done a query? (this improves query speed) if( query != NULL && !itemName.contains(query, false) && !subText.contains(query, false) ) continue; TastyListViewItem *listItem; if( isSeparator ) { if( _alphabetical ) continue; if(listView) { listItem = new TastyListViewItem( listView, prevListItem, "separator" ); listView->insertItem( listItem ); } else if(listItemFather) { listItem = new TastyListViewItem( listItemFather, prevListItem, "separator" ); listItemFather->insertItem( listItem ); } else return; prevListItem = listItem; listItem->setSelectable(false); continue; } if( listView ) listItem = new TastyListViewItem( listView, prevListItem, itemName ); else listItem = new TastyListViewItem( listItemFather, prevListItem, itemName ); listItem->setDisplaySubText(_displaySubText); listItem->setPath( serviceGroup->relPath() ); listItem->setDeskopEntryPath( s->desktopEntryPath() ); listItem->setMenuId( s->menuId() ); listItem->setType( TastyListViewItem::Service ); listItem->setActionType( TastyListViewItem::AddBookMark ); listItem->setText(0,itemName); listItem->setSubText(subText); prevListItem = listItem; TQPixmap iconPix = s->pixmap( TDEIcon::Toolbar, iconSize ); if ( iconPix.height () != iconSize) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( iconSize, iconSize); iconPix = TQPixmap (img); } } listItem->setPixmap(0, iconPix); if( listView ) { listView->insertItem( listItem ); } else if(listItemFather) { listItemFather->insertItem( listItem ); } if( newInstalledList.findIndex(s->desktopEntryPath()) != -1 ) listItem->setHighLight(true); } } } void MenuHandler::initializeRecentlyUsed( ) { recentlyUsedMap.clear(); moreUsedList.clear(); kickerConf->reparseConfiguration(); kickerConf->setGroup("menus"); TQStringList recentUsedList = TQStringList::split(',',kickerConf->readEntry("RecentAppsStat")); for (TQStringList::ConstIterator it = recentUsedList.begin(); it != recentUsedList.end(); ++it ) { TQString item = (*it); TQString desktopPath = item.section(' ',2,2); if(desktopPath.isEmpty() || !TQFile::exists(desktopPath)) continue; recentlyUsedMap[-item.section(' ',1,1).toULong()] = desktopPath; moreUsedList.append(desktopPath); } } void MenuHandler::setupDynList( MenuMode mode ) { /*( mode == RecentDocuments || mode == MoreUsed || mode == RecentlyUsed )*/ if( mode != Favourites ) menu->clearRecentButton->show(); else menu->clearRecentButton->hide(); currentMenuMode = mode; menu->dynamicList->setAcceptDrops( mode == Favourites ); } void MenuHandler::fillRecentDocuments( ) { menu->dynamicList->clear(); setupDynList( RecentDocuments ); TQStringList recentDocsList = TDERecentDocument::recentDocuments(); TastyListViewItem *listItem = NULL; if( recentDocsList.isEmpty() ) return; for (TQStringList::Iterator it = recentDocsList.begin(); it != recentDocsList.end(); ++it ) { KDesktopFile *f= new KDesktopFile(*it, true /* read only */); if( !f ) continue; listItem = new TastyListViewItem( menu->dynamicList, listItem, f->readName() ); listItem->setMultiLinesEnabled(false); listItem->setDeskopEntryPath(*it); listItem->setType( TastyListViewItem::DesktopFile ); TQPixmap iconPix = iconLoader->loadIcon(f->readIcon(), TDEIcon::Panel, _iconSize1); if ( iconPix.height () > _iconSize1) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( _iconSize1, _iconSize1); iconPix = TQPixmap (img); } } listItem->setPixmap(0, iconPix); menu->dynamicList->insertItem( listItem ); } } void MenuHandler::fillMoreUsed( ) { menu->dynamicList->clear(); setupDynList( MoreUsed ); int iteration = 0; TastyListViewItem *listItem = NULL; for (TQStringList::Iterator it = moreUsedList.begin(); it != moreUsedList.end(); ++it ) { //FIXME: yeah, I know, this is U G L Y :-) if( iteration++ >= _numRecentEntries ) break; KService::Ptr s = KService::serviceByDesktopPath(*it); if( !s ) continue; listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name()); listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() ); listItem->setDeskopEntryPath( s->desktopEntryPath() ); listItem->setType( TastyListViewItem::Service ); listItem->setActionType( TastyListViewItem::AddBookMark ); listItem->setDisplaySubText(_displaySubText); TQPixmap iconPix = s->pixmap( TDEIcon::Toolbar, _iconSize1 ); if( !iconPix.isNull() ) { if ( iconPix.height () != _iconSize1) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( _iconSize1, _iconSize1); iconPix = TQPixmap (img); } } listItem->setPixmap(0, iconPix); } menu->dynamicList->insertItem( listItem ); } } //FIXME: avoid the ugly code duplication void MenuHandler::fillRecentlyUsed( ) { menu->dynamicList->clear(); setupDynList( RecentlyUsed ); int iteration = 0; TastyListViewItem *listItem = NULL; for (RecentlyUsedMap::Iterator it = recentlyUsedMap.begin(); it != recentlyUsedMap.end(); ++it ) { //FIXME: yeah, I know, this is U G L Y :-) if( iteration++ >= _numRecentEntries ) break; KService::Ptr s = KService::serviceByDesktopPath(it.data()); if( !s ) continue; listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name()); listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() ); listItem->setDeskopEntryPath( s->desktopEntryPath() ); listItem->setType( TastyListViewItem::Service ); listItem->setActionType( TastyListViewItem::AddBookMark ); listItem->setDisplaySubText(_displaySubText); TQPixmap iconPix = s->pixmap( TDEIcon::Toolbar, _iconSize1 ); if( !iconPix.isNull() ) { if ( iconPix.height () != _iconSize1) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( _iconSize1, _iconSize1); iconPix = TQPixmap (img); } } listItem->setPixmap(0, iconPix); } menu->dynamicList->insertItem( listItem ); } } //FIXME: avoid the ugly code duplication void MenuHandler::fillFavourites( ) { menu->dynamicList->clear(); setupDynList( Favourites ); TastyListViewItem *listItem = NULL; for (TQStringList::Iterator it = favouriteList.begin(); it != favouriteList.end(); ++it ) { KService::Ptr s = KService::serviceByDesktopPath(*it); if( !s ) continue; listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name()); listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() ); listItem->setDeskopEntryPath( s->desktopEntryPath() ); listItem->setType( TastyListViewItem::Service ); listItem->setActionType( TastyListViewItem::RemoveBookMark ); listItem->setDisplaySubText(_displaySubText); TQPixmap iconPix = s->pixmap( TDEIcon::Toolbar, _iconSize1 ); if ( iconPix.height () > _iconSize1) { TQImage img = iconPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( _iconSize1, _iconSize1); iconPix = TQPixmap (img); } } listItem->setPixmap(0, iconPix); menu->dynamicList->insertItem( listItem ); } } void MenuHandler::slotModKickerConf() { kickerConf->reparseConfiguration(); initializeRecentlyUsed( ); if( currentMenuMode == MoreUsed ) fillMoreUsed(); else if( currentMenuMode == RecentlyUsed ) fillRecentlyUsed(); } void MenuHandler::slotApplicationsAdded(const KFileItemList & newItems) { if( firstListing > 0 ) { firstListing--; return; } //avoiding to build a mammoth list... if( newItems.count() > 15 ) return; for(KFileItemListIterator it(newItems); it.current(); ++it) { KFileItem *item = (*it); TQString path(item->url().path()); kdDebug() << "new item: " << item->name() << endl; //ignore items already here if( oldInstalledList.findIndex(path) == -1 ) { newInstalledList.append(path); newInstalledTimeStamps.append( time(0) ); oldInstalledList.append(path); } } prefSkel->setNewInstalledApps( newInstalledList ); prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps ); prefSkel->setOldInstalledApps( oldInstalledList ); emit(newApplications(newInstalledList.count())); //It's necessary to wait some seconds, otherwise apps won't be listed //I do it two times for being sure, because I still haven't the clear idea //where the right files to watch are... TQTimer::singleShot(15000, this, SLOT(slotUpdateApplications())); } void MenuHandler::slotApplicationRemoved() { TQTimer::singleShot(15000, this, SLOT(slotUpdateApplications())); slotUpdateApplications(); } void MenuHandler::slotUpdateApplications() { KRun::runCommand ("tdebuildsycoca"); prefSkel->writeConfig(); menu->rootList->clear(); KServiceGroup::Ptr service = KServiceGroup::root(); populateList( service, menu->rootList, NULL, false ); } void MenuHandler::listClicked( TastyListViewItem * listItem, const TQPoint & coord ) { if( !listItem ) return; //exit if the user clicked on an empty area if( coord.y() != 0 && (listItem->itemPos( )+ listItem->height()) < coord.y() ) return; int x = coord.x(); TQString servicePath = listItem->getDeskopEntryPath(); switch( listItem->getType() ) { case TastyListViewItem::Service: { //These paranoid checks seems to be needed if( !listItem->listView() ) return; TastyListView *lv = dynamic_cast(listItem->listView()); if( !lv ) return; if( x >= (lv->visibleWidth() - lv->getActionIconSpace()) ) { switch( listItem->getActionType() ) { case TastyListViewItem::AddBookMark: favouriteList.remove(servicePath); favouriteList.append(servicePath); prefSkel->setFavouriteApps(favouriteList); prefSkel->writeConfig(); if( menu->menuModes->currentItem() == 0 ) fillFavourites( ); return; case TastyListViewItem::RemoveBookMark: favouriteList.remove(servicePath); prefSkel->setFavouriteApps(favouriteList); prefSkel->writeConfig(); if( menu->menuModes->currentItem() == 0 ) fillFavourites( ); return; default: break; } } //if the item was highlighted get it back to normal and remove it from recently installed listItem->setHighLight(false); int index=newInstalledList.findIndex(servicePath); if( index != -1 ) { newInstalledList.remove(newInstalledList.at(index)); newInstalledTimeStamps.remove(newInstalledTimeStamps.at(index)); prefSkel->setNewInstalledApps( newInstalledList ); prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps ); emit(newApplications(newInstalledList.count())); //remove the highlight from the rootList, at the moment very costly slotUpdateApplications(); } int started = TDEApplication::startServiceByDesktopPath( servicePath ); if( !started ) { DCOPRef kickerKMenuIface ("kicker", "KMenu"); kickerKMenuIface.call("slotServiceStartedByStorageId(TQString,TQString)", "tastymenu", servicePath); if( (currentMenuMode == MoreUsed || currentMenuMode == RecentlyUsed) && !searchMode) slotModKickerConf(); if( !_isNormalWindow ) close(); } break; } case TastyListViewItem::ServiceGroup: { //open, collapse or expand? switch( listItem->getActionType() ) { case TastyListViewItem::Expand: //avoiding setOpen when the user clicks on the three handle if( !listItem->xOnDecoration(x) ) listItem->setOpen(true); if(listItem->isOpen()) listItem->setActionType( TastyListViewItem::Collapse ); break; case TastyListViewItem::Collapse: if( !listItem->xOnDecoration(x) ) listItem->setOpen(false); if(!listItem->isOpen()) listItem->setActionType( TastyListViewItem::Expand ); break; case TastyListViewItem::OpenGroup: default: { KServiceGroup::Ptr serviceGroup = KServiceGroup::group( listItem->getPath() ); if( serviceGroup ) { menu->childList->clear(); populateList( serviceGroup, menu->childList, NULL, true ); } break; } } break; } case TastyListViewItem::DesktopFile: { KDEDesktopMimeType::run(servicePath, true); if( !_isNormalWindow ) close(); break; } default: return; } } void MenuHandler::dynListClicked( TQListViewItem * listItem, const TQPoint & coord, int c ) { c=c; if( !listItem ) return; TastyListViewItem *tastyListItem = dynamic_cast(listItem); if( !tastyListItem ) return; listClicked( static_cast(listItem), coord ); } void MenuHandler::childListClicked( TQListViewItem * listItem, const TQPoint & coord, int c ) { c=c; if( !listItem ) return; TastyListViewItem *tastyListItem = dynamic_cast(listItem); if( !tastyListItem ) return; /*if( _showExpander && (tastyListItem->getType() == TastyListViewItem::ServiceGroup) ) { //FIXME: get the REAL size of the expander if( coord.x() > 16 ) listItem->setOpen( !listItem->isOpen() ); } else*/ listClicked( static_cast(listItem), coord ); } void MenuHandler::rootListClicked( TQListViewItem * listItem, const TQPoint & coord, int c ) { c=c; if( !listItem ) return; TastyListViewItem *tastyListItem = dynamic_cast(listItem); if( !tastyListItem ) return; //don't reload when the current category is clicked (except for the first run) if( menu->childList->childCount() > 0 && prefSkel->currentCategory( ) == tastyListItem->text(0) ) return; if( tastyListItem->getType() == TastyListViewItem::ServiceGroup ) { prefSkel->setCurrentCategory( tastyListItem->text(0) ); prefSkel->writeConfig(); } listClicked( tastyListItem, coord ); if( _alphabetical ) menu->childList->setSorting(0); } void MenuHandler::slotContextMenu(TQListViewItem *listItem, const TQPoint &coord, int c) { if( !listItem ) return; TastyListViewItem *tastyListItem = dynamic_cast(listItem); if( !tastyListItem ) return; TDEPopupMenu menu(this); menu.insertTitle(tastyListItem->text(c)); if( tastyListItem->getPath() != "" ) { if( tastyListItem->getType() == TastyListViewItem::ServiceGroup ) menu.insertItem(SmallIcon("kmenuedit"), i18n("&Edit submenu..."), 1); else if( tastyListItem->getType() == TastyListViewItem::Service ) { menu.insertItem(SmallIcon("kmenuedit"), i18n("&Edit item..."), 1); menu.insertItem(SmallIcon("desktop"), i18n("&Add to desktop"), 3); } } if( tastyListItem->getActionType() == TastyListViewItem::AddBookMark ) menu.insertItem(SmallIcon("bookmark_add"), i18n("&Add to favourite applications"), 2); else if( tastyListItem->getActionType() == TastyListViewItem::RemoveBookMark ) menu.insertItem(SmallIcon("remove"), i18n("&Remove from favourite applications"), 2); int choice; if( menu.count() > 1 ) choice = menu.exec(coord); else return; switch( choice ) { case 1: KRun::runCommand ("kmenuedit /" + tastyListItem->getPath() + " " + tastyListItem->getMenuId()); if( !_isNormalWindow ) close(); break; case 2: listClicked( tastyListItem, TQPoint(tastyListItem->listView()->width(), 0) ); break; case 3: KRun::runCommand( "cp " + tastyListItem->getDeskopEntryPath() + " ~/Desktop" ); break; default: break; } } void MenuHandler::doLogout() { close(); DCOPRef kdesktopKDesktopIface ("kdesktop", "KDesktopIface"); kdesktopKDesktopIface.call ("logout()"); } void MenuHandler::doLock() { hide(); DCOPRef kdesktopKScreensaverIface ("kdesktop", "KScreensaverIface"); kdesktopKScreensaverIface.call ("lock()"); close(); } void MenuHandler::runDialog() { close(); DCOPRef kdesktopKDesktopIface ("kdesktop", "KDesktopIface"); kdesktopKDesktopIface.call ("popupExecuteCommand()"); } /*Following functions are from official KDE KMenu, Copyright 1996-2006 the kicker authors*/ void MenuHandler::slotPopulateSessions() { int p = 0; DM dm; sessionsMenu->clear(); sessionsMenu->insertItem(SmallIconSet("preferences-desktop-personal"), i18n("Edit user profile..."), 100 ); sessionsMenu->insertSeparator(); //optional save/restore session entries if(prefSkel->showSaveSession()) { sessionsMenu->insertItem( i18n("Save current session"), 101 ); } if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0) { if( kapp->authorize("lock_screen") ) sessionsMenu->insertItem( i18n("Lock session and start a new one"), 102 ); sessionsMenu->insertItem(SmallIconSet("fork"), i18n("Start New Session"), 103 ); if (!p) { sessionsMenu->setItemEnabled( 101, false ); sessionsMenu->setItemEnabled( 102, false ); } sessionsMenu->insertSeparator(); } SessList sess; if (dm.localSessions( sess )) for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { int id = sessionsMenu->insertItem( DM::sess2Str( *it ), (*it).vt ); if (!(*it).vt) sessionsMenu->setItemEnabled( id, false ); if ((*it).self) sessionsMenu->setItemChecked( id, true ); } } void MenuHandler::slotSessionActivated( int ent ) { close(); switch(ent) { case 100: close(); KRun::runCommand ("tdecmshell kcm_useraccount"); break; case 101: { close(); DCOPRef ksmserverKsmserver ("ksmserver", "ksmserver"); ksmserverKsmserver.call ("saveCurrentSession()"); break; } case 102: doNewSession( true ); break; case 103: doNewSession( false ); break; } //switch on an other session if (!sessionsMenu->isItemChecked( ent )) DM().lockSwitchVT( ent ); } void MenuHandler::doNewSession( bool lock ) { int result = KMessageBox::warningContinueCancel( kapp->desktop()->screen(kapp->desktop()->screenNumber(menu)), i18n("

You have chosen to open another desktop session.
" "The current session will be hidden " "and a new login screen will be displayed.
" "An F-key is assigned to each session; " "F%1 is usually assigned to the first session, " "F%2 to the second session and so on. " "You can switch between sessions by pressing " "Ctrl, Alt and the appropriate F-key at the same time. " "Additionally, the TDE Panel and Desktop menus have " "actions for switching between sessions.

") .arg(7).arg(8), i18n("Warning - New Session"), KGuiItem(i18n("&Start New Session"), "fork"), ":confirmNewSession", KMessageBox::PlainCaption | KMessageBox::Notify); if (result==KMessageBox::Cancel) return; if (lock) doLock(); DM().startReserve(); } void MenuHandler::initializeSearch( const TQString & query ) { if( !searchMode && query.length() > 2 ) { if( !menu->searchLine->listView() ) menu->searchLine->setListView((TDEListView *)(menu->dynamicList)); searchMode = true; menu->menuModes->setEnabled(false); KServiceGroup::Ptr service = KServiceGroup::root(); menu->dynamicList->clear(); setCursor(TQCursor(TQt::BusyCursor)); populateList( service, menu->dynamicList, NULL, true, query ); setCursor(TQCursor(TQt::ArrowCursor)); } else if( query.length() < 3 ) { if( menu->searchLine->listView() ) { menu->searchLine->setListView(NULL); menu->searchLine->setEnabled(true); menu->searchLine->setFocus(); menu->searchLine->setContextMenuEnabled(false); } searchMode = false; menu->menuModes->setEnabled(true); menu->dynamicList->clear(); menuModeChanged(_menuMode); } } void MenuHandler::strigiSearch( const TQString & query ) { close(); KRun::runCommand ("konqueror strigi:/?q="+query); } void MenuHandler::clearDynList( ) { menu->dynamicList->clear(); switch( currentMenuMode ) { case MoreUsed: case RecentlyUsed: { DCOPRef kickerKMenuIface ("kicker", "kicker"); kickerKMenuIface.call("clearQuickStartMenu()"); slotModKickerConf(); break; } case RecentDocuments: TDERecentDocument::clear(); break; default: break; } } void MenuHandler::menuModeChanged( int index ) { _menuMode = index; prefSkel->setMenuMode(_menuMode); switch(index) { case Favourites: fillFavourites(); break; case MoreUsed: fillMoreUsed(); break; case RecentlyUsed: fillRecentlyUsed(); break; case RecentDocuments: fillRecentDocuments(); break; default: break; } } void MenuHandler::switchWindowMode() { if( !_isNormalWindow /*testWFlags(TQt::WType_Popup)*/ ) { _isNormalWindow = true; hide(); reparent(static_cast(parent()),TQt::WType_Dialog, pos(), true); menu->detachButton->setIconSet(TQPixmap(uic_findImage("attach.png"))); prefSkel->setIsNormalWindow(true); } else { hide(); reparent(static_cast(parent()), TQt::WType_Popup|TQt::WNoAutoErase, pos(), true); menu->detachButton->setIconSet(TQPixmap(uic_findImage("detach.png"))); prefSkel->setIsNormalWindow(false); _isNormalWindow = false; } prefSkel->writeConfig(); } #include "menuhandler.moc" //EOF