From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kicker/applets/launcher/ChangeLog | 40 + kicker/applets/launcher/Makefile.am | 27 + kicker/applets/launcher/ToDo | 8 + kicker/applets/launcher/configdlg.cpp | 101 +++ kicker/applets/launcher/configdlg.h | 55 ++ kicker/applets/launcher/configdlgbase.ui | 273 ++++++ kicker/applets/launcher/easyvector.h | 147 ++++ kicker/applets/launcher/flowgridmanager.cpp | 316 +++++++ kicker/applets/launcher/flowgridmanager.h | 99 +++ kicker/applets/launcher/launcherapplet.kcfg | 77 ++ kicker/applets/launcher/popularity.cpp | 424 ++++++++++ kicker/applets/launcher/popularity.h | 127 +++ kicker/applets/launcher/prefs.kcfgc | 6 + kicker/applets/launcher/quickaddappsmenu.cpp | 67 ++ kicker/applets/launcher/quickaddappsmenu.h | 51 ++ kicker/applets/launcher/quickbutton.cpp | 322 ++++++++ kicker/applets/launcher/quickbutton.h | 124 +++ kicker/applets/launcher/quickbuttongroup.h | 60 ++ kicker/applets/launcher/quicklauncher.cpp | 1093 +++++++++++++++++++++++++ kicker/applets/launcher/quicklauncher.desktop | 140 ++++ kicker/applets/launcher/quicklauncher.h | 138 ++++ 21 files changed, 3695 insertions(+) create mode 100644 kicker/applets/launcher/ChangeLog create mode 100644 kicker/applets/launcher/Makefile.am create mode 100644 kicker/applets/launcher/ToDo create mode 100644 kicker/applets/launcher/configdlg.cpp create mode 100644 kicker/applets/launcher/configdlg.h create mode 100644 kicker/applets/launcher/configdlgbase.ui create mode 100644 kicker/applets/launcher/easyvector.h create mode 100644 kicker/applets/launcher/flowgridmanager.cpp create mode 100644 kicker/applets/launcher/flowgridmanager.h create mode 100644 kicker/applets/launcher/launcherapplet.kcfg create mode 100644 kicker/applets/launcher/popularity.cpp create mode 100644 kicker/applets/launcher/popularity.h create mode 100644 kicker/applets/launcher/prefs.kcfgc create mode 100644 kicker/applets/launcher/quickaddappsmenu.cpp create mode 100644 kicker/applets/launcher/quickaddappsmenu.h create mode 100644 kicker/applets/launcher/quickbutton.cpp create mode 100644 kicker/applets/launcher/quickbutton.h create mode 100644 kicker/applets/launcher/quickbuttongroup.h create mode 100644 kicker/applets/launcher/quicklauncher.cpp create mode 100644 kicker/applets/launcher/quicklauncher.desktop create mode 100644 kicker/applets/launcher/quicklauncher.h (limited to 'kicker/applets/launcher') diff --git a/kicker/applets/launcher/ChangeLog b/kicker/applets/launcher/ChangeLog new file mode 100644 index 000000000..b86dbd7aa --- /dev/null +++ b/kicker/applets/launcher/ChangeLog @@ -0,0 +1,40 @@ +2004-06-15 Dan Bullok + * Fixed flicker on drop/arrange. + * Can now drop more than one item at a time + * Empty panel now has size>0, so user can still drop icons on it. + * Fixed gcc 3.4 incompatibilities in EasyVector + * Fixed Drag and Drop Bugs : + * Crash when non-url dropped on quicklauncher + * Crash panel button dropped on quicklauncher + * Able to drop objects when quicklauncher is locked + * Add application context menu now inserts new app at current location + +2004-06-14 Dan Bullok + * Fixed License statements (added email & pointer to COPYING) + * GUI changes made in previous commit. + * continued separating QuickURL and QuickButton. + * Rearranged menu items to make more sense + +2004-06-13 Dan Bullok + * Fixes Bugs #42278, #55625, #63506, #67891, #76868, #79848, #80530 - also makes bacon & eggs for breakfast (toast & jam available for vegetarians) + * v2.0alpha + * Replaced most of the innards of QuickLauncher class. + * Icons are positions evenly across available space. + * Drag and drop works for all kicker widths. + * Visual Feedback of drop location + * Icon Size is user-definable. Sensible(?) values are used by default (Icons grow slightly as panel size increases. #icons per row for given panel size is Tiny,Small: 1, Normal: 2, Large:3, 110pix: 4). + * User can lock icon drag and drop (prevents accidentally screwing things up). + * Icons can either take up exactly the defined amount of space (ConserveSpace=true - this is the default), or grow slightly to take advantage of unused space. + * Spouts tons of debugging info to kdDebug (for now). + +2004-06-12 Dan Bullok + * Fixed bug #75351: Tooltips change to filenames after rearranging applications in quicklauncher. + * Moved the URL->(menuID,service,kurl) functionality from the QuickButton constructor to its own class: QuickURL. Very similar code is used elsewhere in kicker, and should eventually be merged. + * Renamed some methods in QuickButton (getId -> menuId, getURL -> url) This matches the predominant KDE naming style. + * Groundwork laid for variable-sized buttons. + +2004-06-12 Dan Bullok + * Changed member variable names: myVar -> _myVar. + +2004-06-12 Dan Bullok + * Fixed formatting only - no code changes. There were a few conflicting indenting styles. I picked the one that looked like it was the oldest, and applied it to all the files. diff --git a/kicker/applets/launcher/Makefile.am b/kicker/applets/launcher/Makefile.am new file mode 100644 index 000000000..a101c6ccf --- /dev/null +++ b/kicker/applets/launcher/Makefile.am @@ -0,0 +1,27 @@ + +INCLUDES = -I$(top_srcdir)/kicker/libkicker -I$(top_srcdir)/kicker/kicker/ui $(all_includes) + +kde_module_LTLIBRARIES = launcher_panelapplet.la + +launcher_panelapplet_la_SOURCES = quicklauncher.skel quicklauncher.cpp quickbutton.cpp quickaddappsmenu.cpp flowgridmanager.cpp popularity.cpp configdlgbase.ui prefs.kcfgc configdlg.cpp + +METASOURCES = AUTO +noinst_HEADERS = quicklauncher.h quickbutton.h quickaddappsmenu.h easyvector.h quickbuttongroup.h flowgridmanager.h popularity.h configdlg.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = quicklauncher.desktop + +EXTRA_DIST = $(lnk_DATA) + +launcher_panelapplet_la_LDFLAGS = -module $(KDE_RPATH) $(all_libraries) -avoid-version -no-undefined +launcher_panelapplet_la_LIBADD = ../../kicker/core/libkicker_core.la ../../kicker/buttons/libkicker_buttons.la \ + ../../kicker/ui/libkicker_ui.la ../../libkicker/libkickermain.la $(LIB_KIO) \ + $(LIB_KSYCOCA) $(LIB_KDEUI) $(LIB_KUTILS) + +kde_kcfg_DATA = launcherapplet.kcfg + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/quicklauncher.pot + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/quicklauncher quicklauncher *.h -lqt -lkdecore -lkdeui diff --git a/kicker/applets/launcher/ToDo b/kicker/applets/launcher/ToDo new file mode 100644 index 000000000..c7c852a36 --- /dev/null +++ b/kicker/applets/launcher/ToDo @@ -0,0 +1,8 @@ +TODO: + X * Geometry isn't always updated when panel size changes. + x * Remove debugging code (makes everything slow). + * Tooltip or other popup to alert user that buttons are locked (with a "don't show this again" checkbox). + * Docs. + * Use old quicklauncher config file if found. #77959 + X * "Add application" context menu should add the new application at the index of the button that summoned the context menu. + X * Make sure to always have a little space to drop things on, even when there are no buttons. diff --git a/kicker/applets/launcher/configdlg.cpp b/kicker/applets/launcher/configdlg.cpp new file mode 100644 index 000000000..9950dd2a9 --- /dev/null +++ b/kicker/applets/launcher/configdlg.cpp @@ -0,0 +1,101 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen + +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 "prefs.h" +#include "configdlg.h" +#include "configdlgbase.h" + +ConfigDlg::ConfigDlg(QWidget *parent, const char *name, Prefs *config, + int autoSize, KConfigDialog::DialogType dialogType, + int dialogButtons) : + KConfigDialog(parent, name, config, dialogType, dialogButtons), + m_settings(config), + m_autoSize(autoSize) +{ + m_ui = new ConfigDlgBase(this->plainPage()); + addPage(m_ui, i18n("Configure"), "config"); + + m_ui->iconDim->clear(); + m_ui->iconDim->insertItem(i18n("Automatic")); + for (int n=0; niconDimChoices().size()); ++n) + { + m_ui->iconDim->insertItem(QString::number( + m_settings->iconDimChoices()[n])); + } + connect(m_ui->iconDim, SIGNAL(textChanged(const QString&)), + this, SLOT(updateButtons())); + updateWidgets(); + m_oldIconDimText = m_ui->iconDim->currentText(); + updateButtons(); +} + +void ConfigDlg::updateSettings() +{ + kdDebug() << "updateSettings" << endl; + KConfigDialog::updateSettings(); + if (!hasChanged()) + { + return; + } + m_oldIconDimText = m_ui->iconDim->currentText(); + if (m_ui->iconDim->currentText() == i18n("Automatic")) + { + m_settings->setIconDim(m_autoSize); + } + else + { + m_settings->setIconDim(m_ui->iconDim->currentText().toInt()); + } + settingsChangedSlot(); +} + +void ConfigDlg::updateWidgets() +{ + KConfigDialog::updateWidgets(); + if (m_settings->iconDim() == m_autoSize) + { + m_ui->iconDim->setEditText(i18n("Automatic")); + } + else + { + m_ui->iconDim->setEditText(QString::number(m_settings->iconDim())); + } +} + +void ConfigDlg::updateWidgetsDefault() +{ + KConfigDialog::updateWidgetsDefault(); +} + +bool ConfigDlg::hasChanged() +{ + return m_oldIconDimText != m_ui->iconDim->currentText() || + KConfigDialog::hasChanged(); +} + +#include "configdlg.moc" diff --git a/kicker/applets/launcher/configdlg.h b/kicker/applets/launcher/configdlg.h new file mode 100644 index 000000000..1d03a9381 --- /dev/null +++ b/kicker/applets/launcher/configdlg.h @@ -0,0 +1,55 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen + +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. + +******************************************************************/ + +#ifndef CONFIG_DLG_H +#define CONFIG_DLG_H + +#include + +class ConfigDlgBase; +class Prefs; + +class ConfigDlg : public KConfigDialog +{ + Q_OBJECT + +public: + ConfigDlg(QWidget *parent, const char *name, Prefs *config, int autoSize, + KConfigDialog::DialogType dialogType, int dialogButtons); + +protected: + virtual bool hasChanged(); + +protected slots: + virtual void updateSettings(); + virtual void updateWidgets(); + virtual void updateWidgetsDefault(); + +private: + ConfigDlgBase *m_ui; + Prefs* m_settings; + int m_autoSize; + QString m_oldIconDimText; +}; + +#endif diff --git a/kicker/applets/launcher/configdlgbase.ui b/kicker/applets/launcher/configdlgbase.ui new file mode 100644 index 000000000..bfb1bc4e6 --- /dev/null +++ b/kicker/applets/launcher/configdlgbase.ui @@ -0,0 +1,273 @@ + +ConfigDlgBase + + + ConfigDlgBase + + + + 0 + 0 + 371 + 338 + + + + + unnamed + + + 0 + + + + kcfg_DragEnabled + + + Allow drag and drop + + + + + groupBox2 + + + Layout + + + + unnamed + + + + kcfg_ConserveSpace + + + Conserve space + + + Do not expand icons to the size of the panel + + + + + textLabel1_2 + + + Icon size: + + + + + iconDim + + + true + + + + + spacer4_2 + + + Horizontal + + + Expanding + + + + 332 + 20 + + + + + + + + autoAdjustGroup + + + Most Popular Applications + + + + unnamed + + + + layout1 + + + + unnamed + + + + kcfg_HistoryHorizon + + + 100 + + + 0 + + + 10 + + + Horizontal + + + + + spacer7 + + + Horizontal + + + Expanding + + + + 140 + 20 + + + + + + textLabel1 + + + Short Term + + + AlignCenter + + + + + textLabel2 + + + Long Term + + + AlignCenter + + + + + + + textLabel3 + + + Maximum number of applications: + + + + + kcfg_AutoAdjustMinItems + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 50 + 20 + + + + + + kcfg_AutoAdjustMaxItems + + + + + textLabel3_2 + + + Minimum number of applications: + + + + + kcfg_AutoAdjustEnabled + + + Add/remove applications based on their popularity + + + true + + + + + + + + + + + kcfg_AutoAdjustEnabled + toggled(bool) + kcfg_AutoAdjustMinItems + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + kcfg_AutoAdjustMaxItems + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + kcfg_HistoryHorizon + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + textLabel1 + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + textLabel2 + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + textLabel3 + setEnabled(bool) + + + kcfg_AutoAdjustEnabled + toggled(bool) + textLabel3_2 + setEnabled(bool) + + + + + knuminput.h + knuminput.h + + diff --git a/kicker/applets/launcher/easyvector.h b/kicker/applets/launcher/easyvector.h new file mode 100644 index 000000000..cad9a2c86 --- /dev/null +++ b/kicker/applets/launcher/easyvector.h @@ -0,0 +1,147 @@ +/* Copyright 2004, Daniel Woods Bullok + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#ifndef __easyvector_h__ +#define __easyvector_h__ +#include +#include +#include + +template < class VALUE > +class __Valtype { +public: + typedef const VALUE& CVALUE; +}; + + +template < class VALUE > +class __Valtype< VALUE* > { +public: + typedef const VALUE* CVALUE; +}; + + +template +class EasyVector: public std::vector< VALUE > { +public: + typedef int Index; + typedef std::vector< Index > Indices; + typedef typename __Valtype< VALUE >::CVALUE CVALUE; + + static const Index NotFound=-2; + static const Index Append=-1; + + template < class PTYPE, class PROP_FUNC > + Index findProperty(const PTYPE &property, + PROP_FUNC prop_func) const; + Index findValue(CVALUE value) const; + + Index lastIndex() const {return this->size()-1;} + + void eraseAt(Index index); + + VALUE takeFrom(Index index); + + void insertAt(Index index,const VALUE &value); + void insertAt(Index index,const EasyVector &values); + + bool isValidIndex(Index index) const; + bool isValidInsertIndex(Index index) const; + virtual ~EasyVector(){}; + + +protected: + void _checkInsertIndex(Index index) const; + void _checkIndex(Index index) const; + Index _convertInsertIndex(Index index) const; +}; + + +template < class VALUE, bool CHECKINDEX > +template < class PTYPE, class PROP_FUNC > +typename EasyVector< VALUE, CHECKINDEX >::Index + EasyVector< VALUE, CHECKINDEX >::findProperty(const PTYPE &property, + PROP_FUNC prop_func) const +{ typename EasyVector< VALUE, CHECKINDEX >::const_iterator i; + for (i=this->begin();i!=this->end();++i) { + if (prop_func(*i)==property) + return i-this->begin(); + } + return NotFound; +} + + +template < class VALUE, bool CHECKINDEX > +typename EasyVector< VALUE, CHECKINDEX >::Index + EasyVector< VALUE, CHECKINDEX >::findValue(CVALUE value) const +{ typename EasyVector< VALUE, CHECKINDEX >::const_iterator i; + i=std::find(this->begin(),this->end(),value); + if (i==this->end()) return NotFound; + return i-this->begin(); +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::eraseAt(Index index) +{ _checkIndex(index); + erase(this->begin()+index); +} + + +template < class VALUE, bool CHECKINDEX > +VALUE EasyVector< VALUE, CHECKINDEX >::takeFrom(Index index) +{ _checkIndex(index); + VALUE result=(*this)[index]; + eraseAt(index); + return result; +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::insertAt(EasyVector< VALUE, CHECKINDEX >::Index index,const VALUE &value) +{ index=_convertInsertIndex(index); + _checkInsertIndex(index); + if (index==int(this->size())) { + this->push_back(value); + return; + } + insert(this->begin()+index,value); +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::insertAt(EasyVector< VALUE, CHECKINDEX >::Index index,const EasyVector< VALUE, CHECKINDEX > &v) +{ index=_convertInsertIndex(index); + _checkInsertIndex(index); + insert(this->begin()+index,v.begin(),v.end()); +} + + +template < class VALUE, bool CHECKINDEX > +bool EasyVector< VALUE, CHECKINDEX >::isValidIndex(EasyVector< VALUE, CHECKINDEX >::Index index) const +{ return(0<=index && indexsize()));} + +template < class VALUE, bool CHECKINDEX > +bool EasyVector< VALUE, CHECKINDEX >::isValidInsertIndex(EasyVector< VALUE, CHECKINDEX >::Index index) const +{ return(index==Append)||(0<=index && index<=int(this->size()));} + +template < class VALUE, bool CHECKINDEX > +inline typename EasyVector< VALUE, CHECKINDEX >::Index EasyVector< VALUE, CHECKINDEX >::_convertInsertIndex(Index index) const +{ if (index==Append) return this->size(); + return index; +} + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::_checkInsertIndex(Index index) const +{ if (CHECKINDEX) assert (isValidInsertIndex(index));} + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::_checkIndex(Index index) const +{ if (CHECKINDEX) assert (isValidIndex(index));} + + +#endif + diff --git a/kicker/applets/launcher/flowgridmanager.cpp b/kicker/applets/launcher/flowgridmanager.cpp new file mode 100644 index 000000000..b5715097b --- /dev/null +++ b/kicker/applets/launcher/flowgridmanager.cpp @@ -0,0 +1,316 @@ +/* Copyright 2004, Daniel Woods Bullok + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#include "flowgridmanager.h" +#include +#ifdef DEBUG + #define DEBUGSTR kdDebug() +#else + #define DEBUGSTR kndDebug() +#endif + + +FlowGridManager::FlowGridManager(QSize p_item_size, + QSize p_space_size, + QSize p_border_size, + QSize p_frame_size, + Qt::Orientation orient, + int num_items, + Slack slack_x,Slack slack_y) +{ + _pItemSize=p_item_size; + _pSpaceSize=p_space_size; + _pBorderSize=p_border_size; + _pFrameSize=p_frame_size; + _orientation=orient; + _numItems=num_items; + _slackX=slack_x; + _slackY=slack_y; + _conserveSpace=false; + + _dirty=true; + _valid=false; +} + +// set members. +// These all set the _dirty flag if the new value is different. +void FlowGridManager::setNumItems(int num_items) +{ if (_numItems==num_items) + return; + _numItems=num_items; _dirty=true; +} +void FlowGridManager::setItemSize(QSize p_item_size) +{ if (_pItemSize==p_item_size) + return; + _pItemSize=p_item_size; _dirty=true; +} + +void FlowGridManager::setSpaceSize(QSize p_space_size) +{ if (_pSpaceSize==p_space_size) + return; + _pSpaceSize=p_space_size; _dirty=true; +} + +void FlowGridManager::setBorderSize(QSize p_border_size) +{ if (_pBorderSize==p_border_size) + return; + _pBorderSize=p_border_size; _dirty=true; +} + +void FlowGridManager::setFrameSize(QSize p_frame_size) +{ if (_pFrameSize==p_frame_size) + return; + _pFrameSize=p_frame_size; + if (_pFrameSize.width()<=0) { + _orientation=Qt::Vertical; + } + if (_pFrameSize.height()<=0) { + _orientation=Qt::Horizontal; + } + _dirty=true; +} + +void FlowGridManager::setOrientation(Qt::Orientation orient) +{ if (orient==_orientation) + return; + _orientation=orient; _dirty=true; +} + +void FlowGridManager::setSlack(Slack slack_x, Slack slack_y) +{ if (slack_x==_slackX && slack_y==_slackY) return; + _slackX=slack_x; _slackY=slack_y; _dirty=true;} + + +void FlowGridManager::setConserveSpace(bool conserve) +{ if (_conserveSpace==conserve) + return; + _conserveSpace=conserve; _dirty=true; +} + + + +// get members +QSize FlowGridManager::itemSize() const +{ _checkReconfigure(); return _itemSize;} + +QSize FlowGridManager::spaceSize() const +{ _checkReconfigure(); return _spaceSize;} + +QSize FlowGridManager::borderSize() const +{ _checkReconfigure(); return _borderSize;} + +QSize FlowGridManager::gridDim() const +{ _checkReconfigure(); return _gridDim;} + +QSize FlowGridManager::gridSpacing() const +{ _checkReconfigure(); return _gridSpacing;} + +QSize FlowGridManager::frameSize() const +{ _checkReconfigure(); return _frameSize;} + +QPoint FlowGridManager::origin() const +{ _checkReconfigure(); return _origin;} + +Qt::Orientation FlowGridManager::orientation() const +{ _checkReconfigure(); return _orientation;} + +/*Slack FlowGridManager::slackX() const +{ return _slackY;} + +Slack FlowGridManager::slackY() const +{ return _slackY;} +*/ + +bool FlowGridManager::conserveSpace() const +{ return _conserveSpace; } + + +bool FlowGridManager::isValid() const +{ _checkReconfigure(); return _valid;} + +QPoint FlowGridManager::posAtCell(int x,int y) const +{ _checkReconfigure(); + return _origin+QPoint(_gridSpacing.width()*x,_gridSpacing.height()*y); +} + +QPoint FlowGridManager::pos(int i) const +{ return posAtCell(cell(i).x(),cell(i).y()); +} + +QPoint FlowGridManager::cell(int index) const +{ _checkReconfigure(); + //assert((index>=0) && (index<_gridDim.width()*_gridDim.height())); + int x=index % _gridDim.width(), + y=index / _gridDim.width(); + return QPoint(x,y); +} + + + + +// return height if orientation is Horizontal +// return width if orientation is Vertical +int FlowGridManager::_getHH(QSize size) const +{ if (_orientation==Qt::Horizontal) + return size.height(); + return size.width(); +} + +// return height if orientation is Vertical +// return width if orientation is Horizontal +int FlowGridManager::_getWH(QSize size) const +{ if (_orientation==Qt::Horizontal) + return size.width(); + return size.height(); +} + +// swap horizontal and vertical if orientation is Vertical, otherwise return arg +QSize FlowGridManager::_swapHV(QSize hv) const +{ if (_orientation==Qt::Horizontal) + return hv; + QSize temp=hv; + temp.transpose(); + return temp; +} + + +// return the amount of slack when: +// nitems = # of items +// length = total length of space where items will be placed +// item, space, border = length of respective entities +int FlowGridManager::_slack(int nitems,int length,int item,int space,int border) const +{ return length-(2*border)-(nitems-1)*space-nitems*item;} + + +void FlowGridManager::_clear() const +{ + _borderSize=QSize(0,0); + _spaceSize=QSize(0,0); + _itemSize=QSize(0,0); + _gridDim=QSize(0,0); + _gridSpacing=QSize(0,0); + _origin=QPoint(0,0); + _frameSize=QSize(0,0); + + _dirty=false; + _valid=false; +} + + +int FlowGridManager::indexNearest(QPoint p) const +{ if (!isValid()) return -1; + QPoint c=(p-_origin)-QPoint(_spaceSize.width(),_spaceSize.height())/2; + int x=c.x()/_gridSpacing.width(), + y=c.y()/_gridSpacing.height(); + int i= x+y*_gridDim.width(); + if (i>_numItems) return -1; + return i; +} + + + +// Redistribute the boxes +void FlowGridManager::_reconfigure() const +{ if ((!_pFrameSize.isValid()) || + (!_pItemSize.isValid()) || + _numItems==0 ) { + _clear(); + return; + } + int height=_getHH(_pFrameSize), + pItemHeight=_getHH(_pItemSize), + pSpaceHeight=_getHH(_pSpaceSize), + pBorderHeight=_getHH(_pBorderSize), + spanlen=(height-2*pBorderHeight+pSpaceHeight)/(pItemHeight+pSpaceHeight); + int slack,iSlack; + + if (spanlen==0) { + _dirty=false; + _valid=false; + return; + } + // figure out the number of spans required for all items + int numspans=_numItems/spanlen; + if (numspans*spanlen<_numItems) { + numspans++; + } + + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); // total slack + iSlack=slack/spanlen; // slack per item + // Items pick up extra slack + if (_slackX==ItemSlack) pItemHeight+=iSlack; + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); + + // space picks up extra slack + if (spanlen>1) { + iSlack=slack/(spanlen+1); + pSpaceHeight+=iSlack; + } + + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); + iSlack=slack/2; + pBorderHeight+=iSlack; + if (_conserveSpace) { + _itemSize=_swapHV(QSize(_getWH(_pItemSize),pItemHeight)); + _spaceSize=_swapHV(QSize(_getWH(_pSpaceSize),pSpaceHeight)); + _borderSize=_swapHV(QSize(_getWH(_pBorderSize),pBorderHeight)); + } + else { + _itemSize=_swapHV(QSize(pItemHeight,pItemHeight)); + _spaceSize=_swapHV(QSize(pSpaceHeight,pSpaceHeight)); + _borderSize=_swapHV(QSize(pBorderHeight,pBorderHeight)); + } + _gridDim=_swapHV(QSize(numspans,spanlen)); + + _gridSpacing=_itemSize+_spaceSize; + _origin=QPoint(_borderSize.width(),_borderSize.height()); + _frameSize=2*_borderSize+QSize(_gridDim.width()*_gridSpacing.width()-_spaceSize.width(), + _gridDim.height()*_gridSpacing.height()-_spaceSize.height()); + + _dirty=false; + _valid=true; +} + + +void FlowGridManager::dump() +{ + DEBUGSTR< + + + + + + true + + + + true + + + + 0 + + + + 16,20,24,28,32,48,64 + + + + kde-Home.desktop,kde-konsole.desktop,kde-KControl.desktop,kde-Help.desktop,kde-kwrite.desktop + + + + Buttons that can be removed dynamically if they become unpopular + + + + + true + + + + false + + + + 0 + 3 + + + + 0 + 6 + + + + 0 + 100 + 70 + + + + + + Number of services to remember + 500 + + + + Name of known services + + + + Position where services are inserted when they regain popularity + + + + History Data used to determine the popularity of a service + + + diff --git a/kicker/applets/launcher/popularity.cpp b/kicker/applets/launcher/popularity.cpp new file mode 100644 index 000000000..3bfcdd872 --- /dev/null +++ b/kicker/applets/launcher/popularity.cpp @@ -0,0 +1,424 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen + +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 "popularity.h" +#include "prefs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class PopularityStatisticsImpl +{ +public: + struct SingleFalloffHistory + { + public: + // fallof is a number between 0 and 1. The popularity of + // each service is multiplied with the falloff value + // every time a service is used. Only the used service + // gets also 1-falloff added to its popularity. + double falloff; + // popularity values for each service + map vals; + // accumulated popularity of the unknown programs + // started before the statistic started + double iniVal; + }; + + struct Popularity + { + QString service; + double popularity; + bool operator<(const Popularity& p) const + { + return popularity > p.popularity; + } + }; + + PopularityStatisticsImpl(); + void normalizeHistory(SingleFalloffHistory& h); + void updateServiceRanks(); + + vector m_stats; + vector m_servicesByPopularity; + map m_serviceRanks; + double m_historyHorizon; +}; + +// ---- Public methods ---- + +PopularityStatistics::PopularityStatistics() : + d(new PopularityStatisticsImpl()) +{ +} + +PopularityStatistics::~PopularityStatistics() +{ + delete d; +} + +void PopularityStatistics::useService(const QString& service) +{ + vector::iterator + it(d->m_stats.begin()), end(d->m_stats.end()); + for (; it != end; ++it) + { + map::iterator valIt; + bool found(false); + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + valIt->second = valIt->second * it->falloff; + if (valIt->first == service) + { + found = true; + valIt->second += 1-it->falloff; + } + } + it->iniVal = it->iniVal * it->falloff; + if (found == false) + { + it->vals[service] = 1-it->falloff; + } + d->normalizeHistory(*it); + } + d->updateServiceRanks(); +} + +void PopularityStatistics::moveToTop(const QStringList& newTopServiceList) +{ + vector::iterator + histIt(d->m_stats.begin()), histEnd(d->m_stats.end()); + for (; histIt != histEnd; ++histIt) + { + set newTopServices; + for (uint n=0; n ranking; + map::iterator valIt; + for (valIt = histIt->vals.begin(); valIt != histIt->vals.end(); ++valIt) + { + PopularityStatisticsImpl::Popularity pop; + pop.service = valIt->first; + pop.popularity = valIt->second; + ranking.push_back(pop); + } + stable_sort(ranking.begin(), ranking.end()); + + // Get the new positions of each service in the ranking. + // We don't touch the popularity values in the ranking. + list topServiceList, bottomServiceList; + vector:: iterator rankIt; + for (rankIt = ranking.begin(); rankIt != ranking.end(); ++rankIt) + { + if (newTopServices.find(rankIt->service) != newTopServices.end()) + { + topServiceList.push_back(rankIt->service); + //kdDebug() << "top service: " << valIt->first << endl; + newTopServices.erase(rankIt->service); + } + else + { + //kdDebug() << "bottom service: " << valIt->first << endl; + bottomServiceList.push_back(rankIt->service); + } + } + // Append remaining new services to the topServices list + while (newTopServices.size() > 0) + { + topServiceList.push_back(*newTopServices.begin()); + newTopServices.erase(newTopServices.begin()); + } + + list newServiceList; + copy(topServiceList.begin(), topServiceList.end(), + back_insert_iterator >(newServiceList)); + copy(bottomServiceList.begin(), bottomServiceList.end(), + back_insert_iterator >(newServiceList)); + + // Merge the old list of service popularities + // with the new ordering of the services + histIt->vals.clear(); + list::iterator servIt; + uint serviceIndex = 0; + //kdDebug() << endl; + + for (servIt = newServiceList.begin(); servIt != newServiceList.end(); + ++servIt) + { + if (serviceIndex < ranking.size()) + { + histIt->vals[*servIt] = ranking[serviceIndex].popularity; + //kdDebug() << "->Re-Added service " << + //ranking[serviceIndex].popularity + // << " " << *servIt << endl; + //kdDebug() << "...was replaced by " << *servIt << endl; + } + else + { + //kdDebug() << "Service " << *servIt << endl; + //kdDebug() << "...was set to popularity=0" << endl; + histIt->vals[*servIt] = 0.00001; + } + // Make sure that the topServices are actually bigger than + // the bottomServices and not just bigger or equal + // and also that no services have popularity==0 + if (serviceIndex >= topServiceList.size()) + { + histIt->vals[*servIt] *= histIt->falloff; + } + ++serviceIndex; + } + d->normalizeHistory(*histIt); + } + d->updateServiceRanks(); +} + +/*v +Old version - moves everything else one position up +and 'service' to the bottom +void PopularityStatistics::moveToBottom(const QString& service) +{ + // Moves a service to the bottom of the ranking + // by moving everything else to the top + d->updateServiceRanks(); + QStringList allButOneServices; + vector::iterator + it(d->m_servicesByPopularity.begin()), + end(d->m_servicesByPopularity.end()); + for (; it != end; ++it) + { + if (it->service != service) + allButOneServices << it->service; + } + moveToTop(allButOneServices); +}*/ + +void PopularityStatistics::moveToBottom(const QString& service) +{ + vector::iterator + it(d->m_stats.begin()), end(d->m_stats.end()); + for (; it != end; ++it) + { + it->iniVal += it->vals[service]; + it->vals[service] = 0; + d->normalizeHistory(*it); + } + d->updateServiceRanks(); +} + +QString PopularityStatistics::serviceByRank(int n) const +{ + if (n >= 0 && n < int(d->m_servicesByPopularity.size())) + return d->m_servicesByPopularity[n].service; + else + return QString(); +} + +double PopularityStatistics::popularityByRank(int n) const +{ + if (n >= 0 && n < int(d->m_servicesByPopularity.size())) + return d->m_servicesByPopularity[n].popularity; + else + return 0.0; +} + +int PopularityStatistics::rankByService(const QString service) +{ + if (d->m_serviceRanks.find(service) != d->m_serviceRanks.end()) + { + return d->m_serviceRanks[service]; + } + return -1; +} + +void PopularityStatistics::writeConfig(Prefs* prefs) const +{ + QStringList serviceNames, serviceHistories; + int limit = prefs->serviceCacheSize(); + //kdDebug() << "popularityData: writeConfig" << endl; + for (int n=0; nm_servicesByPopularity.size()) && nm_servicesByPopularity[n]; + QStringList historyData; + for (int i=0; im_stats.size()); ++i) + { + historyData << QString::number(d->m_stats[i].vals[pop.service]); + } + serviceNames << pop.service; + serviceHistories << historyData.join("/"); + //kdDebug() << "popularityData: writeConfig -- " << pop.service << endl; + } + prefs->setServiceNames(serviceNames); + prefs->setServiceHistories(serviceHistories); +} + +void PopularityStatistics::readConfig(Prefs* prefs) +{ + int n = 0; + QStringList serviceNames = prefs->serviceNames(); + QStringList histories = prefs->serviceHistories(); + for (n = std::min(serviceNames.size(), histories.size())-1; n>=0; --n) + { + QString serviceName = serviceNames[n]; + QStringList serviceHistory = + QStringList::split("/", histories[n]); + for (int i=min(serviceHistory.size(), d->m_stats.size())-1; i>=0; --i) + { + d->m_stats[i].vals[serviceName] = serviceHistory[i].toDouble(); + } + } + + for (int i=0; im_stats.size()); ++i) + { + map::iterator valIt; + double valSum = 0; + for (valIt = d->m_stats[i].vals.begin(); + valIt != d->m_stats[i].vals.end(); ++valIt) + { + if (valIt->second < 0) valIt->second = 0; + valSum += valIt->second; + } + // Scale down values if their sum is bigger than 1 + // because of rounding errors or a corrupted config file + if (valSum > 1) + { + for (valIt = d->m_stats[i].vals.begin(); + valIt != d->m_stats[i].vals.end(); ++valIt) + { + valIt->second = valIt->second / valSum; + } + } + d->m_stats[i].iniVal = 1-valSum; + } + d->updateServiceRanks(); +} + +void PopularityStatistics::setHistoryHorizon(double h) +{ + d->m_historyHorizon = std::max(std::min(h, 1.0), 0.0); + d->updateServiceRanks(); +} + +double PopularityStatistics::historyHorizon() +{ + return d->m_historyHorizon; +} + + +// ---- Implementation methods ---- + +PopularityStatisticsImpl::PopularityStatisticsImpl() +{ + const int rateBaseCount(8); + + m_historyHorizon = 0.0; + + for (int n=0; n::iterator it; + for (it = h.vals.begin(); it != h.vals.end(); ++it) + { + sum += it->second; + } + for (it = h.vals.begin(); it != h.vals.end(); ++it) + { + it->second = it->second / sum; + } + h.iniVal = h.iniVal / sum; +} + +void PopularityStatisticsImpl::updateServiceRanks() +{ + // For each service calculate the average over the popularity + // for all falloff values and then sort by these averaged values + + vector::iterator + it(m_stats.begin()), end(m_stats.end()); + map serviceValSum, serviceValWeightSum; + int numStats = m_stats.size(); + for (int statIndex = 0; it != end; ++it, ++statIndex) + { + // Put more weight on the short term history if m_historyHorizon==0 + // and more on the the long term history for m_historyHorizon==1 + double a = 2*(numStats-1)*m_historyHorizon - numStats + 0.5; + if (statIndex < a || statIndex > a + numStats) + { + continue; + } + + map::iterator valIt; + /*double valSum = 0; + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + valSum += valIt->second; + } + if (valSum == 0) valSum = 1;*/ + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + serviceValWeightSum[valIt->first] += 1; + serviceValSum[valIt->first] += valIt->second; + } + } + + m_servicesByPopularity.clear(); + map::iterator sIt; + for (sIt = serviceValWeightSum.begin(); + sIt != serviceValWeightSum.end(); ++sIt) + { + Popularity p; + p.service = sIt->first; + assert(sIt->second > 0); + p.popularity = serviceValSum[sIt->first] / sIt->second; + m_servicesByPopularity.push_back(p); + } + stable_sort(m_servicesByPopularity.begin(), m_servicesByPopularity.end()); + m_serviceRanks.clear(); + for (uint n = 0; n < m_servicesByPopularity.size(); ++n) + { + m_serviceRanks[m_servicesByPopularity[n].service] = n; + /*kdDebug() << QString("Rank %1: %2 %3").arg(n) + .arg(m_servicesByPopularity[n].popularity) + .arg(m_servicesByPopularity[n].service) << endl;*/ + } +} diff --git a/kicker/applets/launcher/popularity.h b/kicker/applets/launcher/popularity.h new file mode 100644 index 000000000..b1dcb32d6 --- /dev/null +++ b/kicker/applets/launcher/popularity.h @@ -0,0 +1,127 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen + +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. + +******************************************************************/ + +#ifndef __popularity_h__ +#define __popularity_h__ + +#include +#include + +class PopularityStatisticsImpl; +class Prefs; + +/** + * Tracks the usage of any kind of service to offer recommendations. + * A service is identified by a string. After calling @useService + * a few times, you can get a popularity ranking for the used + * services. + * The algorithm tries to take both short- and long-term usage + * into account at the same time. + * The popularity value can be interpreted as the probability + * that the given service will be the next one to be used. + * If some new services are suddenly used a few times, their ranking + * may grow higher than the ranking of services, which were used very + * frequently a while ago. But after this short term usage has + * stopped, its influence gets weaker more quickly then for the old, + * more frequently used services. + * During first time usage, the algorithm needs some time to stabilize, + * since there is simply no dependable long term usage data available, + * so the ranking is more likely to change at first. + * But in the long run, the behaviour of the algorithm is + * completely stable, unlike simple usage counting for instance. + */ +class PopularityStatistics +{ +public: + PopularityStatistics(); + virtual ~PopularityStatistics(); + + /** + * Touch a service. This will increase the usage + * counters for the given service and decrease the + * counters for all the others. + */ + void useService(const QString& service); + + /** + * Exchange all state variables of the most + * popular service with those from services, + * moving the given services to the top of the + * list. Apart from that the order stays the same + * as before. Order of items in the string list + * does *not* matter/ + */ + void moveToTop(const QStringList& services); + + /** + * Sets all counters to zero for the given service + */ + void moveToBottom(const QString& service); + + /** + * Retrieve the name of a service by its position + * in the current popularity ranking + */ + QString serviceByRank(int n) const; + + /** + * Retrieve the popularity (0-1) of a service by + * its position in the current popularity ranking + */ + double popularityByRank(int n) const; + + /** + * Gets the rank of a given service. + * Returns -1 if the service is not in the ranking + */ + int rankByService(const QString service); + + /** + * Writes the configuration. + * A section must be set already for config. + */ + void writeConfig(Prefs* prefs) const; + + /** + * Reads the configuration. + * A section must be set already for config. + */ + void readConfig(Prefs* prefs); + + /** + * Modify the weighting of the history logs. + * 0 <= h <= 1. 1 means long term history + * 0 means short term history - in fact the popularity ranking + * becomes a recently-used list in that case. + */ + void setHistoryHorizon(double h); + double historyHorizon(); + +protected: + PopularityStatisticsImpl *d; + +private: + PopularityStatistics(const PopularityStatistics&) {} +}; + +#endif diff --git a/kicker/applets/launcher/prefs.kcfgc b/kicker/applets/launcher/prefs.kcfgc new file mode 100644 index 000000000..26a3f3d07 --- /dev/null +++ b/kicker/applets/launcher/prefs.kcfgc @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=launcherapplet.kcfg +ClassName=Prefs +Singleton=false +Mutators=AutoAdjustMaxItems,Buttons,VolatileButtons,AutoAdjustMaxItems,AutoAdjustMinItems,AutoAdjustEnabled,IconDim,DragEnabled,ConserveSpace,ServiceInspos,ServiceNames,ServiceHistories +# MemberVariables=public diff --git a/kicker/applets/launcher/quickaddappsmenu.cpp b/kicker/applets/launcher/quickaddappsmenu.cpp new file mode 100644 index 000000000..74d00a6e4 --- /dev/null +++ b/kicker/applets/launcher/quickaddappsmenu.cpp @@ -0,0 +1,67 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + based on paneladdappsmenu.cpp which is + Copyright (c) 1999-2000 the kicker authors + +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 "quickaddappsmenu.h" + +QuickAddAppsMenu::QuickAddAppsMenu(const QString &label, const QString &relPath, QWidget *target, QWidget *parent, const char *name, const QString &sender) + : PanelServiceMenu(label, relPath, parent, name) +{ + _targetObject = target; + _sender = sender; + connect(this, SIGNAL(addAppBefore(QString,QString)), + target, SLOT(addAppBeforeManually(QString,QString))); +} + +QuickAddAppsMenu::QuickAddAppsMenu(QWidget *target, QWidget *parent, const QString &sender, const char *name) + : PanelServiceMenu(QString::null, QString::null, parent, name) +{ + _targetObject = target; + _sender = sender; + connect(this, SIGNAL(addAppBefore(QString,QString)), + target, SLOT(addAppBeforeManually(QString,QString))); +} + +void QuickAddAppsMenu::slotExec(int id) +{ + if (!entryMap_.contains(id)) return; + KSycocaEntry * e = entryMap_[id]; + KService::Ptr service = static_cast(e); + emit addAppBefore(locate("apps", service->desktopEntryPath()),_sender); +} + + +PanelServiceMenu *QuickAddAppsMenu::newSubMenu(const QString &label, const QString &relPath, QWidget *parent, const char *name, const QString &insertInlineHeader) +{ + return new QuickAddAppsMenu(label, relPath, _targetObject, parent, name, _sender); +} +#include "quickaddappsmenu.moc" diff --git a/kicker/applets/launcher/quickaddappsmenu.h b/kicker/applets/launcher/quickaddappsmenu.h new file mode 100644 index 000000000..88465049c --- /dev/null +++ b/kicker/applets/launcher/quickaddappsmenu.h @@ -0,0 +1,51 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + based on paneladdappsmenu.h which is + Copyright (c) 1999-2000 the kicker authors + +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. +s +******************************************************************/ + +#ifndef __quickaddappsmenu_h__ +#define __quickaddappsmenu_h__ + +#include "service_mnu.h" + +class QuickAddAppsMenu: public PanelServiceMenu { + Q_OBJECT +public: + QuickAddAppsMenu(const QString &label, const QString &relPath, QWidget *target, QWidget *parent=0, const char *name=0, const QString &sender=QString("")); + QuickAddAppsMenu(QWidget *target, QWidget *parent=0, const QString &sender=QString(""), const char *name=0); +signals: + void addAppBefore(QString,QString); +protected slots: + virtual void slotExec(int id); +protected: + virtual PanelServiceMenu *newSubMenu(const QString &label, + const QString &relPath, + QWidget *parent, + const char *name, + const QString & _inlineHeader=QString::null); +private: + QWidget *_targetObject; + QString _sender; +}; + +#endif diff --git a/kicker/applets/launcher/quickbutton.cpp b/kicker/applets/launcher/quickbutton.cpp new file mode 100644 index 000000000..933088b04 --- /dev/null +++ b/kicker/applets/launcher/quickbutton.cpp @@ -0,0 +1,322 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +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 "quickbutton.h" +#include "quickaddappsmenu.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef DEBUG + #define DEBUGSTR kdDebug() +#else + #define DEBUGSTR kndDebug() +#endif + +QuickURL::QuickURL(const QString &u) +{ DEBUGSTR<<"QuickURL::QuickURL("<desktopEntryPath()="<<_service->desktopEntryPath()<desktopEntryPath())); + } + if (!_service->menuId().isEmpty()) + _menuId = _service->menuId(); + + m_genericName = _service->genericName(); + m_name = _service->name(); + } + } else { + m_name = _kurl.prettyURL(); + } + DEBUGSTR<<"QuickURL::QuickURL("<propagateSessionManager(); // is this needed? + if (_service) + KRun::run(*(_service), KURL::List()); + else + new KRun(_kurl, 0, _kurl.isLocalFile()); +} + +//similar to MimeType::pixmapForURL +QPixmap QuickURL::pixmap( mode_t _mode, KIcon::Group _group, + int _force_size, int _state, QString *) const +{ // Load icon + QPixmap pxmap = KMimeType::pixmapForURL(_kurl, _mode, _group, _force_size, _state); + // Resize to fit button + pxmap.convertFromImage(pxmap.convertToImage().smoothScale(_force_size,_force_size, QImage::ScaleMin)); + return pxmap; +} + + +QuickButton::QuickButton(const QString &u, KAction* configAction, + QWidget *parent, const char *name) : + SimpleButton(parent, name), + m_flashCounter(0), + m_sticky(false) +{ + installEventFilter(KickerTip::the()); + setMouseTracking(true); + _highlight = false; + _oldCursor = cursor(); + _qurl=new QuickURL(u); + + QToolTip::add(this, _qurl->name()); + resize(int(DEFAULT_ICON_DIM),int(DEFAULT_ICON_DIM)); + QBrush bgbrush(colorGroup().brush(QColorGroup::Background)); + + QuickAddAppsMenu *addAppsMenu = new QuickAddAppsMenu( + parent, this, _qurl->url()); + _popup = new QPopupMenu(this); + _popup->insertItem(i18n("Add Application"), addAppsMenu); + configAction->plug(_popup); + _popup->insertSeparator(); + _popup->insertItem(SmallIcon("remove"), i18n("Remove"), + this, SLOT(removeApp())); + + m_stickyAction = new KToggleAction(i18n("Never Remove Automatically"), + KShortcut(), this); + connect(m_stickyAction, SIGNAL(toggled(bool)), + this, SLOT(slotStickyToggled(bool))); + m_stickyAction->plug(_popup, 2); + m_stickyId = _popup->idAt(2); + + connect(this, SIGNAL(clicked()), SLOT(launch())); + connect(this, SIGNAL(removeApp(QuickButton *)), parent, + SLOT(removeAppManually(QuickButton *))); +} + +QuickButton::~QuickButton() +{ + delete _qurl; +} + + +QString QuickButton::url() const +{ + return _qurl->url(); +} + + +QString QuickButton::menuId() const +{ return _qurl->menuId();} + + +void QuickButton::loadIcon() +{ + // Set Icon Dimension from size + _iconDim=std::min(size().width(),size().height())-2*ICON_MARGIN; + // Load icons + _icon = _qurl->pixmap(0, KIcon::Panel, _iconDim, KIcon::DefaultState); + _iconh = _qurl->pixmap(0, KIcon::Panel, _iconDim, KIcon::ActiveState); + setPixmap(_icon); +} + +void QuickButton::resizeEvent(QResizeEvent *e) +{ + loadIcon(); + SimpleButton::resizeEvent(e); +} + +void QuickButton::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == RightButton) + _popup->popup(e->globalPos()); + else if (e->button() == LeftButton) { + _dragPos = e->pos(); + QButton::mousePressEvent(e); + } +} + +void QuickButton::mouseMoveEvent(QMouseEvent *e) +{ + if ((e->state() & LeftButton) == 0) return; + QPoint p(e->pos() - _dragPos); + if (p.manhattanLength() <= KGlobalSettings::dndEventDelay()) + return; + DEBUGSTR<<"dragstart"<kurl()); + DEBUGSTR<<"creating KURLDrag"<setPixmap(_icon); //PIX + DEBUGSTR<<"ready to drag"<drag(); + releaseKeyboard(); + } else { + setCursor(Qt::ForbiddenCursor); + } +} + +void QuickButton::slotIconChanged(int group) +{ + loadIcon(); + SimpleButton::slotIconChanged(group); + update(); +} + +void QuickButton::launch() +{ + setDown(false); + update(); + KIconEffect::visualActivate(this, rect()); + _qurl->run(); + emit executed(_qurl->menuId()); +} + +void QuickButton::setDragging(bool enable) +{ + setDown(enable); + _highlight=enable; + update(); +} + +void QuickButton::setEnableDrag(bool enable) +{ + _dragEnabled=enable; +} + +void QuickButton::removeApp() +{ + emit removeApp(this); +} + +void QuickButton::flash() +{ + m_flashCounter = 2000; + QTimer::singleShot(0, this, SLOT(slotFlash())); +} + +void QuickButton::slotFlash() +{ + static const int timeout = 500/4; + if (m_flashCounter > 0) + { + m_flashCounter -= timeout; + if (m_flashCounter < 0) m_flashCounter = 0; + update(); + QTimer::singleShot(timeout, this, SLOT(slotFlash())); + } +} + +void QuickButton::slotStickyToggled(bool isSticky) +{ + m_sticky = isSticky; + emit stickyToggled(isSticky); +} + +void QuickButton::setSticky(bool sticky) +{ + m_stickyAction->setChecked(sticky); + slotStickyToggled(sticky); +} + +void QuickButton::updateKickerTip(KickerTip::Data &data) +{ + if (!_qurl) + { + return; + } + data.message = _qurl->name(); + data.direction = m_popupDirection; + data.subtext = _qurl->genericName(); + if (data.subtext == QString()) + { + data.subtext = data.message; + } + data.icon = KMimeType::pixmapForURL(_qurl->kurl(), 0, + KIcon::Panel, KIcon::SizeHuge, KIcon::DefaultState); +} + +void QuickButton::setPopupDirection(KPanelApplet::Direction d) +{ + m_popupDirection = d; +} + +void QuickButton::setDynamicModeEnabled(bool enabled) +{ + _popup->setItemVisible(m_stickyId, enabled); +} + + +#include "quickbutton.moc" diff --git a/kicker/applets/launcher/quickbutton.h b/kicker/applets/launcher/quickbutton.h new file mode 100644 index 000000000..98eabec6e --- /dev/null +++ b/kicker/applets/launcher/quickbutton.h @@ -0,0 +1,124 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +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. + +******************************************************************/ + +#ifndef __quickbutton_h__ +#define __quickbutton_h__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "simplebutton.h" + +class QPopupMenu; +class KAction; +class KToggleAction; + +class QuickURL { +public: + QuickURL(const QString &u); + KURL kurl() const {return _kurl;}; + QString url() const {return _kurl.url();}; + QString menuId() const {return _menuId;}; + QString genericName() const { return m_genericName; } + QString name() const { return m_name; } + KService::Ptr service() const {return _service;}; + void run() const; + QPixmap pixmap(mode_t _mode = 0, KIcon::Group _group = KIcon::Desktop, + int _force_size = 0, int _state = 0, QString * _path = 0L) const; + +private: + KURL _kurl; + QString _menuId; + QString m_genericName; + QString m_name; + KService::Ptr _service; +}; + + +class QuickButton: public SimpleButton, public KickerTip::Client { + Q_OBJECT + +public: + enum { DEFAULT_ICON_DIM = 16 }; + enum { ICON_MARGIN = 1 }; + QuickButton(const QString &u, KAction* configAction, + QWidget *parent=0, const char *name=0); + ~QuickButton(); + QString url() const; + QString menuId() const; + QPixmap icon() const{ return _icon;} + bool sticky() { return m_sticky; } + void setSticky(bool bSticky); + void setPopupDirection(KPanelApplet::Direction d); + + void setDragging(bool drag); + void setEnableDrag(bool enable); + void setDynamicModeEnabled(bool enabled); + void flash(); + +signals: + void removeApp(QuickButton *); + void executed(QString serviceStorageID); + void stickyToggled(bool isSticky); + +protected: + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *rsevent); + void loadIcon(); + void updateKickerTip(KickerTip::Data &data); + +protected slots: + void slotIconChanged(int); + void launch(); + void removeApp(); + void slotFlash(); + void slotStickyToggled(bool isSticky); + +private: + int m_flashCounter; + QuickURL *_qurl; + QPoint _dragPos; + QPopupMenu *_popup; + QPixmap _icon, _iconh; + QCursor _oldCursor; + bool _highlight, _changeCursorOverItem, _dragEnabled; + int _iconDim; + bool m_sticky; + KToggleAction *m_stickyAction; + int m_stickyId; + KPanelApplet::Direction m_popupDirection; +}; + +#endif + diff --git a/kicker/applets/launcher/quickbuttongroup.h b/kicker/applets/launcher/quickbuttongroup.h new file mode 100644 index 000000000..1d373ae92 --- /dev/null +++ b/kicker/applets/launcher/quickbuttongroup.h @@ -0,0 +1,60 @@ +/* Copyright 2004, Daniel Woods Bullok + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#ifndef __quickbuttongroup_h__ +#define __quickbuttongroup_h__ + +#include +#include +#include "easyvector.h" +#include "quickbutton.h" + + +class QuickButtonGroup: virtual public EasyVector< QuickButton* > { +public: + QuickButtonGroup(const EasyVector< QuickButton* > &kv):EasyVector< QuickButton* >(kv){}; + QuickButtonGroup():EasyVector< QuickButton* >(){}; + Index findDescriptor(const QString &desc); + + void show(); + void hide(); + void setDragging(bool drag); + void setEnableDrag(bool enable); + void deleteContents(); + void setUpdatesEnabled(bool enable); +}; + +QuickButtonGroup::Index QuickButtonGroup::findDescriptor(const QString &desc) +{ return findProperty(desc, std::mem_fun(&QuickButton::url));} + +inline void QuickButtonGroup::setUpdatesEnabled(bool enable) +{ for (QuickButtonGroup::iterator i=begin();i!=end();++i) { + (*i)->setUpdatesEnabled(enable); + if (enable) { (*i)->update();} + } +} + +inline void QuickButtonGroup::show() +{ std::for_each(begin(),end(),std::mem_fun(&QWidget::show));} + +inline void QuickButtonGroup::hide() +{ std::for_each(begin(),end(),std::mem_fun(&QWidget::hide));} + +inline void QuickButtonGroup::setDragging(bool drag) +{ std::for_each(begin(),end(),std::bind2nd(std::mem_fun(&QuickButton::setDragging),drag));} + +inline void QuickButtonGroup::setEnableDrag(bool enable) +{ std::for_each(begin(),end(),std::bind2nd(std::mem_fun(&QuickButton::setEnableDrag),enable));} + +inline void QuickButtonGroup::deleteContents() +{ for (QuickButtonGroup::iterator i=begin();i!=end();++i) { + delete (*i); + (*i)=0; + } +} + +#endif + diff --git a/kicker/applets/launcher/quicklauncher.cpp b/kicker/applets/launcher/quicklauncher.cpp new file mode 100644 index 000000000..abae9efe1 --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.cpp @@ -0,0 +1,1093 @@ +/***************************************************************** + +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(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("quicklauncher"); + return new QuickLauncher(configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, + parent, "quicklauncher"); + } +} + +QuickLauncher::QuickLauncher(const QString& configFile, Type type, int actions, + QWidget *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(), + this, SLOT(slotConfigure()), this); + + m_saveTimer = new QTimer(this); + connect(m_saveTimer, SIGNAL(timeout()), this, SLOT(saveConfig())); + + m_popularity = new PopularityStatistics(); + + setBackgroundOrigin(AncestorOrigin); + + loadConfig(); + + buildPopupMenu(); + m_minPanelDim = std::max(16, m_settings->iconDimChoices()[1]); + refreshContents(); + setRefreshEnabled(true); + + setAcceptDrops(true); + //QToolTip::add(this, i18n("Drop applications here")); + DEBUGSTR << " QuickLauncher::QuickLauncher(" << configFile << + ",...) END" << endl << flush; + + DCOPClient *dcopClient = KApplication::dcopClient(); + dcopClient->connectDCOPSignal(0, "appLauncher", + "serviceStartedByStorageId(QString,QString)", + "QuickLauncherApplet", + "serviceStartedByStorageId(QString,QString)", + 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 QPopupMenu(this); + m_popup->insertItem(i18n("Add Application"), addAppsMenu); + m_configAction->plug(m_popup); + + m_appletPopup = new QPopupMenu(this); + m_appletPopup->insertItem(i18n("Add Application"), addAppsMenu); + m_removeAppsMenu = new QPopupMenu(this); + connect(m_removeAppsMenu, SIGNAL(aboutToShow()), + SLOT(fillRemoveAppsMenu())); + connect(m_removeAppsMenu, SIGNAL(activated(int)), + SLOT(removeAppManually(int))); + m_appletPopup->insertItem(i18n("Remove Application"), m_removeAppsMenu); + + m_appletPopup->insertSeparator(); + m_appletPopup->setCheckable( true ); + m_appletPopup->insertItem(i18n("About"), this, 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()) + { + QString text = QToolTip::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, SIGNAL(settingsChanged()), + this, 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(QString 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; + + QString removeAppUrl = (*m_buttons)[index]->url(); + QString removeAppMenuId = (*m_buttons)[index]->menuId(); + + 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(QString 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(QSize(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(QSize(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(QString url, bool manuallyAdded) +{ + assert(m_buttons); + QString 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) + { + QString buttonId = (*m_buttons)[appPos]->menuId(); + if (m_appOrdering[buttonId] >= m_appOrdering[newButtonId]) + { + break; + } + } + addApp(url, appPos, manuallyAdded); +} + +QuickButton* QuickLauncher::createButton(QString url) +{ + QuickButton* newButton=new QuickButton(url, m_configAction, this); + connect(newButton, SIGNAL(executed(QString)), + this, SLOT(slotOwnServiceExecuted(QString))); + connect(newButton, SIGNAL(stickyToggled(bool)), + this, SLOT(slotStickyToggled())); + newButton->setPopupDirection(popupDirection()); + return newButton; +} + +void QuickLauncher::addApp(QString 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) + { + QString 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(QString url, QString 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(QMouseEvent *e) +{ + if (e->button() == RightButton) + { + m_popup->popup(e->globalPos()); + } +} + +void QuickLauncher::resizeEvent(QResizeEvent*) +{ + refreshContents(); +} + +void QuickLauncher::dragEnterEvent(QDragEnterEvent *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); + + QString 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(QDragMoveEvent *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(QDragLeaveEvent *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(QDropEvent *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()); + // 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 = QSize(idim, idim); + m_manager->setOrientation(orientation()); + m_manager->setNumItems(m_buttons->size()); + m_manager->setFrameSize(size()); + m_manager->setItemSize(m_buttonSize); + m_manager->setSpaceSize(QSize(m_space, m_space)); + m_manager->setBorderSize(QSize(m_border, m_border)); + if (!m_refreshEnabled) + { + m_needsRefresh=true; + return; + } + if (!m_manager->isValid()) + { + kdDebug()<dump(); + return; + } + + unsigned index; + QPoint pos; + setUpdatesEnabled(false); + m_buttons->setUpdatesEnabled(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(); + setUpdatesEnabled(true); + update(); + m_buttons->setUpdatesEnabled(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.contains(button->menuId()) == false) + { + button->setSticky(true); + } + button->setDynamicModeEnabled(m_settings->autoAdjustEnabled()); + } + + m_popularity->readConfig(m_settings); + m_popularity->setHistoryHorizon(m_settings->historyHorizon()/100.0); + + QStringList serviceNames = m_settings->serviceNames(); + QValueList 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; + } + QStringList 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 + QStringList serviceNames = m_settings->serviceNames(); + QValueList 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(QString /*starter*/, QString storageId) +{ + KService::Ptr service = KService::serviceByStorageId(storageId); + if (service->icon() == QString::null) + { + kdDebug() << storageId << " has no icon. Makes no sense to add it."; + return; + } + QuickURL url = QuickURL(locate("apps", service->desktopEntryPath())); + QString 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]; + QString 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()) + { + QTimer::singleShot(0, this, 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) + { + QString 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(QString serviceMenuId) +{ + m_popularity->useService(serviceMenuId); + if (m_settings->autoAdjustEnabled()) + { + QTimer::singleShot(0, this, 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 + QPixmap areaPix(width(), height()); + QPainter areaPixPainter(&areaPix); + areaPixPainter.fillRect(0, 0, width(), height(), QColor(255, 255, 255)); + QSize itemSize = m_manager->itemSize(); + QSize spaceSize = m_manager->spaceSize(); + for (uint n=0; nsize(); ++n) + { + QPoint 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, + QColor(0, 0, 0)); + } + } + QImage areaLayer = areaPix.convertToImage(); + m_stickyHighlightLayer = QImage(width(), height(), 32); + m_stickyHighlightLayer.setAlphaBuffer(true); + int pix, tlPix, brPix, w(width()), h(height()); + QRgb transparent(qRgba(0, 0, 0, 0)); + for (int y = h-1; y >= 0; --y) + { + for (int x = w-1; x >= 0; --x) + { + pix = qRed(areaLayer.pixel(x, y)); + if (pix == 0) + { + tlPix = (y>0 && x>0) ? qRed(areaLayer.pixel(x-1,y-1)) : 255; + brPix = (yautoAdjustEnabled() && + m_settings->showVolatileButtonIndicator()) + { + QPainter 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" diff --git a/kicker/applets/launcher/quicklauncher.desktop b/kicker/applets/launcher/quicklauncher.desktop new file mode 100644 index 000000000..0e80149aa --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.desktop @@ -0,0 +1,140 @@ +[Desktop Entry] +Type=Plugin +Name=Quick Launcher +Name[af]=Vinnige Lanseerder +Name[ar]=الإنطلاق السريع +Name[az]=Sür'ətli Başladıcı +Name[be]=Хуткі запускальнік +Name[bg]=Бързо стартиране +Name[bn]=কুইক লঞ্চার +Name[br]=Loc'her prim +Name[bs]=Brzo pokretanje +Name[ca]=Engegador ràpid +Name[cs]=Rychlé spouštění aplikací +Name[csb]=Chùtczé zrëszenié +Name[cy]=Cychwynydd Cyflym +Name[da]=Hurtigstarter +Name[de]=Schnellstarter +Name[el]=Γρήγορη φόρτωση +Name[eo]=Rapidlanĉilo +Name[es]=Lanzador rápido +Name[et]=Kiirkäivitaja +Name[eu]=Abiarazle bizkorra +Name[fa]=راه‌انداز سریع +Name[fi]=Sovellusten pikakäynnistin +Name[fr]=Lanceur d'applications +Name[fy]=Snel útfierder +Name[ga]=Tosaitheoir Tapa +Name[gl]=Lanzador Rápido +Name[he]=הפעלה מהירה +Name[hi]=द्रुत लांचर +Name[hr]=Brzo pokretanje +Name[hu]=Gyorsindító +Name[id]=Launcher Cepat +Name[is]=Flýtiræsir +Name[it]=Esecuzione rapida +Name[ja]=クイックランチャー +Name[ka]=სწრაფი დაწყება +Name[kk]=Жедел жегуші +Name[km]=អ្នក​ចាប់ផ្ដើម​រហ័ស +Name[lo]=ຮງກທຳງານດ່ວນ +Name[lt]=Greitasis paleidimas +Name[lv]=Ātrais Palaidējs +Name[mk]=Брз стартувач +Name[mn]=Түргэн ажилуулагч +Name[ms]=Pelancar Pantas +Name[mt]=Ħaddem Malajr +Name[nb]=Hurtigstarter +Name[nds]=Fixstarter +Name[ne]=द्रुत सुरुआत +Name[nl]=Snelstarter +Name[nn]=Snøggstartar +Name[nso]=Ngwadisoleswa ya Kapela +Name[oc]=Engegador rapid +Name[pa]=ਚੁਸਤ ਸ਼ੁਰੂਆਤੀ +Name[pl]=Szybkie uruchamianie +Name[pt]=Execução de Aplicações +Name[pt_BR]=Lançador rápido +Name[ro]=Executor rapid +Name[ru]=Быстрый запуск +Name[rw]=Mutangiza Yihuta +Name[se]=Jođánisálggaheaddji +Name[sk]=Rýchly spúšťač +Name[sl]=Hitri zaganjalnik +Name[sr]=Брзи покретач +Name[sr@Latn]=Brzi pokretač +Name[sv]=Snabbstartare +Name[ta]=உடனடியாக திரையில் தெரிதல் +Name[te]=త్వరగా మొదలుపెట్టెది +Name[tg]=Сар додани тез +Name[th]=เรียกทำงานด่วน +Name[tr]=Hızlı Başlatıcı +Name[tt]=Tiz Cibärgeç +Name[uk]=Швидкий запуск +Name[uz]=Tez ishga tushirgich +Name[uz@cyrillic]=Тез ишга туширгич +Name[ven]=Tavhanya +Name[vi]=Khởi động nhanh +Name[wa]=Enondeu al vole di programes +Name[zh_CN]=快速启动 +Name[zh_TW]=快速起動 +Name[zu]=Umqalisi osheshayo +Comment=Directly access your frequently used applications +Comment[af]=Kry direkte toegang tot die programme wat jy gereeld gebruik +Comment[ar]=للوصول المباشر إلى تطبيقاتك الأكثر إستعمالاً +Comment[be]=Наўпрост запускае праграму +Comment[bg]=Бърз достъп до често използваните програми +Comment[bn]=আপনার সবচেয়ে ঘনঘন ব্যবহৃত অ্যাপলিকেশনগুলি সরাসরি চালু করুন +Comment[bs]=Direktno pristupite vašim često korištenim programima +Comment[ca]=Accedeix directament a les aplicacions més usades +Comment[cs]=Přímý přístup k nejčastěji používaným aplikacím +Comment[csb]=Prosti przistãp do nôczãstczi brëkòwónëch programów +Comment[da]=Direkte adgang til programmer du ofte bruger +Comment[de]=Schneller Zugriff auf häufig verwendete Programme +Comment[el]=Απευθείας πρόσβαση στις συχνά χρησιμοποιούμενες εφαρμογές σας +Comment[eo]=Rekte atingi viajn preferatajn aplikaĵojn +Comment[es]=Acceso directo a las aplicaciones usadas más frecuentemente +Comment[et]=Ligipääs sagedamini kasutatud rakendustele +Comment[eu]=Sarbide zuzena zure ohiko aplikazioei +Comment[fa]=دستیابی مستقیم به کاربردهای مکرر استفاده‌شدۀ شما +Comment[fi]=Siirry suoraan useimmin käyttämiisi sovelluksiin +Comment[fr]=Accès direct aux applications les plus utilisées +Comment[fy]=Direkte tagong ta jo faak brûkte programma's +Comment[gl]=Aceda directamenta ás aplicacións que use mais amiudo +Comment[he]=גישה מהירה ליישומים שאתה משתמש בהם הכי הרבה +Comment[hr]=Izravni pristup najčešće upotrebljavanim aplikacijama +Comment[hu]=A gyakran használt alkalmazások közvetlen elérése +Comment[is]=Beinn aðgangur að mest notuðu forritunum þínum +Comment[it]=Accesso diretto alle applicazioni usate più frequentemente +Comment[ja]=よく用いるアプリケーションに直接アクセス +Comment[kk]=Жиі пайдаланатын қолданбаларды тез жегу +Comment[km]=ដំណើរការ​កម្មវិធី​ដែល​បាន​ប្រើ​ជា​រឿយៗ​របស់អ្នក​ដោយ​ផ្ទាល់ +Comment[lt]=Tiesiogiai pasiekite dažniausiai naudojamas programas +Comment[mk]=Пристапете директно на вашите често користени апликации +Comment[nb]=Få direkte tilgang til ofte brukte programmer +Comment[nds]=Direktemang Dien meist bruukte Programmen opropen +Comment[ne]=बारम्बार प्रयोग भएका अनुप्रयोगमा तपाईँको प्रत्यक्ष पहुँच +Comment[nl]=Directe toegang tot uw veelgebruikte programma's +Comment[nn]=Direkte tilgang til program du brukar ofte +Comment[pa]=ਅਕਸਰ ਵਰਤੇ ਜਾਂਦੇ ਕਾਰਜਾਂ ਲਈ ਸਿੱਧੀ ਪਹੁੰਚ +Comment[pl]=Bezpośredni dostęp do najczęściej używanych programów +Comment[pt]=Aceder directamente às aplicações usadas com mais frequência por si +Comment[pt_BR]=Acesso direito à seus aplicativos mais freqüentemente usados +Comment[ro]=Accesează direct aplicațiile folosite frecvent +Comment[ru]=Быстрый вызов часто используемых приложений +Comment[sk]=Priamo zprístupní najčastejšie používané programy. +Comment[sl]=Neposreden dostop do vaših najbolj uporabljanih programov +Comment[sr]=Директно приступите својим често коришћеним програмима +Comment[sr@Latn]=Direktno pristupite svojim često korišćenim programima +Comment[sv]=Direkt åtkomst av program du ofta använder +Comment[th]=เรียกใช้งานแอพพลิเคชั่นที่คุณใช้บ่อยๆ ได้โดยตรง +Comment[tr]=Sıkça kullanılan programlara erişim sağlar +Comment[uk]=Безпосередній доступ до програм, які часто вживаються +Comment[uz]=Eng koʻp ishlatilgan dasturlarga qisqa yoʻl +Comment[uz@cyrillic]=Энг кўп ишлатилган дастурларга қисқа йўл +Comment[vi]=Chạy ngay các trình bạn thường xuyên dùng +Comment[wa]=Accès direk ås programes sovint eployîs +Comment[zh_CN]=直接访问您最经常使用的应用程序 +Comment[zh_TW]=直接存取您最常使用的應用程式 +Icon=launch +X-KDE-Library=launcher_panelapplet diff --git a/kicker/applets/launcher/quicklauncher.h b/kicker/applets/launcher/quicklauncher.h new file mode 100644 index 000000000..c82d39661 --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.h @@ -0,0 +1,138 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +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. + +******************************************************************/ + +#ifndef __quicklauncher_h__ +#define __quicklauncher_h__ + +#include +#include +#include +#include +#include +#include + +#include "flowgridmanager.h" +#include "prefs.h" +#include "quickbutton.h" + +class ConfigDlg; +class QPopupMenu; +class QuickButtonGroup; +class PopularityStatistics; +class KAction; + +typedef QuickButtonGroup ButtonGroup; + +class QuickLauncher: public KPanelApplet, public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + void serviceStartedByStorageId(QString starter, QString storageId); + +public: + enum {DEFAULT_ICON_DIM=QuickButton::DEFAULT_ICON_DIM}; + enum {SIZE_AUTO=0}; + + struct PopularityInfo { + float popularity; + }; + + QuickLauncher(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~QuickLauncher(); + int widthForHeight(int height) const; + int heightForWidth(int width) const; + void addApp(QString url, int index, bool manuallyAdded); + virtual void action(Action a); + +public slots: + void addApp(QString url, bool manuallyAdded); + void addAppBeforeManually(QString url, QString sender); + void removeAppManually(QuickButton *button); + void removeApp(QString url, bool manuallyRemoved); + void removeApp(int index, bool manuallyRemoved); + void removeAppManually(int index); + void saveConfig(); + void about(); + +protected: + int findApp(QString url); + int findApp(QuickButton *button); + + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent*); + void dragEnterEvent(QDragEnterEvent *e); + void dragLeaveEvent(QDragLeaveEvent *e); + void dragMoveEvent(QDragMoveEvent *e); + void dropEvent(QDropEvent *e); + void refreshContents(); + void setRefreshEnabled(bool enable); + void setConserveSpace(bool conserve_space); + void setDragEnabled(bool conserve_space); + + bool conserveSpace() const { return m_manager->conserveSpace(); } + bool isDragEnabled() const { return m_settings->dragEnabled(); } + + void buildPopupMenu(); + void loadConfig(); + + void mergeButtons(int index); + void clearTempButtons(); + int dimension() const; + +protected slots: + void slotConfigure(); + void slotSettingsDialogChanged(); + void fillRemoveAppsMenu(); + void slotOwnServiceExecuted(QString serviceMenuId); + void slotAdjustToCurrentPopularity(); + void slotStickyToggled(); + +protected: + void updateInsertionPosToStatusQuo(); + void updateStickyHighlightLayer(); + QuickButton* createButton(QString url); + virtual void paintEvent(QPaintEvent* e); + virtual void positionChange(Position); + + QPopupMenu *m_popup; + QPopupMenu *m_appletPopup; + QPopupMenu *m_removeAppsMenu; + QuickButtonGroup *m_buttons, *m_newButtons, *m_oldButtons, *m_dragButtons; + int m_space, m_border; + QSize m_buttonSize; + FlowGridManager *m_manager; + int m_dropLen, m_dropPos, m_minPanelDim; + bool m_dragAccepted, m_refreshEnabled, m_needsSave, m_needsRefresh; + std::map m_appOrdering; + Prefs* m_settings; + KAction *m_configAction; + ConfigDlg *m_configDialog; + PopularityStatistics* m_popularity; + QImage m_stickyHighlightLayer; + QTimer *m_saveTimer; +}; + +#endif -- cgit v1.2.3