summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2016-04-10 02:08:09 +0200
committerSlávek Banko <slavek.banko@axis.cz>2016-04-10 02:08:09 +0200
commit0d02094e2b261de9aadac40f65a574e9fbee66e2 (patch)
tree60621cbe5c2907665040e91d9c9523ce7a05e4fa /src
downloadtastymenu-0d02094e2b261de9aadac40f65a574e9fbee66e2.tar.gz
tastymenu-0d02094e2b261de9aadac40f65a574e9fbee66e2.zip
Initial import of tastymenu 1.0.8
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-rw-r--r--src/appearance.ui608
-rw-r--r--src/appearance.ui.h23
-rw-r--r--src/behaviour.ui234
-rw-r--r--src/create_buttons.sh1
-rw-r--r--src/dmctl.cpp434
-rw-r--r--src/dmctl.h93
-rw-r--r--src/menu.ui379
-rw-r--r--src/menuhandler.cpp1712
-rw-r--r--src/menuhandler.h184
-rw-r--r--src/misc.cpp38
-rw-r--r--src/misc.h24
-rw-r--r--src/pics/.svn/all-wcprops17
-rw-r--r--src/pics/.svn/entries42
-rw-r--r--src/pics/.svn/format1
-rw-r--r--src/pics/.svn/prop-base/attach.png.svn-base5
-rw-r--r--src/pics/.svn/prop-base/detach.png.svn-base5
-rw-r--r--src/pics/.svn/text-base/attach.png.svn-basebin0 -> 192 bytes
-rw-r--r--src/pics/.svn/text-base/detach.png.svn-basebin0 -> 199 bytes
-rw-r--r--src/pics/attach.pngbin0 -> 192 bytes
-rw-r--r--src/pics/detach.pngbin0 -> 199 bytes
-rw-r--r--src/prefs.kcfgc6
-rw-r--r--src/tastybutton.cpp116
-rw-r--r--src/tastybutton.h49
-rw-r--r--src/tastylistview.cpp600
-rw-r--r--src/tastylistview.h225
-rw-r--r--src/tastymenu.cpp492
-rw-r--r--src/tastymenu.desktop10
-rw-r--r--src/tastymenu.h165
-rw-r--r--src/tastymenu.kcfg188
-rw-r--r--src/tastymenu.lsm16
-rw-r--r--src/tastytooltip.cpp100
-rw-r--r--src/tastytooltip.h59
-rw-r--r--src/tastytooltipwidget.ui109
34 files changed, 5957 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..75007d3
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES= $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = tastymenu_panelapplet.la
+
+tastymenu_panelapplet_la_SOURCES = tastymenu.cpp menu.ui menuhandler.cpp \
+ dmctl.cpp dmctl.h tastylistview.cpp misc.cpp misc.h appearance.ui prefs.kcfgc \
+ behaviour.ui tastytooltip.cpp tastytooltipwidget.ui tastybutton.cpp
+tastymenu_panelapplet_la_LDFLAGS = -version-info 0:0:0 -module $(KDE_PLUGIN) $(all_libraries)
+tastymenu_panelapplet_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO)
+
+tastymenu_DATA = tastymenu.desktop
+tastymenudir = $(kde_datadir)/kicker/applets
+kde_kcfg_DATA = tastymenu.kcfg
+
+EXTRA_DIST = pics
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/tastymenu.pot
+noinst_HEADERS = menuhandler.h tastylistview.h tastytooltip.h buttons.h \
+ tastybutton.h
diff --git a/src/appearance.ui b/src/appearance.ui
new file mode 100644
index 0000000..6e8c409
--- /dev/null
+++ b/src/appearance.ui
@@ -0,0 +1,608 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Appearance</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Appearance</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>520</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Icons</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Applications list</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="12" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_ShowExpander</cstring>
+ </property>
+ <property name="text">
+ <string>Show tree e&amp;xpanders</string>
+ </property>
+ <property name="accel">
+ <string>Alt+X</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="13" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_AlwaysCollapsed</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Alwa&amp;ys collapsed categories</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="10" column="1">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Hei&amp;ght:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_MenuHeight</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Button label:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>79</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLineEdit" row="7" column="2">
+ <property name="name">
+ <cstring>kcfg_ToolTipTitle</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>What text should be displayed in the Kicker button tooltip instead of "Tasty Menu".
+Empty means default.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="9" column="1">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Wi&amp;dth:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_MenuWidth</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="1">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Tootip title:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="11" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>ApplicationsList</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Applications list</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="9" column="3">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>of the screen width</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>MenuButton</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Menu button</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="10" column="3">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>of the screen height</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="6" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_MenuButtonIconType</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_Icon</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Icon:</string>
+ </property>
+ <property name="accel">
+ <string>Alt+I</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KIconButton">
+ <property name="name">
+ <cstring>MenuButtonIcon</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>What icon should be displayed in the kicker button instead of the KMenu one.
+Empty means default.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>kcfg_MenuButtonIcon</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_IconNone</cstring>
+ </property>
+ <property name="text">
+ <string>N&amp;one</string>
+ </property>
+ <property name="accel">
+ <string>Alt+O</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="8" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>menuSize</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Menu size</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Action icons size:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ActionIconSize</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_DisplaySubText</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Display applications descriptions</string>
+ </property>
+ <property name="accel">
+ <string>Alt+D</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="5" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_MenuButtonLabelType</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_MenuButtonText</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Text:</string>
+ </property>
+ <property name="accel">
+ <string>Alt+T</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>kcfg_MenuButtonLabel</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>What label instead of "Menu" should be shown for the Kicker button.
+Empty means default.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_MenuButtonNone</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;None</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QSpinBox" row="9" column="2">
+ <property name="name">
+ <cstring>kcfg_MenuWidth</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>90</number>
+ </property>
+ <property name="minValue">
+ <number>10</number>
+ </property>
+ <property name="value">
+ <number>70</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="10" column="2">
+ <property name="name">
+ <cstring>kcfg_MenuHeight</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>90</number>
+ </property>
+ <property name="minValue">
+ <number>10</number>
+ </property>
+ <property name="value">
+ <number>70</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Button icon:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <spacer row="9" column="4" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>78</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="1" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel1_5_3</cstring>
+ </property>
+ <property name="text">
+ <string>third column:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel1_5_2</cstring>
+ </property>
+ <property name="text">
+ <string>second column:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="0">
+ <property name="name">
+ <cstring>kcfg_IconSize1</cstring>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ <property name="maxValue">
+ <number>48</number>
+ </property>
+ <property name="minValue">
+ <number>16</number>
+ </property>
+ <property name="value">
+ <number>22</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_IconSize3</cstring>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ <property name="maxValue">
+ <number>48</number>
+ </property>
+ <property name="minValue">
+ <number>16</number>
+ </property>
+ <property name="value">
+ <number>22</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_IconSize2</cstring>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ <property name="maxValue">
+ <number>48</number>
+ </property>
+ <property name="minValue">
+ <number>16</number>
+ </property>
+ <property name="value">
+ <number>22</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>first column:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Icons sizes:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_IconSize</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="2">
+ <property name="name">
+ <cstring>kcfg_ActionIconSize</cstring>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ <property name="maxValue">
+ <number>48</number>
+ </property>
+ <property name="minValue">
+ <number>16</number>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>kcfg_MenuButtonText</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_IconNone</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_Icon</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_MenuButtonNone</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_MenuButtonText</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_MenuButtonLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_Icon</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MenuButtonIcon</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>MenuButtonIcon</sender>
+ <signal>iconChanged(QString)</signal>
+ <receiver>Appearance</receiver>
+ <slot>iconChanged(QString)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">appearance.ui.h</include>
+</includes>
+<slots>
+ <slot>kcfg_ShowExpander_toggled( bool status )</slot>
+ <slot>iconChanged( QString icon )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kicondialog.h</includehint>
+</includehints>
+</UI>
diff --git a/src/appearance.ui.h b/src/appearance.ui.h
new file mode 100644
index 0000000..938c41a
--- /dev/null
+++ b/src/appearance.ui.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+void Appearance::kcfg_ShowExpander_toggled( bool status )
+{
+ kcfg_AlwaysCollapsed->setEnabled( status );
+}
+
+
+void Appearance::iconChanged( QString icon )
+{
+ kcfg_MenuButtonIcon->setText(icon);
+}
diff --git a/src/behaviour.ui b/src/behaviour.ui
new file mode 100644
index 0000000..b65cd3c
--- /dev/null
+++ b/src/behaviour.ui
@@ -0,0 +1,234 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Behaviour</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Behaviour</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>516</width>
+ <height>400</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>GeneralBehaviour</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>General behaviour</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_OverrideAltF1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Override alt+F1 keyboard shortcut (requires kicker restart)</string>
+ </property>
+ <property name="accel">
+ <string>Alt+O</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Pops up Tasty Menu instead of KMenu when the shortcut sequence Alt+F1 is pressed</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>81</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_ShowSaveSession</cstring>
+ </property>
+ <property name="text">
+ <string>Show save session functionalit&amp;y</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Under the menu that pops up when the button with user name is pressed a new item "Save current session" is added.
+It saves the current session informations like open applications and windows position. In order to use it you must set "Restore manually saved session" in the Session Manager Kcontrol module.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1">
+ <property name="name">
+ <cstring>kcfg_HideOneChild</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Hide groups with only one application</string>
+ </property>
+ <property name="accel">
+ <string>Alt+H</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="1">
+ <property name="name">
+ <cstring>kcfg_Alphabetical</cstring>
+ </property>
+ <property name="text">
+ <string>Show items in alpha&amp;betical order</string>
+ </property>
+ <property name="accel">
+ <string>Alt+B</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>SearchFieldBehaviour</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Search field behaviour</string>
+ </property>
+ <property name="alignment">
+ <set>AlignBottom</set>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="7" column="1">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>simpleSearch</cstring>
+ </property>
+ <property name="text">
+ <string>Si&amp;mple searches</string>
+ </property>
+ <property name="accel">
+ <string>Alt+M</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Filters the applications list</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>It displays in the first column all the applications whose name or description matches with the query you entered</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_KerryIntegration</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Kerry Beagle integration</string>
+ </property>
+ <property name="accel">
+ <string>Alt+K</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Perform queries with Kerry Beagle</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Perform queries with Kerry Beagle instead of using the first column.
+It needs Kerry Beagle up and running.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_StrigiIntegration</cstring>
+ </property>
+ <property name="text">
+ <string>Stri&amp;gi Integration</string>
+ </property>
+ <property name="accel">
+ <string>Alt+G</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Perform queries with Strigi</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Perform queries with Strigi instead of using the first column.
+It needs the Strigi Daemon up and running</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_NewAppsNotification</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Notify recently installed applications (requires kicker restart)</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/create_buttons.sh b/src/create_buttons.sh
new file mode 100644
index 0000000..7f787b2
--- /dev/null
+++ b/src/create_buttons.sh
@@ -0,0 +1 @@
+uic -o buttons.h -embed buttons pics/attach.png pics/detach.png
diff --git a/src/dmctl.cpp b/src/dmctl.cpp
new file mode 100644
index 0000000..9f24a52
--- /dev/null
+++ b/src/dmctl.cpp
@@ -0,0 +1,434 @@
+/*
+ Copyright (C) 2004 Oswald Buddenhagen <ossi@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Lesser GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "dmctl.h"
+
+#ifdef Q_WS_X11
+
+#include <klocale.h>
+#include <dcopclient.h>
+
+#include <qregexp.h>
+
+#include <X11/Xauth.h>
+#include <X11/Xlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static enum { Dunno, NoDM, NewKDM, OldKDM, GDM } DMType = Dunno;
+static const char *ctl, *dpy;
+
+DM::DM() : fd( -1 )
+{
+ const char *ptr;
+ struct sockaddr_un sa;
+
+ if (DMType == Dunno) {
+ if (!(dpy = ::getenv( "DISPLAY" )))
+ DMType = NoDM;
+ else if ((ctl = ::getenv( "DM_CONTROL" )))
+ DMType = NewKDM;
+ else if ((ctl = ::getenv( "XDM_MANAGED" )) && ctl[0] == '/')
+ DMType = OldKDM;
+ else if (::getenv( "GDMSESSION" ))
+ DMType = GDM;
+ else
+ DMType = NoDM;
+ }
+ switch (DMType) {
+ default:
+ return;
+ case NewKDM:
+ case GDM:
+ if ((fd = ::socket( PF_UNIX, SOCK_STREAM, 0 )) < 0)
+ return;
+ sa.sun_family = AF_UNIX;
+ if (DMType == GDM)
+ strcpy( sa.sun_path, "/tmp/.gdm_socket" );
+ else {
+ if ((ptr = strchr( dpy, ':' )))
+ ptr = strchr( ptr, '.' );
+ snprintf( sa.sun_path, sizeof(sa.sun_path),
+ "%s/dmctl-%.*s/socket",
+ ctl, ptr ? ptr - dpy : 512, dpy );
+ }
+ if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) {
+ ::close( fd );
+ fd = -1;
+ }
+ if (DMType == GDM)
+ GDMAuthenticate();
+ break;
+ case OldKDM:
+ {
+ QString tf( ctl );
+ tf.truncate( tf.find( ',' ) );
+ fd = ::open( tf.latin1(), O_WRONLY );
+ }
+ break;
+ }
+}
+
+DM::~DM()
+{
+ if (fd >= 0)
+ close( fd );
+}
+
+bool
+DM::exec( const char *cmd )
+{
+ QCString buf;
+
+ return exec( cmd, buf );
+}
+
+/**
+ * Execute a KDM/GDM remote control command.
+ * @param cmd the command to execute. FIXME: undocumented yet.
+ * @param buf the result buffer.
+ * @return result:
+ * @li If true, the command was successfully executed.
+ * @p ret might contain addional results.
+ * @li If false and @p ret is empty, a communication error occurred
+ * (most probably KDM is not running).
+ * @li If false and @p ret is non-empty, it contains the error message
+ * from KDM.
+ */
+bool
+DM::exec( const char *cmd, QCString &buf )
+{
+ bool ret = false;
+ int tl;
+ unsigned len = 0;
+
+ if (fd < 0)
+ goto busted;
+
+ if (::write( fd, cmd, (tl = strlen( cmd )) ) != tl) {
+ bust:
+ ::close( fd );
+ fd = -1;
+ busted:
+ buf.resize( 0 );
+ return false;
+ }
+ if (DMType == OldKDM) {
+ buf.resize( 0 );
+ return true;
+ }
+ for (;;) {
+ if (buf.size() < 128)
+ buf.resize( 128 );
+ else if (buf.size() < len * 2)
+ buf.resize( len * 2 );
+ if ((tl = ::read( fd, buf.data() + len, buf.size() - len)) <= 0) {
+ if (tl < 0 && errno == EINTR)
+ continue;
+ goto bust;
+ }
+ len += tl;
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = 0;
+ if (len > 2 && (buf[0] == 'o' || buf[0] == 'O') &&
+ (buf[1] == 'k' || buf[1] == 'K') && buf[2] <= 32)
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool
+DM::canShutdown()
+{
+ if (DMType == OldKDM)
+ return strstr( ctl, ",maysd" ) != 0;
+
+ QCString re;
+
+ if (DMType == GDM)
+ return exec( "QUERY_LOGOUT_ACTION\n", re ) && re.find("HALT") >= 0;
+
+ return exec( "caps\n", re ) && re.find( "\tshutdown" ) >= 0;
+}
+
+void
+DM::shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode, /* NOT Default */
+ const QString &bootOption )
+{
+ if (shutdownType == KApplication::ShutdownTypeNone)
+ return;
+
+ bool cap_ask;
+ if (DMType == NewKDM) {
+ QCString re;
+ cap_ask = exec( "caps\n", re ) && re.find( "\tshutdown ask" ) >= 0;
+ } else {
+ if (!bootOption.isEmpty())
+ return;
+ cap_ask = false;
+ }
+ if (!cap_ask && shutdownMode == KApplication::ShutdownModeInteractive)
+ shutdownMode = KApplication::ShutdownModeForceNow;
+
+ QCString cmd;
+ if (DMType == GDM) {
+ cmd.append( shutdownMode == KApplication::ShutdownModeForceNow ?
+ "SET_LOGOUT_ACTION " : "SET_SAFE_LOGOUT_ACTION " );
+ cmd.append( shutdownType == KApplication::ShutdownTypeReboot ?
+ "REBOOT\n" : "HALT\n" );
+ } else {
+ cmd.append( "shutdown\t" );
+ cmd.append( shutdownType == KApplication::ShutdownTypeReboot ?
+ "reboot\t" : "halt\t" );
+ if (!bootOption.isNull())
+ cmd.append( "=" ).append( bootOption.local8Bit() ).append( "\t" );
+ cmd.append( shutdownMode == KApplication::ShutdownModeInteractive ?
+ "ask\n" :
+ shutdownMode == KApplication::ShutdownModeForceNow ?
+ "forcenow\n" :
+ shutdownMode == KApplication::ShutdownModeTryNow ?
+ "trynow\n" : "schedule\n" );
+ }
+ exec( cmd.data() );
+}
+
+bool
+DM::bootOptions( QStringList &opts, int &defopt, int &current )
+{
+ if (DMType != NewKDM)
+ return false;
+
+ QCString re;
+ if (!exec( "listbootoptions\n", re ))
+ return false;
+
+ opts = QStringList::split( '\t', QString::fromLocal8Bit( re.data() ) );
+ if (opts.size() < 4)
+ return false;
+
+ bool ok;
+ defopt = opts[2].toInt( &ok );
+ if (!ok)
+ return false;
+ current = opts[3].toInt( &ok );
+ if (!ok)
+ return false;
+
+ opts = QStringList::split( ' ', opts[1] );
+ for (QStringList::Iterator it = opts.begin(); it != opts.end(); ++it)
+ (*it).replace( "\\s", " " );
+
+ return true;
+}
+
+void
+DM::setLock( bool on )
+{
+ if (DMType != GDM)
+ exec( on ? "lock\n" : "unlock\n" );
+}
+
+bool
+DM::isSwitchable()
+{
+ if (DMType == OldKDM)
+ return dpy[0] == ':';
+
+ if (DMType == GDM)
+ return exec( "QUERY_VT\n" );
+
+ QCString re;
+
+ return exec( "caps\n", re ) && re.find( "\tlocal" ) >= 0;
+}
+
+int
+DM::numReserve()
+{
+ if (DMType == GDM)
+ return 1; /* Bleh */
+
+ if (DMType == OldKDM)
+ return strstr( ctl, ",rsvd" ) ? 1 : -1;
+
+ QCString re;
+ int p;
+
+ if (!(exec( "caps\n", re ) && (p = re.find( "\treserve " )) >= 0))
+ return -1;
+ return atoi( re.data() + p + 9 );
+}
+
+void
+DM::startReserve()
+{
+ if (DMType == GDM)
+ exec("FLEXI_XSERVER\n");
+ else
+ exec("reserve\n");
+}
+
+bool
+DM::localSessions( SessList &list )
+{
+ if (DMType == OldKDM)
+ return false;
+
+ QCString re;
+
+ if (DMType == GDM) {
+ if (!exec( "CONSOLE_SERVERS\n", re ))
+ return false;
+ QStringList sess = QStringList::split( QChar(';'), re.data() + 3 );
+ for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ QStringList ts = QStringList::split( QChar(','), *it, true );
+ SessEnt se;
+ se.display = ts[0];
+ se.user = ts[1];
+ se.vt = ts[2].toInt();
+ se.session = "<unknown>";
+ se.self = ts[0] == ::getenv( "DISPLAY" ); /* Bleh */
+ se.tty = false;
+ list.append( se );
+ }
+ } else {
+ if (!exec( "list\talllocal\n", re ))
+ return false;
+ QStringList sess = QStringList::split( QChar('\t'), re.data() + 3 );
+ for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ QStringList ts = QStringList::split( QChar(','), *it, true );
+ SessEnt se;
+ se.display = ts[0];
+ if (ts[1][0] == '@')
+ se.from = ts[1].mid( 1 ), se.vt = 0;
+ else
+ se.vt = ts[1].mid( 2 ).toInt();
+ se.user = ts[2];
+ se.session = ts[3];
+ se.self = (ts[4].find( '*' ) >= 0);
+ se.tty = (ts[4].find( 't' ) >= 0);
+ list.append( se );
+ }
+ }
+ return true;
+}
+
+void
+DM::sess2Str2( const SessEnt &se, QString &user, QString &loc )
+{
+ if (se.tty) {
+ user = i18n("user: ...", "%1: TTY login").arg( se.user );
+ loc = se.vt ? QString("vt%1").arg( se.vt ) : se.display ;
+ } else {
+ user =
+ se.user.isEmpty() ?
+ se.session.isEmpty() ?
+ i18n("Unused") :
+ se.session == "<remote>" ?
+ i18n("X login on remote host") :
+ i18n("... host", "X login on %1").arg( se.session ) :
+ se.session == "<unknown>" ?
+ se.user :
+ i18n("user: session type", "%1: %2")
+ .arg( se.user ).arg( se.session );
+ loc =
+ se.vt ?
+ QString("%1, vt%2").arg( se.display ).arg( se.vt ) :
+ se.display;
+ }
+}
+
+QString
+DM::sess2Str( const SessEnt &se )
+{
+ QString user, loc;
+
+ sess2Str2( se, user, loc );
+ return i18n("session (location)", "%1 (%2)").arg( user ).arg( loc );
+}
+
+bool
+DM::switchVT( int vt )
+{
+ if (DMType == GDM)
+ return exec( QString("SET_VT %1\n").arg(vt).latin1() );
+
+ return exec( QString("activate\tvt%1\n").arg(vt).latin1() );
+}
+
+void
+DM::lockSwitchVT( int vt )
+{
+ if (switchVT( vt ))
+ kapp->dcopClient()->send( "kdesktop", "KScreensaverIface", "lock()", "" );
+}
+
+void
+DM::GDMAuthenticate()
+{
+ FILE *fp;
+ const char *dpy, *dnum, *dne;
+ int dnl;
+ Xauth *xau;
+
+ dpy = DisplayString( QPaintDevice::x11AppDisplay() );
+ if (!dpy) {
+ dpy = ::getenv( "DISPLAY" );
+ if (!dpy)
+ return;
+ }
+ dnum = strchr( dpy, ':' ) + 1;
+ dne = strchr( dpy, '.' );
+ dnl = dne ? dne - dnum : strlen( dnum );
+
+ /* XXX should do locking */
+ if (!(fp = fopen( XauFileName(), "r" )))
+ return;
+
+ while ((xau = XauReadAuth( fp ))) {
+ if (xau->family == FamilyLocal &&
+ xau->number_length == dnl && !memcmp( xau->number, dnum, dnl ) &&
+ xau->data_length == 16 &&
+ xau->name_length == 18 && !memcmp( xau->name, "MIT-MAGIC-COOKIE-1", 18 ))
+ {
+ QString cmd( "AUTH_LOCAL " );
+ for (int i = 0; i < 16; i++)
+ cmd += QString::number( (uchar)xau->data[i], 16 ).rightJustify( 2, '0');
+ cmd += "\n";
+ if (exec( cmd.latin1() )) {
+ XauDisposeAuth( xau );
+ break;
+ }
+ }
+ XauDisposeAuth( xau );
+ }
+
+ fclose (fp);
+}
+
+#endif // Q_WS_X11
diff --git a/src/dmctl.h b/src/dmctl.h
new file mode 100644
index 0000000..aadc89b
--- /dev/null
+++ b/src/dmctl.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2004,2005 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (C) 2005 Stephan Kulow <coolo@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Lesser GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DMCTL_H
+#define DMCTL_H
+
+#include <kapplication.h>
+
+struct SessEnt {
+ QString display, from, user, session;
+ int vt;
+ bool self:1, tty:1;
+};
+
+typedef QValueList<SessEnt> SessList;
+
+class DM {
+
+#ifdef Q_WS_X11
+
+public:
+ DM();
+ ~DM();
+
+ bool canShutdown();
+ void shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode,
+ const QString &bootOption = QString::null );
+
+ void setLock( bool on );
+
+ bool isSwitchable();
+ int numReserve();
+ void startReserve();
+ bool localSessions( SessList &list );
+ bool switchVT( int vt );
+ void lockSwitchVT( int vt );
+
+ bool bootOptions( QStringList &opts, int &dflt, int &curr );
+
+ static QString sess2Str( const SessEnt &se );
+ static void sess2Str2( const SessEnt &se, QString &user, QString &loc );
+
+private:
+ int fd;
+
+ bool exec( const char *cmd, QCString &ret );
+ bool exec( const char *cmd );
+
+ void GDMAuthenticate();
+
+#else // Q_WS_X11
+
+public:
+ DM() {}
+
+ bool canShutdown() { return false; }
+ void shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode,
+ const QString &bootOption = QString::null ) {}
+
+ void setLock( bool ) {}
+
+ bool isSwitchable() { return false; }
+ int numReserve() { return -1; }
+ void startReserve() {}
+ bool localSessions( SessList &list ) { return false; }
+ void switchVT( int vt ) {}
+
+ bool bootOptions( QStringList &opts, int &dflt, int &curr );
+
+#endif // Q_WS_X11
+
+}; // class DM
+
+#endif // DMCTL_H
diff --git a/src/menu.ui b/src/menu.ui
new file mode 100644
index 0000000..f666fd2
--- /dev/null
+++ b/src/menu.ui
@@ -0,0 +1,379 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Menu</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Menu</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>538</width>
+ <height>428</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Tasty Menu</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame9</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>PopupPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame" row="0" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>leftFrame</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="midLineWidth">
+ <number>0</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TastyListView" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>dynamicList</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>clearRecentButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Clear list</string>
+ </property>
+ <property name="accel">
+ <string>Alt+C</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>searchLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Se&amp;arch:</string>
+ </property>
+ <property name="textFormat">
+ <enum>AutoText</enum>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>searchLine</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1" rowspan="1" colspan="2">
+ <item>
+ <property name="text">
+ <string>Favourite applications</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Most used applications</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Recent applications</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Recent documents</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>menuModes</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use this dropdown menu to change the behaviour of the list below</string>
+ </property>
+ </widget>
+ <widget class="KListViewSearchLine" row="0" column="1">
+ <property name="name">
+ <cstring>searchLine</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QToolButton" row="0" column="2">
+ <property name="name">
+ <cstring>clearButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>showLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>menuModes</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TastyListView" row="1" column="1">
+ <property name="name">
+ <cstring>rootList</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="TastyListView" row="1" column="2">
+ <property name="name">
+ <cstring>childList</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QFrame" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>allAppsFrame</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>All Applications</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>detachButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Make this menu a normal window</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>runButton</cstring>
+ </property>
+ <property name="text">
+ <string>Ru&amp;n program...</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>If you know exatly how a program is named you can directly enter the application name</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>switchButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Start a new session, switch the active user or edit your user profile</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>lockButton</cstring>
+ </property>
+ <property name="text">
+ <string>L&amp;ock Session</string>
+ </property>
+ <property name="accel">
+ <string>Alt+O</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Lock the pc with a password if you are going away for a while</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>logoutButton</cstring>
+ </property>
+ <property name="text">
+ <string>Lo&amp;g Out...</string>
+ </property>
+ <property name="accel">
+ <string>Alt+G</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Logout, reboot or shoutdown the computer</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>TastyListView</class>
+ <header location="local">tastylistview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>searchLine</tabstop>
+ <tabstop>menuModes</tabstop>
+ <tabstop>dynamicList</tabstop>
+ <tabstop>rootList</tabstop>
+ <tabstop>childList</tabstop>
+ <tabstop>runButton</tabstop>
+ <tabstop>switchButton</tabstop>
+ <tabstop>lockButton</tabstop>
+ <tabstop>logoutButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>tastylistview.h</includehint>
+ <includehint>klistviewsearchline.h</includehint>
+ <includehint>tastylistview.h</includehint>
+ <includehint>tastylistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/src/menuhandler.cpp b/src/menuhandler.cpp
new file mode 100644
index 0000000..06ca863
--- /dev/null
+++ b/src/menuhandler.cpp
@@ -0,0 +1,1712 @@
+
+/***************************************************************************
+ * Copyright (C) 2006-2007 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kuser.h>
+#include <kstandarddirs.h>
+#include <kmimetype.h>
+#include <qfocusdata.h>
+#include <qstyle.h>
+#include <qfile.h>
+#include <qcursor.h>
+#include <kpopupmenu.h>
+#include <kdebug.h>
+
+
+#include "menuhandler.h"
+#include "buttons.h"
+
+MenuHandler::MenuHandler( QWidget *parent, Prefs *prefs, char *name, WFlags fl)
+ :QFrame(parent, name, fl ), searchMode(false)
+{
+
+ prefSkel = prefs;
+
+ //make a KServiceGroup to iterate the menu entries
+ KServiceGroup::Ptr service = KServiceGroup::root();
+
+ //Kicker config
+ QString kickerConfPath = locate("config", "kickerrc");
+ kickerConf = new KConfig(kickerConfPath);
+
+ kickerConfWatch = new KDirWatch( this );
+ kickerConfWatch->addFile(kickerConfPath);
+ connect( kickerConfWatch, SIGNAL(dirty(const QString&)), this,
+ SLOT(slotModKickerConf()) );
+ connect( kickerConfWatch, SIGNAL(dirty(const QString&)), this,
+ SIGNAL(kickerConfChanged()) );
+
+ if( _newAppsNotification = prefSkel->newAppsNotification() )
+ {
+ //init the old and new installed list
+ oldInstalledList = prefSkel->oldInstalledApps();
+ loadNewInstalledApps();
+ initOldInstalledApps(service);
+ //save the creation time
+ prefSkel->setOldInstalledAppsAge(time(0));
+ initNewInstalledApps(service);
+ if( newInstalledList.count() > 0 )
+ emit(newApplications(newInstalledList.count()));
+ prefSkel->setOldInstalledApps(oldInstalledList);
+ prefSkel->setNewInstalledApps( newInstalledList );
+ prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps );
+ }
+
+
+ //Main widget initialization
+ menu = new Menu(this, "tastyMenu");
+
+ MenuHandlerLayout = new QVBoxLayout( this, 0, 0, "MenuHandlerLayout");
+ MenuHandlerLayout->addWidget(menu);
+
+ readConfig();
+ setupColumns();
+
+ //Searchline...
+ iconLoader = KGlobal::iconLoader();
+ QPixmap icon;
+ if( QApplication::reverseLayout() )
+ icon = iconLoader->loadIcon("locationbar_erase", KIcon::Small);
+ else
+ icon = iconLoader->loadIcon("clear_left", KIcon::Small);
+ menu->clearButton->setIconSet(icon);
+
+ connect(menu->clearButton, SIGNAL(clicked()), menu->searchLine, SLOT (clear()) );
+
+ menu->detachButton->setIconSet(QPixmap(uic_findImage("detach.png")));
+ connect(menu->detachButton, SIGNAL(clicked()), this, SLOT (switchWindowMode()) );
+
+ menu->searchLine->setContextMenuEnabled(false);
+
+ //event filters for keyboard navigation
+ menu->clearButton->installEventFilter(this);
+ menu->searchLine->installEventFilter(this);
+ menu->menuModes->installEventFilter(this);
+ menu->runButton->installEventFilter(this);
+ menu->switchButton->installEventFilter(this);
+ menu->lockButton->installEventFilter(this);
+ menu->logoutButton->installEventFilter(this);
+
+ //action buttons
+ icon = iconLoader->loadIcon("exit", KIcon::Toolbar);
+ menu->logoutButton->setIconSet(icon);
+
+ icon = iconLoader->loadIcon("lock", KIcon::Toolbar);
+ menu->lockButton->setIconSet(icon);
+
+ icon = iconLoader->loadIcon("run", KIcon::Toolbar);
+ menu->runButton->setIconSet(icon);
+
+ icon = iconLoader->loadIcon("locationbar_erase", KIcon::Toolbar);
+ menu->clearRecentButton->setIconSet(icon);
+
+ setCaption("Tasty Menu");
+ setIcon(iconLoader->loadIcon("kmenu", KIcon::Panel));
+
+ //user icon and login
+ KUser *user = new KUser ();
+ QString loginName (user->loginName ());
+ QImage
+ userImage (locate
+ ("data", "/home/" + loginName + "/.face.icon"));
+ if( !userImage.isNull() )
+ {
+ userImage = userImage.smoothScale (KIcon::SizeSmallMedium, KIcon::SizeSmallMedium);
+ menu->switchButton->setIconSet(QPixmap(userImage));
+ }
+ menu->switchButton->setText(loginName);
+ sessionsMenu = new QPopupMenu();
+ menu->switchButton->setPopup(sessionsMenu);
+
+
+ initializeRecentlyUsed( );
+
+ populateList( service, menu->rootList, NULL, false );
+
+ //left/middle mouse button
+ connect (menu->dynamicList,
+ SIGNAL (activated(QListViewItem *, const QPoint & , int )), this,
+ SLOT (dynListClicked(QListViewItem *, const QPoint &, int)));
+ connect (menu->rootList,
+ SIGNAL (activated(QListViewItem *, const QPoint & , int )), this,
+ SLOT (rootListClicked(QListViewItem *, const QPoint &, int)));
+ connect (menu->childList,
+ SIGNAL (activated(QListViewItem *, const QPoint & , int )), this,
+ SLOT (childListClicked(QListViewItem *, const QPoint &, int)));
+
+ //right mouse button
+ connect (menu->dynamicList,
+ SIGNAL (contextMenuRequested(QListViewItem *, const QPoint & , int )), this,
+ SLOT (slotContextMenu(QListViewItem *, const QPoint &, int)));
+ connect (menu->rootList,
+ SIGNAL (contextMenuRequested(QListViewItem *, const QPoint & , int )), this,
+ SLOT (slotContextMenu(QListViewItem *, const QPoint &, int)));
+ connect (menu->childList,
+ SIGNAL (contextMenuRequested(QListViewItem *, const QPoint & , int )), this,
+ SLOT (slotContextMenu(QListViewItem *, const QPoint &, int)));
+
+ //don't open categories on mouseover on childlist
+ //menu->childList->setEasyOpen( true );
+
+ connect (menu->clearRecentButton, SIGNAL (clicked()), this, SLOT (clearDynList()));
+ connect (menu->logoutButton, SIGNAL (clicked()), this, SLOT (doLogout()));
+ connect (menu->lockButton, SIGNAL (clicked()), this, SLOT (doLock()));
+ connect (menu->runButton, SIGNAL (clicked()), this, SLOT (runDialog()));
+
+ connect( sessionsMenu, SIGNAL(aboutToShow()), SLOT(slotPopulateSessions()) );
+ connect( sessionsMenu, SIGNAL(activated(int)), SLOT(slotSessionActivated(int)) );
+
+
+ connect( menu->menuModes, SIGNAL(activated(int)), SLOT(menuModeChanged(int)) );
+ menuModeChanged(_menuMode);
+}
+
+
+MenuHandler::~MenuHandler()
+{
+}
+
+void MenuHandler::loadNewInstalledApps()
+{
+ //Notification for newly installed apps
+ xdgMenuLister = new KDirLister( );
+ KStandardDirs *standardDir=new KStandardDirs();
+ QStringList appDirs = standardDir->findDirs("xdgdata-apps", ".");
+ firstListing = 0;
+ for(QStringList::Iterator it = appDirs.begin(); it != appDirs.end(); ++it)
+ {
+ xdgMenuLister->openURL(*it, true);
+ /*HACK: links to kde programs are often installed in a kde subdirectory
+ of one of these, so i duplicate all the entries with entry+"kde/"*/
+ QString appDirWithKde = (*it)+"kde/";
+ if( QFile::exists(appDirWithKde) )
+ {
+ xdgMenuLister->openURL(appDirWithKde, true);
+ firstListing++;
+ }
+ }
+
+ firstListing += appDirs.count();
+ connect( xdgMenuLister, SIGNAL(newItems(const KFileItemList &)), this,
+ SLOT(slotApplicationsAdded(const KFileItemList &)) );
+ connect( xdgMenuLister, SIGNAL(deleteItem( KFileItem *)), this,
+ SLOT(slotApplicationRemoved()) );
+
+ xdgMenuWatch = new KDirWatch(this);
+ xdgMenuWatch->addFile(locateLocal("xdgconf-menu", "applications-kmenuedit.menu"));
+ //connect with slotApplicationRemoved() because we need to wait a while...
+ connect( xdgMenuWatch, SIGNAL(dirty(const QString&)), this,
+ SLOT(slotApplicationRemoved()) );
+
+ newInstalledList = prefSkel->newInstalledApps();
+ newInstalledTimeStamps = prefSkel->newInstalledAppsTimeStamps();
+
+ //expire old apps
+ for(uint i=0; i<newInstalledTimeStamps.count(); i++)
+ {
+ //127800 seconds = two days
+ if(time(0) - (uint)newInstalledTimeStamps[i] > 127800 )
+ {
+ newInstalledTimeStamps.remove(newInstalledTimeStamps.at(i));
+ newInstalledList.remove(newInstalledList.at(i));
+ }
+ }
+}
+
+void MenuHandler::setupColumns()
+{
+ menu->dynamicList->header()->hide();
+ menu->dynamicList->setResizeMode(QListView::AllColumns);
+ menu->dynamicList->addColumn("name");
+ menu->dynamicList->setShowToolTips(true);
+ menu->dynamicList->setSortColumn(-1);
+ menu->dynamicList->header()->setResizeEnabled(false);
+ menu->dynamicList->setHScrollBarMode(QScrollView::AlwaysOff);
+ menu->dynamicList->setActionIconSize( _actionIconSize );
+ menu->dynamicList->setRootIsDecorated( _showExpander );
+ //manage drag'n drop
+ menu->dynamicList->setAcceptDrops(true);
+ menu->dynamicList->setDragEnabled(true);
+ connect( menu->dynamicList, SIGNAL(moved()),
+ this, SLOT(dynListElemMoved()) );
+
+ menu->rootList->header()->hide();
+ menu->rootList->setResizeMode(QListView::AllColumns);
+ menu->rootList->addColumn("name");
+ menu->rootList->setSortColumn(-1);
+ menu->rootList->header()->setResizeEnabled(false);
+ menu->rootList->setHScrollBarMode(QScrollView::AlwaysOff);
+ menu->rootList->setHighLightGroups( false );
+ menu->rootList->setActionIconSize( _actionIconSize );
+ menu->rootList->setDragEnabled(true);
+
+ menu->childList->header()->hide();
+ menu->childList->setResizeMode(QListView::AllColumns);
+ menu->childList->addColumn("name");
+ menu->childList->setSortColumn(_alphabetical?0:-1);
+ menu->childList->header()->setResizeEnabled(false);
+ menu->childList->setHScrollBarMode(QScrollView::AlwaysOff);
+ menu->childList->setActionIconSize( _actionIconSize );
+ menu->childList->setRootIsDecorated( _showExpander );
+ menu->childList->setDragEnabled(true);
+}
+
+
+void MenuHandler::dynListElemMoved( )
+{
+ //very stupid: iterate the entire list and rewrite the favouriteList
+ favouriteList.clear();
+ QListViewItemIterator it( menu->dynamicList );
+
+ while ( it.current() )
+ {
+ TastyListViewItem *li = dynamic_cast<TastyListViewItem *>(it.current());
+
+ if( !li )
+ return;
+
+ favouriteList.append( li->getDeskopEntryPath() );
+ it++;
+ }
+
+ prefSkel->setFavouriteApps(favouriteList);
+ prefSkel->writeConfig();
+}
+
+
+bool MenuHandler::eventFilter( QObject *o, QEvent * e )
+{
+ if ( e->type() == QEvent::KeyPress )
+ {
+ QKeyEvent *keyEvent = (QKeyEvent *)e;
+ QFocusData *fData = focusData();
+ fData->home();
+
+ switch( keyEvent->key() )
+ {
+
+ case Qt::Key_Up:
+ if( dynamic_cast<QComboBox *>(o) )
+ return false;
+ fData->prev()->setFocus();
+ break;
+
+ case Qt::Key_Down:
+ {
+ if( dynamic_cast<QComboBox *>(o) )
+ return false;
+
+ //this is a workaround in order to set the focus on the
+ //right widget when the combobox is disabled
+ QWidget *nextWidget = fData->next();
+ if( nextWidget->isEnabled() )
+ nextWidget->setFocus();
+ else
+ fData->next()->setFocus();
+ }
+ break;
+
+ case Qt::Key_Right:
+ if( dynamic_cast<KListViewSearchLine *>(o) )
+ return false;
+ fData->next()->setFocus();
+ break;
+
+ case Qt::Key_Left:
+ if( dynamic_cast<KListViewSearchLine *>(o) )
+ return false;
+ fData->prev()->setFocus();
+ break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ {
+ //only filter enter on search line
+ if( o != menu->searchLine )
+ return false;
+
+ QListViewItem *listItem = NULL;
+ //execute the only list item when there is exactly one
+ QListViewItemIterator it( menu->dynamicList,
+ QListViewItemIterator::Visible);
+ //listItem = it.current();
+ int count = 0;
+ //ensure the first level have only one result
+ while ( it.current() )
+ {
+ if( it.current()->childCount() == 0 )
+ {
+ count++;
+ listItem = it.current();
+ }
+ kdDebug() << "current: " << count << " " << it.current()->text(0);
+ if( count > 1 )
+ return false;
+ it++;
+ }
+
+ if( listItem )
+ {
+ dynListClicked(listItem, QPoint(0,0), 0);
+ menu->searchLine->clear();
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ break;
+ }
+ return true;
+ }
+ //for some reasons clicking with the right mouse button on the searchline everything crashes...
+/* else if( e->type() == QEvent::MouseButtonPress && o == menu->searchLine )
+ {return true;
+ QMouseEvent *mouseEvent = (QMouseEvent *)e;
+
+ if( mouseEvent->button() != QMouseEvent::RightButton )
+ return true;
+
+ if( menu->searchLine->text().length() < 4 )
+ return true;
+ else
+ return false;
+ }*/
+ else
+ return false;
+}
+
+
+void MenuHandler::readConfig()
+{
+ _menuMode = prefSkel->menuMode();
+ if( _menuMode < 0 )
+ _menuMode = 0;
+ menu->menuModes->setCurrentItem(_menuMode);
+
+ _currentCategory = prefSkel->currentCategory();
+
+ kickerConf->setGroup("menus");
+ _numRecentEntries = kickerConf->readNumEntry("NumVisibleEntries", 5);
+
+ _hideOneChild = prefSkel->hideOneChild();
+ _alphabetical = prefSkel->alphabetical();
+
+ favouriteList = prefSkel->favouriteApps();
+ if( favouriteList.isEmpty() )
+ {
+ favouriteList.append(locate("xdgdata-apps","kde/konqbrowser.desktop"));
+ favouriteList.append(locate("xdgdata-apps","kde/KMail.desktop"));
+ favouriteList.append(locate("xdgdata-apps","kde/Help.desktop"));
+ }
+
+ _showExpander = prefSkel->showExpander();
+ _alwaysCollapsed = prefSkel->alwaysCollapsed();
+
+ _displaySubText = prefSkel->displaySubText();
+
+ _iconSize1 = prefSkel->iconSize1();
+ if( _iconSize1 < 16 || _iconSize1 > 64 )
+ _iconSize1 = 22;
+ _iconSize2 = prefSkel->iconSize2();
+ if( _iconSize2 < 16 || _iconSize2 > 64 )
+ _iconSize2 = 22;
+ _iconSize3 = prefSkel->iconSize3();
+ if( _iconSize3 < 16 || _iconSize3 > 64 )
+ _iconSize3 = 22;
+
+ _actionIconSize = prefSkel->actionIconSize();
+ if( _actionIconSize > _iconSize1 )
+ _actionIconSize = _iconSize1;
+
+ //menu size
+ _menuWidth = 100.0/prefSkel->menuWidth();
+ _menuHeight = 100.0/prefSkel->menuHeight();
+ QRect r = QDesktopWidget().screenGeometry(this);
+ int w = (int)(r.width()/_menuWidth);
+ int h = (int)(r.height()/_menuHeight);
+ resize(w,h);
+
+ _kerryIntegration = prefSkel->kerryIntegration();
+ _strigiIntegration = prefSkel->strigiIntegration();
+
+ _isNormalWindow = prefSkel->isNormalWindow();
+ if( _isNormalWindow )
+ {
+ menu->detachButton->setIconSet(QPixmap(uic_findImage("attach.png")));
+ QToolTip::add( menu->detachButton, tr2i18n( "Make this window a popup menu" ) );
+ }
+ else
+ {
+ menu->detachButton->setIconSet(QPixmap(uic_findImage("detach.png")));
+ QToolTip::add( menu->detachButton, tr2i18n( "Make this menu a normal window" ) );
+ }
+
+ // disconnect(menu->searchLine, 0, 0, 0);
+ if( !_kerryIntegration && !_strigiIntegration )
+ {
+ //menu->searchLine->setListView((KListView *)(menu->dynamicList));
+ disconnect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (kerrySearch( const QString &)) );
+ disconnect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (strigiSearch( const QString &)) );
+ connect(menu->searchLine, SIGNAL(textChanged( const QString &)),
+ this, SLOT (initializeSearch( const QString &)) );
+ }
+ else if( _kerryIntegration )
+ {
+ menu->searchLine->setListView(NULL);
+ menu->searchLine->setEnabled(true);
+ disconnect(menu->searchLine, SIGNAL(textChanged( const QString &)),
+ this, SLOT (initializeSearch( const QString &)) );
+ disconnect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (strigiSearch( const QString &)) );
+ connect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (kerrySearch( const QString &)) );
+ menu->searchLine->setContextMenuEnabled(false);
+ }
+ else //strigi
+ {
+ menu->searchLine->setListView(NULL);
+ menu->searchLine->setEnabled(true);
+ disconnect(menu->searchLine, SIGNAL(textChanged( const QString &)),
+ this, SLOT (initializeSearch( const QString &)) );
+ disconnect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (kerrySearch( const QString &)) );
+ connect(menu->searchLine, SIGNAL(returnPressed( const QString &)),
+ this, SLOT (strigiSearch( const QString &)) );
+ menu->searchLine->setContextMenuEnabled(false);
+ }
+}
+
+void MenuHandler::updateConfig()
+{
+ readConfig();
+
+ menu->dynamicList->setActionIconSize( _actionIconSize );
+ menu->rootList->setActionIconSize( _actionIconSize );
+ menu->childList->setActionIconSize( _actionIconSize );
+
+ menu->dynamicList->setRootIsDecorated( _showExpander );
+ menu->childList->setRootIsDecorated( _showExpander );
+
+ menuModeChanged( _menuMode );
+ KServiceGroup::Ptr service = KServiceGroup::root();
+ menu->rootList->clear();
+ populateList( service, menu->rootList, NULL, false );
+}
+
+
+void MenuHandler::mousePressEvent( QMouseEvent *e)
+{
+ if(static_cast<QWidget *>(parent())->hasMouse())
+ {
+ close();
+ }
+ else if(!_isNormalWindow && !(rect().contains(e->pos())) )
+ {
+ hide();
+ QTimer::singleShot(200, this,SLOT(close()));
+ }
+}
+
+void MenuHandler::closeEvent ( QCloseEvent *e)
+{
+ e=e;
+
+ if( _isNormalWindow )
+ {
+ prefSkel->setNormalWindowWidth(width());
+ prefSkel->setNormalWindowHeight(height());
+ prefSkel->setNormalWindowX(x());
+ prefSkel->setNormalWindowY(y());
+ prefSkel->writeConfig();
+ }
+
+ //HACK: I wait a little bit to permit closing the menu
+ // when user clicks on the menu button again
+ QTimer::singleShot(50, this, SLOT(hide()));
+ emit(hidden());
+}
+
+void MenuHandler::popup(QPoint pos)
+{
+ if(isVisible())
+ {
+ close();
+ return;
+ }
+
+ menu->searchLine->setFocus();
+
+ int w;
+ int h;
+ if( !_isNormalWindow )
+ {
+ QRect r = QDesktopWidget().screenGeometry(this);
+ w = (int)(r.width()/_menuWidth);
+ h = (int)(r.height()/_menuHeight);
+ }
+ else
+ {
+ w = prefSkel->normalWindowWidth();
+ h = prefSkel->normalWindowHeight();
+ }
+
+ //the only way to make things proportioned
+ menu->leftFrame->setMaximumWidth( (int)((w-24)/3) );
+ menu->allAppsFrame->setMaximumHeight(menu->clearButton->height());
+
+ if( !_isNormalWindow )
+ move(pos);
+ else
+ move(prefSkel->normalWindowX(), prefSkel->normalWindowY());
+
+ resize(w,h);
+
+ show();
+}
+
+void MenuHandler::initOldInstalledApps(KServiceGroup::Ptr group)
+{
+ if( !group || !group->isValid() )
+ return;
+
+ //expires at 639000 seconds = 10 days
+ if( !prefSkel->oldInstalledApps().empty() ||
+ (time(0) - (uint)prefSkel->oldInstalledAppsAge() < 639000 )
+ )
+ return;
+
+ KServiceGroup::List list = group->entries(true, true, true, false);
+ for (KServiceGroup::List::ConstIterator it = list.begin ();
+ it != list.end (); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if( p->isType( KST_KServiceGroup ) )
+ {
+ KServiceGroup *g = static_cast < KServiceGroup * > ( p );
+ if( g ->childCount() > 0 )
+ initOldInstalledApps(g);
+ }
+ else
+ {
+ KService *s = static_cast < KService * >(p);
+
+ oldInstalledList.append(s->desktopEntryPath());
+ }
+ }
+}
+
+void MenuHandler::initNewInstalledApps(KServiceGroup::Ptr group)
+{
+ if( !group || !group->isValid() )
+ return;
+ if( oldInstalledList.empty() )
+ return;
+
+ KServiceGroup::List list = group->entries(true, true, true, false);
+ for (KServiceGroup::List::ConstIterator it = list.begin ();
+ it != list.end (); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if( p->isType( KST_KServiceGroup ) )
+ {
+ KServiceGroup *g = static_cast < KServiceGroup * > ( p );
+ if( g ->childCount()>0 )
+ initNewInstalledApps(g);
+ }
+ else
+ {
+ KService *s = static_cast < KService * > ( p );
+
+
+ QString path(s->desktopEntryPath());
+ if( oldInstalledList.findIndex(path) == -1 &&
+ newInstalledList.findIndex(path) == -1 )
+ {
+ newInstalledList.append(path);
+ newInstalledTimeStamps.append(time(0));
+ oldInstalledList.append(path);
+ }
+ }
+ }
+}
+
+
+bool MenuHandler::searchNewItems(KServiceGroup::Ptr group)
+{
+ if( !group || !group->isValid() )
+ return false;
+
+ if( newInstalledList.count() <= 0 )
+ return false;
+
+ KServiceGroup::List list = group->entries(true, true, true, false);
+ for (KServiceGroup::List::ConstIterator it = list.begin ();
+ it != list.end (); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if( p->isType( KST_KServiceGroup ) )
+ {
+ KServiceGroup *g = static_cast < KServiceGroup * > ( p );
+ if( g ->childCount()<=0 )
+ continue;
+
+ if(searchNewItems(g))
+ return true;
+ }
+ else
+ {
+ KService *s = static_cast < KService * >(p);
+
+
+ /*kdDebug() << group->relPath() << ": "<< s->desktopEntryPath()
+ <<(( newInstalledList.findIndex(s->desktopEntryPath()) != -1 )
+ ?" present":" not present")<< endl;*/
+ if( newInstalledList.findIndex(s->desktopEntryPath()) != -1 )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*KServiceGroup::List MenuHandler::getServiceGroupList( KServiceGroup *serviceGroup )
+{
+ QString key(serviceGroup->directoryEntryPath());
+
+ if( sListMap.contains(key) )
+ return sListMap[key];
+ else
+ {
+ KServiceGroup::List list = serviceGroup->entries(true, true, true, false);
+ sListMap[key] = list;
+ return list;
+ }
+}*/
+
+void MenuHandler::populateList( KServiceGroup *serviceGroup, TastyListView *listView,
+ TastyListViewItem *listItemFather,
+ bool recursive, const QString & query )
+{
+ if( !serviceGroup || !serviceGroup->isValid() )
+ return;
+ serviceGroup->setShowEmptyMenu(false);
+ //KServiceGroup::List list = serviceGroup->entries(true, true, true, false);
+
+ KServiceGroup::List list = serviceGroup->entries(true, true, true, false);
+
+ TastyListViewItem *prevListItem = NULL;
+
+ for (KServiceGroup::List::ConstIterator it = list.begin ();
+ it != list.end (); it++)
+ {
+ KSycocaEntry *p = (*it);
+
+ int iconSize;
+ if( listView && listView == menu->rootList
+ || listItemFather && listItemFather->listView() == menu->rootList )
+ iconSize = _iconSize2;
+ else if( listView && listView == menu->childList
+ || listItemFather && listItemFather->listView() == menu->childList)
+ iconSize = _iconSize3;
+ else
+ iconSize = _iconSize1;
+
+ if( p->isType( KST_KServiceGroup ) )
+ {
+ //KServiceGroup::Ptr g (static_cast < KServiceGroup * >(p));
+ KServiceGroup *g = static_cast < KServiceGroup * > ( p );
+ if( g ->childCount()<=0 || (g->name().at(0) == '.') )
+ continue;
+
+ g->setShowEmptyMenu(false);
+
+ int numChilds = g->childCount();
+ //FIXME: useless?
+ if(numChilds == 0)
+ continue;
+
+ QPixmap iconPix = iconLoader->loadIcon(g->icon(), KIcon::Toolbar,iconSize);
+
+ if ( iconPix.height () != iconSize)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( iconSize, iconSize);
+ iconPix = QPixmap (img);
+ }
+ }
+
+ TastyListViewItem *listItem;
+ if( listView )
+ listItem = new TastyListViewItem( listView, prevListItem,
+ !g->caption().isEmpty()?g->caption()
+ :g->name().section('/', -2));
+ else
+ listItem = new TastyListViewItem( listItemFather, prevListItem,
+ !g->caption().isEmpty()?g->caption()
+ :g->name().section('/', -2));
+
+ listItem->setPath( g->relPath() );
+ listItem->setType( TastyListViewItem::ServiceGroup );
+ //OpenGrup only on menu->rootList
+ if( listView == menu->rootList )
+ listItem->setActionType( TastyListViewItem::OpenGroup );
+ else
+ listItem->setActionType( TastyListViewItem::Collapse );
+
+ prevListItem = listItem;
+
+ listItem->setPixmap(0, iconPix);
+
+ //avoiding to display empty categories or with only one child (very common in SUSE)
+ if( (!_hideOneChild && numChilds > 0) || numChilds > 1 )
+ {
+ if( listView )
+ {
+ listView->insertItem( listItem );
+ if( _currentCategory == listItem->text(0) && listView == menu->rootList )
+ {
+ listView->setCurrentItem(listItem);
+ listView->setOpenItem(static_cast<QListViewItem *>(listItem));
+ rootListClicked(listItem, QPoint(0,0), 0);
+ }
+ if(searchNewItems(g))
+ listItem->setHighLight(true);
+ }
+ else if(listItemFather)
+ listItemFather->insertItem( listItem );
+
+ if( recursive )
+ populateList( g, NULL, listItem, true, query);
+
+ //the left column is always open
+ if( listView == menu->dynamicList ||
+ (listItemFather && listItemFather->listView()==menu->dynamicList))
+ listItem->setOpen( true );
+ else
+ listItem->setOpen( !_alwaysCollapsed );
+
+ if( listItem->getActionType() == TastyListViewItem::Expand &&
+ listItem->isOpen() )
+ listItem->setActionType( TastyListViewItem::Collapse );
+ else if( listItem->getActionType() == TastyListViewItem::Collapse &&
+ !listItem->isOpen() )
+ listItem->setActionType( TastyListViewItem::Expand );
+ }
+ else if( recursive )
+ {
+ if( listView )
+ populateList( g, listView, NULL, true, query);
+
+ else if(listItemFather)
+ populateList( g, NULL, listItemFather, true, query);
+
+ delete listItem;
+ }
+
+ }
+ else //The entry is a Service
+ {
+ KService *s = static_cast < KService * >(p);
+
+ if( s->name().at(0) == '.' )
+ continue;
+
+ const bool isSeparator = s->name() == "separator";
+
+
+ //Name and comment
+ QString itemName = s->name();
+ QString subText= QString();
+ if( !isSeparator )
+ {
+ if( s->comment() != NULL && !s->comment().isEmpty() )
+ subText = s->comment();
+ else if( s->genericName() && !s->genericName().isEmpty() )
+ subText = s->genericName();
+ }
+
+ //Have we done a query? (this improves query speed)
+ if( query != NULL
+ && !itemName.contains(query, false)
+ && !subText.contains(query, false) )
+ continue;
+
+ TastyListViewItem *listItem;
+
+ if( isSeparator )
+ {
+ if( _alphabetical )
+ continue;
+
+ if(listView)
+ {
+ listItem = new TastyListViewItem( listView, prevListItem, "separator" );
+ listView->insertItem( listItem );
+ }
+ else if(listItemFather)
+ {
+ listItem = new TastyListViewItem( listItemFather, prevListItem, "separator" );
+ listItemFather->insertItem( listItem );
+ }
+ else
+ return;
+
+ prevListItem = listItem;
+ listItem->setSelectable(false);
+ continue;
+ }
+
+ if( listView )
+ listItem = new TastyListViewItem( listView, prevListItem, itemName );
+ else
+ listItem = new TastyListViewItem( listItemFather, prevListItem, itemName );
+
+ listItem->setDisplaySubText(_displaySubText);
+ listItem->setPath( serviceGroup->relPath() );
+ listItem->setDeskopEntryPath( s->desktopEntryPath() );
+ listItem->setMenuId( s->menuId() );
+ listItem->setType( TastyListViewItem::Service );
+ listItem->setActionType( TastyListViewItem::AddBookMark );
+
+ listItem->setText(0,itemName);
+ listItem->setSubText(subText);
+
+ prevListItem = listItem;
+
+ QPixmap iconPix = s->pixmap( KIcon::Toolbar, iconSize );
+ if ( iconPix.height () != iconSize)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( iconSize, iconSize);
+ iconPix = QPixmap (img);
+ }
+ }
+ listItem->setPixmap(0, iconPix);
+
+ if( listView )
+ {
+ listView->insertItem( listItem );
+ }
+ else if(listItemFather)
+ {
+ listItemFather->insertItem( listItem );
+ }
+ if( newInstalledList.findIndex(s->desktopEntryPath()) != -1 )
+ listItem->setHighLight(true);
+ }
+
+ }
+
+}
+
+
+void MenuHandler::initializeRecentlyUsed( )
+{
+
+ recentlyUsedMap.clear();
+ moreUsedList.clear();
+
+ kickerConf->reparseConfiguration();
+ kickerConf->setGroup("menus");
+ QStringList recentUsedList = QStringList::split(',',kickerConf->readEntry("RecentAppsStat"));
+
+ for (QStringList::ConstIterator it = recentUsedList.begin();
+ it != recentUsedList.end(); ++it )
+ {
+ QString item = (*it);
+
+ QString desktopPath = item.section(' ',2,2);
+ if(desktopPath.isEmpty() || !QFile::exists(desktopPath))
+ continue;
+
+ recentlyUsedMap[-item.section(' ',1,1).toULong()] = desktopPath;
+ moreUsedList.append(desktopPath);
+
+ }
+
+}
+
+void MenuHandler::setupDynList( MenuMode mode )
+{
+ /*( mode == RecentDocuments
+ || mode == MoreUsed
+ || mode == RecentlyUsed )*/
+ if( mode != Favourites )
+ menu->clearRecentButton->show();
+ else
+ menu->clearRecentButton->hide();
+
+ currentMenuMode = mode;
+ menu->dynamicList->setAcceptDrops( mode == Favourites );
+}
+
+void MenuHandler::fillRecentDocuments( )
+{
+ menu->dynamicList->clear();
+ setupDynList( RecentDocuments );
+
+ QStringList recentDocsList = KRecentDocument::recentDocuments();
+
+ TastyListViewItem *listItem = NULL;
+
+ if( recentDocsList.isEmpty() )
+ return;
+
+ for (QStringList::Iterator it = recentDocsList.begin();
+ it != recentDocsList.end(); ++it )
+ {
+ KDesktopFile *f= new KDesktopFile(*it, true /* read only */);
+
+ if( !f )
+ continue;
+
+ listItem = new TastyListViewItem( menu->dynamicList, listItem, f->readName() );
+ listItem->setMultiLinesEnabled(false);
+
+ listItem->setDeskopEntryPath(*it);
+ listItem->setType( TastyListViewItem::DesktopFile );
+
+ QPixmap iconPix = iconLoader->loadIcon(f->readIcon(), KIcon::Panel, _iconSize1);
+ if ( iconPix.height () > _iconSize1)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( _iconSize1, _iconSize1);
+ iconPix = QPixmap (img);
+ }
+ }
+ listItem->setPixmap(0, iconPix);
+
+ menu->dynamicList->insertItem( listItem );
+ }
+
+}
+
+
+void MenuHandler::fillMoreUsed( )
+{
+ menu->dynamicList->clear();
+ setupDynList( MoreUsed );
+
+ int iteration = 0;
+
+ TastyListViewItem *listItem = NULL;
+
+ for (QStringList::Iterator it = moreUsedList.begin();
+ it != moreUsedList.end(); ++it )
+ {
+ //FIXME: yeah, I know, this is U G L Y :-)
+ if( iteration++ >= _numRecentEntries )
+ break;
+
+ KService::Ptr s = KService::serviceByDesktopPath(*it);
+ if( !s )
+ continue;
+
+ listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name());
+ listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() );
+
+ listItem->setDeskopEntryPath( s->desktopEntryPath() );
+ listItem->setType( TastyListViewItem::Service );
+ listItem->setActionType( TastyListViewItem::AddBookMark );
+ listItem->setDisplaySubText(_displaySubText);
+
+
+ QPixmap iconPix = s->pixmap( KIcon::Toolbar, _iconSize1 );
+ if( !iconPix.isNull() )
+ {
+ if ( iconPix.height () != _iconSize1)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( _iconSize1, _iconSize1);
+ iconPix = QPixmap (img);
+ }
+ }
+ listItem->setPixmap(0, iconPix);
+ }
+
+ menu->dynamicList->insertItem( listItem );
+ }
+
+}
+
+//FIXME: avoid the ugly code duplication
+void MenuHandler::fillRecentlyUsed( )
+{
+ menu->dynamicList->clear();
+ setupDynList( RecentlyUsed );
+
+ int iteration = 0;
+ TastyListViewItem *listItem = NULL;
+
+ for (RecentlyUsedMap::Iterator it = recentlyUsedMap.begin();
+ it != recentlyUsedMap.end(); ++it )
+ {
+ //FIXME: yeah, I know, this is U G L Y :-)
+ if( iteration++ >= _numRecentEntries )
+ break;
+
+ KService::Ptr s = KService::serviceByDesktopPath(it.data());
+ if( !s )
+ continue;
+
+ listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name());
+ listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() );
+
+ listItem->setDeskopEntryPath( s->desktopEntryPath() );
+ listItem->setType( TastyListViewItem::Service );
+ listItem->setActionType( TastyListViewItem::AddBookMark );
+ listItem->setDisplaySubText(_displaySubText);
+
+
+ QPixmap iconPix = s->pixmap( KIcon::Toolbar, _iconSize1 );
+ if( !iconPix.isNull() )
+ {
+ if ( iconPix.height () != _iconSize1)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( _iconSize1, _iconSize1);
+ iconPix = QPixmap (img);
+ }
+ }
+ listItem->setPixmap(0, iconPix);
+ }
+
+ menu->dynamicList->insertItem( listItem );
+ }
+
+}
+
+
+//FIXME: avoid the ugly code duplication
+void MenuHandler::fillFavourites( )
+{
+ menu->dynamicList->clear();
+ setupDynList( Favourites );
+
+ TastyListViewItem *listItem = NULL;
+
+ for (QStringList::Iterator it = favouriteList.begin();
+ it != favouriteList.end(); ++it )
+ {
+
+ KService::Ptr s = KService::serviceByDesktopPath(*it);
+ if( !s )
+ continue;
+ listItem = new TastyListViewItem( menu->dynamicList, listItem, s->name());
+ listItem->setSubText(!(s->comment().isEmpty())?s->comment():s->genericName() );
+
+ listItem->setDeskopEntryPath( s->desktopEntryPath() );
+ listItem->setType( TastyListViewItem::Service );
+ listItem->setActionType( TastyListViewItem::RemoveBookMark );
+ listItem->setDisplaySubText(_displaySubText);
+
+
+ QPixmap iconPix = s->pixmap( KIcon::Toolbar, _iconSize1 );
+ if ( iconPix.height () > _iconSize1)
+ {
+ QImage img = iconPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( _iconSize1, _iconSize1);
+ iconPix = QPixmap (img);
+ }
+ }
+ listItem->setPixmap(0, iconPix);
+
+ menu->dynamicList->insertItem( listItem );
+ }
+
+}
+
+
+
+void MenuHandler::slotModKickerConf()
+{
+ kickerConf->reparseConfiguration();
+ initializeRecentlyUsed( );
+ if( currentMenuMode == MoreUsed )
+ fillMoreUsed();
+ else if( currentMenuMode == RecentlyUsed )
+ fillRecentlyUsed();
+}
+
+
+void MenuHandler::slotApplicationsAdded(const KFileItemList & newItems)
+{
+
+ if( firstListing > 0 )
+ {
+ firstListing--;
+ return;
+ }
+
+ //avoiding to build a mammoth list...
+ if( newItems.count() > 15 )
+ return;
+
+ for(KFileItemListIterator it(newItems); it.current(); ++it)
+ {
+ KFileItem *item = (*it);
+ QString path(item->url().path());
+
+ kdDebug() << "new item: " << item->name() << endl;
+ //ignore items already here
+ if( oldInstalledList.findIndex(path) == -1 )
+ {
+ newInstalledList.append(path);
+ newInstalledTimeStamps.append( time(0) );
+ oldInstalledList.append(path);
+ }
+ }
+
+ prefSkel->setNewInstalledApps( newInstalledList );
+ prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps );
+ prefSkel->setOldInstalledApps( oldInstalledList );
+
+ emit(newApplications(newInstalledList.count()));
+
+ //It's necessary to wait some seconds, otherwise apps won't be listed
+ //I do it two times for being sure, because I still haven't the clear idea
+ //where the right files to watch are...
+ QTimer::singleShot(15000, this, SLOT(slotUpdateApplications()));
+}
+
+
+void MenuHandler::slotApplicationRemoved()
+{
+ QTimer::singleShot(15000, this, SLOT(slotUpdateApplications()));
+ slotUpdateApplications();
+}
+
+void MenuHandler::slotUpdateApplications()
+{
+ KRun::runCommand ("kbuildsycoca");
+ prefSkel->writeConfig();
+ menu->rootList->clear();
+ KServiceGroup::Ptr service = KServiceGroup::root();
+
+ populateList( service, menu->rootList, NULL, false );
+}
+
+void MenuHandler::listClicked( TastyListViewItem * listItem, const QPoint & coord )
+{
+ if( !listItem )
+ return;
+
+ //exit if the user clicked on an empty area
+ if( coord.y() != 0 &&
+ (listItem->itemPos( )+ listItem->height()) < coord.y() )
+ return;
+
+ int x = coord.x();
+
+ QString servicePath = listItem->getDeskopEntryPath();
+
+ switch( listItem->getType() )
+ {
+ case TastyListViewItem::Service:
+ {
+ //These paranoid checks seems to be needed
+ if( !listItem->listView() )
+ return;
+ TastyListView *lv = dynamic_cast<TastyListView *>(listItem->listView());
+ if( !lv )
+ return;
+ if( x >= (lv->visibleWidth() - lv->getActionIconSpace()) )
+ {
+ switch( listItem->getActionType() )
+ {
+ case TastyListViewItem::AddBookMark:
+ favouriteList.remove(servicePath);
+ favouriteList.append(servicePath);
+ prefSkel->setFavouriteApps(favouriteList);
+ prefSkel->writeConfig();
+ if( menu->menuModes->currentItem() == 0 )
+ fillFavourites( );
+ return;
+
+ case TastyListViewItem::RemoveBookMark:
+ favouriteList.remove(servicePath);
+ prefSkel->setFavouriteApps(favouriteList);
+ prefSkel->writeConfig();
+ if( menu->menuModes->currentItem() == 0 )
+ fillFavourites( );
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ //if the item was highlighted get it back to normal and remove it from recently installed
+ listItem->setHighLight(false);
+ int index=newInstalledList.findIndex(servicePath);
+ if( index != -1 )
+ {
+ newInstalledList.remove(newInstalledList.at(index));
+ newInstalledTimeStamps.remove(newInstalledTimeStamps.at(index));
+ prefSkel->setNewInstalledApps( newInstalledList );
+ prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps );
+ emit(newApplications(newInstalledList.count()));
+ //remove the highlight from the rootList, at the moment very costly
+ slotUpdateApplications();
+ }
+
+ int started = KApplication::startServiceByDesktopPath( servicePath );
+ if( !started )
+ {
+ DCOPRef kickerKMenuIface ("kicker", "KMenu");
+
+ kickerKMenuIface.call("slotServiceStartedByStorageId(QString,QString)", "tastymenu", servicePath);
+ if( (currentMenuMode == MoreUsed
+ || currentMenuMode == RecentlyUsed)
+ && !searchMode)
+ slotModKickerConf();
+ if( !_isNormalWindow )
+ close();
+ }
+ break;
+ }
+
+ case TastyListViewItem::ServiceGroup:
+ {
+ //open, collapse or expand?
+ switch( listItem->getActionType() )
+ {
+ case TastyListViewItem::Expand:
+ //avoiding setOpen when the user clicks on the three handle
+ if( !listItem->xOnDecoration(x) )
+ listItem->setOpen(true);
+ if(listItem->isOpen())
+ listItem->setActionType( TastyListViewItem::Collapse );
+ break;
+ case TastyListViewItem::Collapse:
+ if( !listItem->xOnDecoration(x) )
+ listItem->setOpen(false);
+ if(!listItem->isOpen())
+ listItem->setActionType( TastyListViewItem::Expand );
+ break;
+ case TastyListViewItem::OpenGroup:
+ default:
+ {
+ KServiceGroup::Ptr serviceGroup = KServiceGroup::group( listItem->getPath() );
+ if( serviceGroup )
+ {
+ menu->childList->clear();
+ populateList( serviceGroup, menu->childList, NULL, true );
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ case TastyListViewItem::DesktopFile:
+ {
+ KDEDesktopMimeType::run(servicePath, true);
+ if( !_isNormalWindow )
+ close();
+ break;
+ }
+
+ default:
+ return;
+ }
+
+}
+
+void MenuHandler::dynListClicked( QListViewItem * listItem, const QPoint & coord, int c )
+{
+ c=c;
+ if( !listItem )
+ return;
+
+ TastyListViewItem *tastyListItem = dynamic_cast<TastyListViewItem *>(listItem);
+ if( !tastyListItem )
+ return;
+
+ listClicked( static_cast<TastyListViewItem *>(listItem), coord );
+}
+
+void MenuHandler::childListClicked( QListViewItem * listItem, const QPoint & coord, int c )
+{
+ c=c;
+ if( !listItem )
+ return;
+
+ TastyListViewItem *tastyListItem = dynamic_cast<TastyListViewItem *>(listItem);
+ if( !tastyListItem )
+ return;
+
+ /*if( _showExpander && (tastyListItem->getType() == TastyListViewItem::ServiceGroup) )
+ {
+ //FIXME: get the REAL size of the expander
+ if( coord.x() > 16 )
+ listItem->setOpen( !listItem->isOpen() );
+ }
+ else*/
+ listClicked( static_cast<TastyListViewItem *>(listItem), coord );
+}
+
+void MenuHandler::rootListClicked( QListViewItem * listItem, const QPoint & coord, int c )
+{
+ c=c;
+ if( !listItem )
+ return;
+
+ TastyListViewItem *tastyListItem = dynamic_cast<TastyListViewItem *>(listItem);
+ if( !tastyListItem )
+ return;
+
+ //don't reload when the current category is clicked (except for the first run)
+ if( menu->childList->childCount() > 0 &&
+ prefSkel->currentCategory( ) == tastyListItem->text(0) )
+ return;
+
+ if( tastyListItem->getType() == TastyListViewItem::ServiceGroup )
+ {
+ prefSkel->setCurrentCategory( tastyListItem->text(0) );
+ prefSkel->writeConfig();
+ }
+
+ listClicked( tastyListItem, coord );
+ if( _alphabetical )
+ menu->childList->setSorting(0);
+}
+
+void MenuHandler::slotContextMenu(QListViewItem *listItem, const QPoint &coord, int c)
+{
+
+ if( !listItem )
+ return;
+ TastyListViewItem *tastyListItem = dynamic_cast<TastyListViewItem *>(listItem);
+ if( !tastyListItem )
+ return;
+
+ KPopupMenu menu(this);
+
+ menu.insertTitle(tastyListItem->text(c));
+ if( tastyListItem->getPath() != "" )
+ {
+ if( tastyListItem->getType() == TastyListViewItem::ServiceGroup )
+ menu.insertItem(SmallIcon("kmenuedit"), i18n("&Edit submenu..."), 1);
+ else if( tastyListItem->getType() == TastyListViewItem::Service )
+ {
+ menu.insertItem(SmallIcon("kmenuedit"), i18n("&Edit item..."), 1);
+ menu.insertItem(SmallIcon("desktop"), i18n("&Add to desktop"), 3);
+ }
+ }
+
+ if( tastyListItem->getActionType() == TastyListViewItem::AddBookMark )
+ menu.insertItem(SmallIcon("bookmark_add"), i18n("&Add to favourite applications"), 2);
+ else if( tastyListItem->getActionType() == TastyListViewItem::RemoveBookMark )
+ menu.insertItem(SmallIcon("remove"), i18n("&Remove from favourite applications"), 2);
+
+ int choice;
+ if( menu.count() > 1 )
+ choice = menu.exec(coord);
+ else
+ return;
+
+ switch( choice )
+ {
+ case 1:
+ KRun::runCommand ("kmenuedit /" +
+ tastyListItem->getPath() +
+ " " +
+ tastyListItem->getMenuId());
+ if( !_isNormalWindow )
+ close();
+ break;
+
+ case 2:
+ listClicked( tastyListItem, QPoint(tastyListItem->listView()->width(), 0) );
+ break;
+
+ case 3:
+ KRun::runCommand( "cp " + tastyListItem->getDeskopEntryPath() + " ~/Desktop" );
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+void MenuHandler::doLogout()
+{
+ close();
+ DCOPRef kdesktopKDesktopIface ("kdesktop", "KDesktopIface");
+ kdesktopKDesktopIface.call ("logout()");
+}
+
+void MenuHandler::doLock()
+{
+ hide();
+ DCOPRef kdesktopKScreensaverIface ("kdesktop", "KScreensaverIface");
+ kdesktopKScreensaverIface.call ("lock()");
+ close();
+}
+
+void MenuHandler::runDialog()
+{
+ close();
+ DCOPRef kdesktopKDesktopIface ("kdesktop", "KDesktopIface");
+ kdesktopKDesktopIface.call ("popupExecuteCommand()");
+}
+
+/*Following functions are from official KDE Kmenu, Copyright 1996-2006 the kicker authors*/
+
+void MenuHandler::slotPopulateSessions()
+{
+ int p = 0;
+ DM dm;
+
+ sessionsMenu->clear();
+
+ sessionsMenu->insertItem(SmallIconSet("personal"), i18n("Edit user profile..."), 100 );
+ sessionsMenu->insertSeparator();
+
+ //optional save/restore session entries
+ if(prefSkel->showSaveSession())
+ {
+ sessionsMenu->insertItem( i18n("Save current session"), 101 );
+ }
+
+ if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0)
+ {
+ if( kapp->authorize("lock_screen") )
+ sessionsMenu->insertItem( i18n("Lock session and start a new one"), 102 );
+ sessionsMenu->insertItem(SmallIconSet("fork"), i18n("Start New Session"), 103 );
+ if (!p) {
+ sessionsMenu->setItemEnabled( 101, false );
+ sessionsMenu->setItemEnabled( 102, false );
+ }
+ sessionsMenu->insertSeparator();
+ }
+
+ SessList sess;
+ if (dm.localSessions( sess ))
+ for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ int id = sessionsMenu->insertItem( DM::sess2Str( *it ), (*it).vt );
+ if (!(*it).vt)
+ sessionsMenu->setItemEnabled( id, false );
+ if ((*it).self)
+ sessionsMenu->setItemChecked( id, true );
+ }
+}
+
+void MenuHandler::slotSessionActivated( int ent )
+{
+ close();
+
+ switch(ent)
+ {
+ case 100:
+ close();
+ KRun::runCommand ("kcmshell kcm_useraccount");
+ break;
+ case 101:
+ {
+ close();
+ DCOPRef ksmserverKsmserver ("ksmserver", "ksmserver");
+ ksmserverKsmserver.call ("saveCurrentSession()");
+ break;
+ }
+ case 102:
+ doNewSession( true );
+ break;
+ case 103:
+ doNewSession( false );
+ break;
+ }
+
+ //switch on an other session
+ if (!sessionsMenu->isItemChecked( ent ))
+ DM().lockSwitchVT( ent );
+}
+
+void MenuHandler::doNewSession( bool lock )
+{
+ int result = KMessageBox::warningContinueCancel(
+ kapp->desktop()->screen(kapp->desktop()->screenNumber(menu)),
+ i18n("<p>You have chosen to open another desktop session.<br>"
+ "The current session will be hidden "
+ "and a new login screen will be displayed.<br>"
+ "An F-key is assigned to each session; "
+ "F%1 is usually assigned to the first session, "
+ "F%2 to the second session and so on. "
+ "You can switch between sessions by pressing "
+ "Ctrl, Alt and the appropriate F-key at the same time. "
+ "Additionally, the KDE Panel and Desktop menus have "
+ "actions for switching between sessions.</p>")
+ .arg(7).arg(8),
+ i18n("Warning - New Session"),
+ KGuiItem(i18n("&Start New Session"), "fork"),
+ ":confirmNewSession",
+ KMessageBox::PlainCaption | KMessageBox::Notify);
+
+ if (result==KMessageBox::Cancel)
+ return;
+
+ if (lock)
+ doLock();
+
+ DM().startReserve();
+}
+
+
+void MenuHandler::initializeSearch( const QString & query )
+{
+ if( !searchMode && query.length() > 2 )
+ {
+ if( !menu->searchLine->listView() )
+ menu->searchLine->setListView((KListView *)(menu->dynamicList));
+ searchMode = true;
+ menu->menuModes->setEnabled(false);
+ KServiceGroup::Ptr service = KServiceGroup::root();
+ menu->dynamicList->clear();
+ setCursor(QCursor(Qt::BusyCursor));
+ populateList( service, menu->dynamicList, NULL, true, query );
+ setCursor(QCursor(Qt::ArrowCursor));
+ }
+ else if( query.length() < 3 )
+ {
+ if( menu->searchLine->listView() )
+ {
+ menu->searchLine->setListView(NULL);
+ menu->searchLine->setEnabled(true);
+ menu->searchLine->setFocus();
+ menu->searchLine->setContextMenuEnabled(false);
+ }
+ searchMode = false;
+ menu->menuModes->setEnabled(true);
+ menu->dynamicList->clear();
+ menuModeChanged(_menuMode);
+ }
+}
+
+void MenuHandler::kerrySearch( const QString & query )
+{
+ close();
+ DCOPRef kdesktopKScreensaverIface ("kerry", "search");
+ kdesktopKScreensaverIface.call ("search(QString)", query);
+}
+
+void MenuHandler::strigiSearch( const QString & query )
+{
+ close();
+ KRun::runCommand ("konqueror strigi:/?q="+query);
+}
+
+void MenuHandler::clearDynList( )
+{
+ menu->dynamicList->clear();
+ switch( currentMenuMode )
+ {
+ case MoreUsed:
+ case RecentlyUsed:
+ {
+ DCOPRef kickerKMenuIface ("kicker", "kicker");
+ kickerKMenuIface.call("clearQuickStartMenu()");
+ slotModKickerConf();
+ break;
+ }
+ case RecentDocuments:
+ KRecentDocument::clear();
+ break;
+ default:
+ break;
+ }
+}
+
+void MenuHandler::menuModeChanged( int index )
+{
+ _menuMode = index;
+ prefSkel->setMenuMode(_menuMode);
+
+ switch(index)
+ {
+ case Favourites:
+ fillFavourites();
+ break;
+
+ case MoreUsed:
+ fillMoreUsed();
+ break;
+
+ case RecentlyUsed:
+ fillRecentlyUsed();
+ break;
+
+ case RecentDocuments:
+ fillRecentDocuments();
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void MenuHandler::switchWindowMode()
+{
+ if( !_isNormalWindow /*testWFlags(Qt::WType_Popup)*/ )
+ {
+ _isNormalWindow = true;
+ hide();
+ reparent(static_cast<QWidget *>(parent()),Qt::WType_Dialog, pos(), true);
+
+ menu->detachButton->setIconSet(QPixmap(uic_findImage("attach.png")));
+ prefSkel->setIsNormalWindow(true);
+ }
+ else
+ {
+ hide();
+ reparent(static_cast<QWidget *>(parent()),
+ Qt::WType_Popup|Qt::WNoAutoErase,
+ pos(), true);
+
+ menu->detachButton->setIconSet(QPixmap(uic_findImage("detach.png")));
+ prefSkel->setIsNormalWindow(false);
+ _isNormalWindow = false;
+ }
+
+ prefSkel->writeConfig();
+}
+
+//EOF
diff --git a/src/menuhandler.h b/src/menuhandler.h
new file mode 100644
index 0000000..9fdf33f
--- /dev/null
+++ b/src/menuhandler.h
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef MENUHANDLER_H
+#define MENUHANDLER_H
+
+#include <kservicegroup.h>
+#include <kservice.h>
+#include <klistbox.h>
+#include <klistview.h>
+#include <klistviewsearchline.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <krecentdocument.h>
+#include <krun.h>
+#include <dcopref.h>
+#include <qheader.h>
+#include <qimage.h>
+#include <qtoolbutton.h>
+#include <qpopupmenu.h>
+#include <qcombobox.h>
+#include <kdirwatch.h>
+#include <kdirlister.h>
+#include <qlayout.h>
+#include <kfileitem.h>
+
+#include "dmctl.h"
+#include "menu.h"
+#include "prefs.h"
+#include "tastylistview.h"
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+*/
+class MenuHandler : public QFrame{
+ Q_OBJECT
+
+public:
+ MenuHandler( QWidget *parent, Prefs *prefs, char *name=0, WFlags fl=WType_TopLevel );
+
+ ~MenuHandler();
+
+ void readConfig();
+ void popup(QPoint pos);
+ void updateConfig();
+ void focusNextChild(){focusNextPrevChild(true);}
+ void focusPrevChild(){focusNextPrevChild(false);}
+ void clearNewInstalledApplications()
+ {newInstalledList.clear();newInstalledTimeStamps.clear();
+ prefSkel->setNewInstalledApps( newInstalledList );
+ prefSkel->setNewInstalledAppsTimeStamps( newInstalledTimeStamps );}
+
+signals:
+ void newApplications(int);
+ void kickerConfChanged();
+ void hidden();
+
+protected:
+ virtual bool eventFilter( QObject *o, QEvent * e );
+
+ virtual void closeEvent ( QCloseEvent *e);
+ virtual void resizeEvent ( QResizeEvent *e)
+ { QWidget::resizeEvent(e); menu->leftFrame->setMaximumWidth( (int)((width()-24)/3) ); }
+ virtual void mousePressEvent( QMouseEvent *e);
+
+private:
+ typedef QMap<ulong, QString> RecentlyUsedMap;
+ typedef enum
+ {
+ Favourites = 0,
+ MoreUsed = 1,
+ RecentlyUsed = 2,
+ RecentDocuments = 3
+ } MenuMode;
+
+ RecentlyUsedMap recentlyUsedMap;
+
+ QStringList moreUsedList, favouriteList;
+
+ Menu * menu;
+ MenuMode currentMenuMode;
+ KIconLoader *iconLoader;
+ QPopupMenu *sessionsMenu;
+ bool searchMode;
+ Prefs *prefSkel;
+ KConfig *kickerConf;
+ KDirWatch *kickerConfWatch;
+ //xdgMenuWatch for applications-kmenuedit.menu xdgMenuLister for all the desktop files
+ KDirWatch *xdgMenuWatch;
+ KDirLister *xdgMenuLister;
+ int firstListing;
+ QStringList oldInstalledList, newInstalledList;
+ QValueList<int> newInstalledTimeStamps;
+
+ QPixmap bookMarkPix;
+ QVBoxLayout * MenuHandlerLayout;
+
+//configuration items
+ int _menuMode;
+ QString _currentCategory;
+ int _numRecentEntries;
+ int _iconSize1;
+ int _iconSize2;
+ int _iconSize3;
+ int _actionIconSize;
+ bool _displaySubText;
+ bool _newAppsNotification;
+ bool _kerryIntegration;
+ bool _strigiIntegration;
+ double _menuWidth;
+ double _menuHeight;
+ bool _isNormalWindow;
+ bool _showExpander;
+ bool _alwaysCollapsed;
+ bool _hideOneChild;
+ bool _alphabetical;
+
+ typedef QMap<QString, KServiceGroup::List> SListMap;
+ SListMap sListMap;
+ //KServiceGroup::List getServiceGroupList( KServiceGroup *serviceGroup );
+ void setupColumns();
+ void loadNewInstalledApps();
+ void initOldInstalledApps(KServiceGroup::Ptr group);
+ void initNewInstalledApps(KServiceGroup::Ptr group);
+ void populateList( KServiceGroup *serviceGroup,
+ TastyListView *listView,
+ TastyListViewItem *listItemFather,
+ bool recursive, const QString & query = NULL );
+
+ void listClicked( TastyListViewItem * listItem, const QPoint & coord );
+ void fillRecentDocuments( );
+ void fillMoreUsed( );
+ void fillRecentlyUsed( );
+ void fillFavourites( );
+ void setupDynList( MenuMode mode );
+ //FIXME: this thing is UBER HEAVY
+ bool searchNewItems(KServiceGroup::Ptr group);
+
+public slots:
+ void slotUpdateApplications();
+
+private slots:
+ void dynListElemMoved( );
+ void dynListClicked( QListViewItem * listItem, const QPoint & coord, int c );
+ void slotContextMenu(QListViewItem *listItem, const QPoint &coord, int c );
+ void initializeRecentlyUsed( );
+ void slotModKickerConf();
+ void slotApplicationsAdded(const KFileItemList & newItems);
+ void slotApplicationRemoved();
+ void childListClicked( QListViewItem * listItem, const QPoint & coord, int c );
+ void rootListClicked( QListViewItem * listItem, const QPoint & coord, int c );
+ void doLogout();
+ void doLock();
+ void slotPopulateSessions();
+ void slotSessionActivated( int ent );
+ void doNewSession( bool lock );
+ void runDialog();
+ void initializeSearch( const QString & query );
+ void kerrySearch( const QString & query );
+ void strigiSearch( const QString & query );
+ void clearDynList();
+ void menuModeChanged( int index );
+ void switchWindowMode();
+};
+
+#endif
diff --git a/src/misc.cpp b/src/misc.cpp
new file mode 100644
index 0000000..2f1d30c
--- /dev/null
+++ b/src/misc.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003, Sandro Giessl <ceebx@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <qcolor.h>
+#include "misc.h"
+
+QColor alphaBlendColors(const QColor &bgColor, const QColor &fgColor, const int a)
+{
+
+ // normal button...
+ QRgb rgb = bgColor.rgb();
+ QRgb rgb_b = fgColor.rgb();
+ int alpha = a;
+ if(alpha>255) alpha = 255;
+ if(alpha<0) alpha = 0;
+ int inv_alpha = 255 - alpha;
+
+ QColor result = QColor( qRgb(qRed(rgb_b)*inv_alpha/255 + qRed(rgb)*alpha/255,
+ qGreen(rgb_b)*inv_alpha/255 + qGreen(rgb)*alpha/255,
+ qBlue(rgb_b)*inv_alpha/255 + qBlue(rgb)*alpha/255) );
+
+ return result;
+}
diff --git a/src/misc.h b/src/misc.h
new file mode 100644
index 0000000..835c277
--- /dev/null
+++ b/src/misc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003, Sandro Giessl <ceebx@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MISC_H
+#define __MISC_H
+
+QColor alphaBlendColors(const QColor &backgroundColor, const QColor &foregroundColor, const int alpha);
+
+#endif // __MISC_H
diff --git a/src/pics/.svn/all-wcprops b/src/pics/.svn/all-wcprops
new file mode 100644
index 0000000..771d36b
--- /dev/null
+++ b/src/pics/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 30
+/svn/!svn/ver/2/trunk/src/pics
+END
+attach.png
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/2/trunk/src/pics/attach.png
+END
+detach.png
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/2/trunk/src/pics/detach.png
+END
diff --git a/src/pics/.svn/entries b/src/pics/.svn/entries
new file mode 100644
index 0000000..257243f
--- /dev/null
+++ b/src/pics/.svn/entries
@@ -0,0 +1,42 @@
+9
+
+dir
+2
+https://tastymenu.googlecode.com/svn/trunk/src/pics
+https://tastymenu.googlecode.com/svn
+
+
+
+2007-05-27T14:44:26.685461Z
+2
+notmart
+
+
+svn:special svn:externals svn:needs-lock
+
+attach.png
+file
+
+
+
+
+2006-07-28T13:14:20.000000Z
+ed780d9ddd2ed20aaa4b9fa7a5c9ecec
+2007-05-27T14:44:26.685461Z
+2
+notmart
+has-props
+
+detach.png
+file
+
+
+
+
+2006-07-28T13:14:01.000000Z
+f7ea9ad2adbf18c94d8fa4badc7e07db
+2007-05-27T14:44:26.685461Z
+2
+notmart
+has-props
+
diff --git a/src/pics/.svn/format b/src/pics/.svn/format
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/src/pics/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/src/pics/.svn/prop-base/attach.png.svn-base b/src/pics/.svn/prop-base/attach.png.svn-base
new file mode 100644
index 0000000..5e9587e
--- /dev/null
+++ b/src/pics/.svn/prop-base/attach.png.svn-base
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/src/pics/.svn/prop-base/detach.png.svn-base b/src/pics/.svn/prop-base/detach.png.svn-base
new file mode 100644
index 0000000..5e9587e
--- /dev/null
+++ b/src/pics/.svn/prop-base/detach.png.svn-base
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/src/pics/.svn/text-base/attach.png.svn-base b/src/pics/.svn/text-base/attach.png.svn-base
new file mode 100644
index 0000000..9a2382f
--- /dev/null
+++ b/src/pics/.svn/text-base/attach.png.svn-base
Binary files differ
diff --git a/src/pics/.svn/text-base/detach.png.svn-base b/src/pics/.svn/text-base/detach.png.svn-base
new file mode 100644
index 0000000..53986e4
--- /dev/null
+++ b/src/pics/.svn/text-base/detach.png.svn-base
Binary files differ
diff --git a/src/pics/attach.png b/src/pics/attach.png
new file mode 100644
index 0000000..9a2382f
--- /dev/null
+++ b/src/pics/attach.png
Binary files differ
diff --git a/src/pics/detach.png b/src/pics/detach.png
new file mode 100644
index 0000000..53986e4
--- /dev/null
+++ b/src/pics/detach.png
Binary files differ
diff --git a/src/prefs.kcfgc b/src/prefs.kcfgc
new file mode 100644
index 0000000..b996f04
--- /dev/null
+++ b/src/prefs.kcfgc
@@ -0,0 +1,6 @@
+# Code generation options for kconfig_compiler
+File=tastymenu.kcfg
+ClassName=Prefs
+Singleton=false
+Mutators=true
+
diff --git a/src/tastybutton.cpp b/src/tastybutton.cpp
new file mode 100644
index 0000000..9f89c05
--- /dev/null
+++ b/src/tastybutton.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "tastybutton.h"
+
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qcolor.h>
+#include <kimageeffect.h>
+
+TastyButton::TastyButton(QWidget *parent)
+ : QToolButton(parent)
+{
+ iconEffect = new KIconEffect();
+ iconEffect->init();
+}
+
+
+TastyButton::~TastyButton()
+{
+}
+
+void TastyButton::drawButton( QPainter * p )
+{
+ //background image or pseudo transparency
+ if( parentWidget()->erasePixmap() )
+ {
+ const QPixmap erasePix(size());
+ QPainter buffPainter(&erasePix);
+ buffPainter.drawPixmap(QPoint(0, 0), *parentWidget()->erasePixmap(), geometry());
+ buffPainter.end();
+
+ QImage eraseImg = erasePix.convertToImage();
+ if( isDown() )
+ {
+ KImageEffect::fade(eraseImg, 0.25, black);
+ p->drawPixmap(rect(), eraseImg );
+ }
+ else if( uses3D() )
+ {
+ KImageEffect::fade(eraseImg, 0.4, white);
+ p->drawPixmap(rect(), eraseImg );
+ }
+ else
+ p->drawPixmap(rect(), erasePix );
+
+ //lightScore = 0 grey, >0 lighter <0 darker
+ int lightScore = 0;
+ //chacks the brightness of 10 pixels of the diagonal
+ //we won't be 100% sure if this reflects the global brightess of the image
+ //but it seems to work well
+ int x = 0;
+ int y = 0;
+ while( x < eraseImg.width() && y < eraseImg.height() && x < 10 )
+ {
+ x=++y;
+ //deciding the text color to use
+ int h,s,v;
+ QColor(eraseImg.pixel(x,y)).getHsv( h, s, v );
+ // is purely empirical :)
+ if( v > 140) lightScore++;
+ else lightScore--;
+ }
+ if( lightScore < 0 )
+ setPaletteForegroundColor(white);
+ else
+ setPaletteForegroundColor(black);
+ }
+ //simple background color
+ else
+ {
+ if( isDown() )
+ {
+ p->fillRect(rect(), colorGroup().background().dark(120));
+ }
+ else if( uses3D() )
+ {
+ p->fillRect(rect(), colorGroup().background().light(120));
+ }
+ else
+ {
+ p->fillRect(rect(), colorGroup().background());
+ }
+ }
+
+ drawButtonLabel(p);
+}
+
+void TastyButton::setIconSet( QIconSet is )
+{
+ is.setPixmap(iconEffect->apply(is.pixmap(),
+ (int)KIcon::Panel,
+ (int)KIcon::ActiveState),
+ QIconSet::Automatic,
+ QIconSet::Active);
+
+ QToolButton::setIconSet( is );
+}
+
diff --git a/src/tastybutton.h b/src/tastybutton.h
new file mode 100644
index 0000000..4fa0d89
--- /dev/null
+++ b/src/tastybutton.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef TASTYBUTTON_H
+#define TASTYBUTTON_H
+
+#include <kiconeffect.h>
+#include <kicontheme.h>
+#include <qiconset.h>
+#include <qtoolbutton.h>
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+*/
+class TastyButton : public QToolButton
+{
+public:
+ TastyButton(QWidget *parent);
+
+ ~TastyButton();
+
+ void setIconSet( QIconSet is );
+
+protected:
+ void drawButton( QPainter * p );
+
+ private:
+ QPixmap highLightedIcon;
+ KIconEffect *iconEffect;
+
+};
+
+#endif
diff --git a/src/tastylistview.cpp b/src/tastylistview.cpp
new file mode 100644
index 0000000..ed5e2a7
--- /dev/null
+++ b/src/tastylistview.cpp
@@ -0,0 +1,600 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "tastylistview.h"
+#include "misc.h"
+
+#include <kdeversion.h>
+#include <kstringhandler.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qheader.h>
+#include <klocale.h>
+#include <kurldrag.h>
+#include <qapplication.h>
+
+
+TastyListView::TastyListView( QWidget * parent, const char * name)
+ : KListView(parent, name), highLightGroups(true), easyOpen(true)
+{
+
+ onItemTimer = new QTimer(this, "onItemTimer");
+ underCursorItem = openItem = NULL;
+ mouseDown = false;
+ actionIconSize = 16;
+ actionIconSpace = 32;
+
+ listItemTip = new TastyListViewToolTip(viewport(), this);
+
+ connect(this, SIGNAL(onItem(QListViewItem *) ), SLOT(slotOnItem(QListViewItem *) ) );
+ connect(onItemTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()) );
+}
+
+
+TastyListView::~TastyListView()
+{
+}
+
+void TastyListView::startDrag()
+{
+ if( !currentItem() )
+ return;
+ TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem());
+ if( !item )
+ return;
+
+ QDragObject *d = new KURLDrag( KURL(item->getDeskopEntryPath()) , viewport() );
+ if(!d)
+ return;
+
+ if (d->drag() && d->target() != viewport())
+ emit moved();
+}
+
+void TastyListView::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ int x = e->x();
+ if( x > width() || x < 0)
+ return;
+
+ if( !currentItem() )
+ return;
+ TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem());
+ if( !item )
+ return;
+
+ if( e->button() == RightButton )
+ emit(contextMenuRequested( currentItem(), e->globalPos(), 0) );
+ else
+ emit(activated( currentItem(), QPoint(x, e->y()), 0) );
+
+ if(item && (item->getType() == TastyListViewItem::ServiceGroup))
+ {
+ if( !openItem )
+ {
+ openItem = currentItem();
+ return;
+ }
+
+ TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem);
+ openItem = currentItem();
+ if( !oldOpenItem || !oldOpenItem->listView() )
+ return;
+
+ oldOpenItem->repaint();
+ }
+ KListView::contentsMouseReleaseEvent(e);
+}
+
+void TastyListView::contentsMouseMoveEvent( QMouseEvent * e )
+{
+ KListView::contentsMouseMoveEvent(e);
+ mouseDown = (e->state() & Qt::LeftButton);
+
+ if( itemAt( contentsToViewport(QPoint(e->x(), e->y()))) == 0 )
+ underCursorItem = NULL;
+}
+
+void TastyListView::leaveEvent( QEvent * e )
+{
+ KListView::leaveEvent( e );
+ onItemTimer->stop();
+ if( openItem )
+ setCurrentItem( openItem );
+}
+
+
+void TastyListView::keyPressEvent( QKeyEvent * e )
+{
+
+ switch(e->key())
+ {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Space:
+ {
+ emit(activated(currentItem(), QPoint(0,0), 0));
+ if(!currentItem())
+ return;
+ TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem());
+ if(item && item->getType() == TastyListViewItem::ServiceGroup)
+ {
+ if( !openItem )
+ {
+ openItem = currentItem();
+ return;
+ }
+ TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem);
+ openItem = currentItem();
+ if( !oldOpenItem || !oldOpenItem->listView() )
+ return;
+
+ oldOpenItem->repaint();
+ }
+ }
+ break;
+
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ KListView::keyPressEvent( e );
+ break;
+
+ case Qt::Key_Right:
+ {
+ if(!currentItem())
+ return;
+ TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem());
+ if(item && easyOpen && !QApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup)
+ {
+ emit( activated( currentItem(), QPoint(0,0), 0));
+ if( !openItem )
+ {
+ openItem = currentItem();
+ return;
+ }
+ TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem);
+ openItem = currentItem();
+ if( !oldOpenItem || !oldOpenItem->listView() )
+ return;
+
+ oldOpenItem->repaint();
+ }
+ focusNextPrevChild(!QApplication::reverseLayout());
+ break;
+ }
+ case Qt::Key_Left:
+ {
+ if( !currentItem() )
+ return;
+ TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem());
+ if(item && easyOpen && QApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup)
+ {
+ emit( activated( currentItem(), QPoint(0,0), 0));
+ if( !openItem )
+ {
+ openItem = currentItem();
+ return;
+ }
+ TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem);
+ openItem = currentItem();
+ if( !oldOpenItem || !oldOpenItem->listView() )
+ return;
+
+ oldOpenItem->repaint();
+ }
+ focusNextPrevChild(QApplication::reverseLayout());
+ break;
+ }
+ case Qt::Key_Tab:
+ KListView::keyPressEvent( e );
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void TastyListView::slotOnItem( QListViewItem * listItem )
+{
+ if( !listItem || listItem->listView() != this )
+ return;
+
+ if( listItem != underCursorItem )
+ {
+ underCursorItem = listItem;
+ setCurrentItem(listItem);
+ if(mouseDown)
+ onItemTimer->start(250, true);
+ else
+ onItemTimer->start(1000, true);
+ }
+}
+
+void TastyListView::slotTimeout( )
+{
+ if( !underCursorItem /*|| !openItem*/ )
+ return;
+
+ TastyListViewItem *tastyUnderCursorItem = dynamic_cast<TastyListViewItem *>(underCursorItem);
+
+ if( easyOpen && tastyUnderCursorItem &&
+ tastyUnderCursorItem->getType() == TastyListViewItem::ServiceGroup )
+ {
+ emit(activated(underCursorItem, QPoint(underCursorItem->listView()->width()/2,1), 0));
+ TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem);
+ openItem = currentItem();
+ if( !oldOpenItem || !oldOpenItem->listView() )
+ return;
+
+ oldOpenItem->repaint();
+ }
+}
+
+///////////TASTYLISTVIEWTOOLTIP
+TastyListViewToolTip::TastyListViewToolTip( QWidget *parent, TastyListView *tListView )
+ : QToolTip( parent ), listView( tListView )
+{
+}
+
+void TastyListViewToolTip::maybeTip( const QPoint &pos )
+{
+ if( !parentWidget() || !listView || !listView->showToolTips() )
+ return;
+
+ TastyListViewItem *item = static_cast<TastyListViewItem *>(listView->itemAt( pos ));
+ QPoint contentsPos = listView->viewportToContents( pos );
+ if( !item || !listView->columns() )
+ return;
+
+ int actionWidth = 0;
+ TastyListViewItem::ActionType actionType = item->getActionType();
+ if( actionType != TastyListViewItem::NoAction )
+ actionWidth = listView->getActionIconSpace();
+
+ int column = listView->header()->sectionAt( contentsPos.x() );
+
+
+ QRect r = listView->itemRect( item );
+ int headerPos = listView->header()->sectionPos( column );
+ r.setLeft( headerPos );
+ r.setRight( headerPos + listView->header()->sectionSize( column ) );
+
+ int actionLeft = r.right()-actionWidth;
+ if( pos.x() >= actionLeft )
+ {
+ r.setLeft( actionLeft );
+ switch( actionType )
+ {
+ case TastyListViewItem::AddBookMark:
+ tip( r, i18n( "Add" )+" \""+item->text( column )+"\" "+i18n( "to your favourite applications" ) );
+ return;
+
+ case TastyListViewItem::RemoveBookMark:
+ tip( r, i18n( "Remove" )+" \""+item->text( column )+"\" "+i18n( "from your favourite applications" ) );
+ return;
+
+ case TastyListViewItem::OpenGroup:
+ tip( r, i18n( "Browse" )+" \""+item->text( column )+"\"" );
+ return;
+
+ case TastyListViewItem::Expand:
+ tip( r, i18n( "Expand" )+" \""+item->text( column )+"\"" );
+ return;
+
+ case TastyListViewItem::Collapse:
+ tip( r, i18n( "Collapse" )+" \""+item->text( column )+"\"" );
+ return;
+
+ default:
+ break;
+ }
+ }
+ else if( actionType == TastyListViewItem::OpenGroup && !item->hasEllipsis() )
+ {
+ tip( r, i18n( "Browse" )+" \""+item->text( column )+"\"" );
+ return;
+ }
+
+ if( !item->hasEllipsis() )
+ return;
+ tip( r, item->text( column )+"\n"+item->getSubText() );
+}
+
+
+///////////TASTYLISTVIEWITEM
+
+TastyListViewItem::TastyListViewItem( TastyListView * parent )
+ : KListViewItem(parent)
+{commonConstructor();}
+
+TastyListViewItem::TastyListViewItem( TastyListViewItem * parent )
+ : KListViewItem(parent)
+{commonConstructor();}
+
+TastyListViewItem::TastyListViewItem( TastyListView * parent, TastyListViewItem * after, QString label1 )
+ : KListViewItem(parent, after, label1)
+{commonConstructor();cellText = label1;}
+
+TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, TastyListViewItem * after, QString label1 )
+ : KListViewItem(parent, after, label1)
+{commonConstructor();cellText = label1;}
+
+TastyListViewItem::TastyListViewItem( TastyListView * parent, QString label1 )
+ : KListViewItem(parent, label1)
+{commonConstructor();cellText = label1;}
+
+TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, QString label1 )
+ : KListViewItem(parent, label1)
+{commonConstructor();cellText = label1;}
+
+TastyListViewItem::~TastyListViewItem()
+{
+}
+
+void TastyListViewItem::commonConstructor()
+{
+
+ subText="";cellText="";
+
+ actionType = NoAction;
+
+ actionPix = QPixmap();
+
+ menuId = QString();
+ desktopEntryPath = QString();
+ path = QString();
+
+ ellipsis = false;
+ highLight = false;
+ displaySubText = true;
+
+}
+
+void TastyListViewItem::loadPixmap()
+{
+ QString iconFile = "";
+ iconLoader = KGlobal::iconLoader();
+
+ if( !listView() )
+ return;
+
+ TastyListView *lv = dynamic_cast<TastyListView *>(listView());
+ if( !lv )
+ return;
+
+ switch( actionType )
+ {
+ case AddBookMark:
+ actionPix = iconLoader->loadIcon("bookmark_add", KIcon::Small, lv->getActionIconSize());
+ break;
+
+ case RemoveBookMark:
+ actionPix = iconLoader->loadIcon("remove", KIcon::Small, lv->getActionIconSize());
+ break;
+
+ case OpenGroup:
+ if( QApplication::reverseLayout() )
+ actionPix = iconLoader->loadIcon("1leftarrow", KIcon::Small, lv->getActionIconSize());
+ else
+ actionPix = iconLoader->loadIcon("1rightarrow", KIcon::Small, lv->getActionIconSize());
+ break;
+
+ case Expand:
+ actionPix = iconLoader->loadIcon("1downarrow", KIcon::Small, lv->getActionIconSize());
+ break;
+
+ case Collapse:
+ actionPix = iconLoader->loadIcon("1uparrow", KIcon::Small, lv->getActionIconSize());
+ break;
+
+ default:
+ return;
+ }
+
+
+ if ( actionPix.height () > lv->getActionIconSize())
+ {
+ QImage img = actionPix.convertToImage();
+ if( !img.isNull() )
+ {
+ img = img.smoothScale ( lv->getActionIconSize(), lv->getActionIconSize());
+ actionPix = QPixmap (img);
+ }
+ }
+}
+
+QString TastyListViewItem::key( int column, bool ascending ) const
+{
+ ascending = ascending;
+ QString prefix;
+
+ //ensure all the categories are before the leaf items
+ if( itemType == ServiceGroup )
+ prefix = "0";
+ else
+ prefix = "1";
+ return prefix.append(text( column ));
+}
+
+void TastyListViewItem::setup ( )
+{
+ //KListViewItem::setup();
+
+ //calculate listitem height
+ QFontMetrics fm( listView()->font() );
+
+ int pixmapHeight = 5;
+ if( pixmap(0) )
+ pixmapHeight = pixmap(0)->height()+4;
+
+ if( displaySubText && !subText.isEmpty() )
+ {
+ int textHeight = (int)(fm.height()*2.5);
+ setHeight( (pixmapHeight > textHeight) ? pixmapHeight : textHeight );
+ }
+ else
+ setHeight( pixmapHeight );
+}
+
+
+/*Adapted from Amarok's Statistic listView Copyright (c) 2006 Seb Ruiz*/
+void TastyListViewItem::paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align )
+{
+ int textHeight = height();
+ QString name = cellText;
+
+ int textX = 0;
+
+ QColor fillColor, textColor;
+
+# if KDE_VERSION < KDE_MAKE_VERSION(3,3,91)
+# define BackgroundColor backgroundColor()
+# else
+# define BackgroundColor backgroundColor(0)
+# endif
+
+
+ fillColor = isSelected() ? cg.highlight() : BackgroundColor;
+
+ textColor = isSelected() ? cg.highlightedText() : cg.text();
+
+ if( !listView() )
+ return;
+ TastyListView *lv = dynamic_cast<TastyListView *>( listView() );
+ if( !lv )
+ return;
+
+ QFont font( lv->font() );
+
+ if( !isSelected() && (lv->getOpenItem() == this||
+ (lv->getHighLightGroups() && itemType == ServiceGroup)) )
+ fillColor = alphaBlendColors( fillColor, cg.highlight(), 200);
+
+ else if( !isSelected() && highLight )
+ {
+ int hue, saturation, value;
+ cg.highlight().getHsv(&hue, &saturation, &value);
+ //calculate the inverse color 128 means rotating the spectral value by 180 degrees
+ fillColor.setHsv( (hue+128)%256, saturation/2, value );
+ }
+
+ else if( isSelected() && !lv->hasFocus() )
+ fillColor = alphaBlendColors( fillColor, BackgroundColor, 150);
+
+ QFontMetrics fm( font );
+ widthChanged(column);
+
+ QPixmap buffer(width*2, textHeight);
+
+ if( buffer.isNull() )
+ return;
+
+ buffer.fill( fillColor );
+
+ QPainter pBuf(&buffer);
+
+
+ if( pixmap( column ) )
+ {
+ int y = (textHeight - pixmap(column)->height())/2;
+ pBuf.drawPixmap( 0, y, *pixmap(column) );
+ textX += pixmap(column)->width() + 4;
+ }
+
+ //Calculate the ellipsis for the MAIN text
+ int extraSpace = fm.width("...") + textX + lv->getActionIconSpace();
+ ellipsis = false;
+ while( (fm.width(name)+extraSpace) > width && name.length() > 4)
+ {
+ name.truncate(name.length()-1);
+ ellipsis = true;
+ }
+ if( ellipsis )
+ name.append("...");
+
+
+ if( name == "separator" )
+ {
+ int y = textHeight/2;
+ pBuf.setPen(cg.background().dark(140));
+ pBuf.drawLine(textX, y, width, y);
+ pBuf.setPen(textColor);
+ pBuf.end();
+ p->drawPixmap( 0, 0, buffer );
+ return;
+ }
+
+ if( fm.width( name ) + textX + lv->itemMargin()*2 > width )
+ {
+ const int _width = width - textX - lv->itemMargin()*2;
+ name = KStringHandler::rPixelSqueeze( name, pBuf.fontMetrics(), _width );
+ }
+
+ pBuf.setPen(textColor);
+ pBuf.drawText( textX, 3, width, textHeight, AlignTop, name );
+
+ if( displaySubText && !subText.isEmpty() )
+ {
+ font.setPointSize( max((int)(font.pointSize()/1.2), 7) );
+ pBuf.setFont( font );
+
+ QString subTextCopy = subText;
+ QFontMetrics sfm( font );
+
+ //Calculate the ellipsis for the subtext
+ int extraSpace = fm.width("...") + textX + lv->getActionIconSpace();
+ bool ellipsisSubText = false;
+ while( (sfm.width(subTextCopy)+extraSpace) > width && subTextCopy.length() > 4)
+ {
+ subTextCopy.truncate(subTextCopy.length()-1);
+ ellipsisSubText = true;
+ }
+ if( ellipsisSubText )
+ {
+ subTextCopy.append("...");
+ ellipsis = true;
+ }
+
+ pBuf.setPen(cg.background().dark(140));
+ pBuf.drawLine(textX, fm.height() + 3, width-textX-5, fm.height() + 3);
+ pBuf.setPen(textColor.light(130));
+ pBuf.drawText( textX, fm.height() + 4, width, fm.height(), AlignTop, subTextCopy );
+ }
+
+ if( !actionPix.isNull() &&
+ (actionType == OpenGroup ||
+ actionType == Expand ||
+ actionType == Collapse ||
+ lv->currentItem() == this) )
+ {
+ int y = (textHeight - actionPix.height())/2;
+ pBuf.drawPixmap( width-(actionPix.width()+5), y, actionPix );
+ }
+
+
+ pBuf.end();
+ p->drawPixmap( 0, 0, buffer );
+}
+
+
+
+//EOF
diff --git a/src/tastylistview.h b/src/tastylistview.h
new file mode 100644
index 0000000..fae9d02
--- /dev/null
+++ b/src/tastylistview.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef TASTYLISTVIEW_H
+#define TASTYLISTVIEW_H
+
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kservice.h>
+#include <kservicegroup.h>
+#include <kdesktopfile.h>
+#include <qpixmap.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+#include <qheader.h>
+
+class TastyListView;
+
+//the space reserved for the action icon (bookmark, remove bookmark etc
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+ */
+class TastyListViewToolTip: public QToolTip
+{
+ public:
+ TastyListViewToolTip( QWidget *parent, TastyListView *tListView );
+
+ void maybeTip( const QPoint &pos );
+
+ private:
+ TastyListView *listView;
+};
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+*/
+class TastyListView : public KListView
+{
+ Q_OBJECT
+private:
+ bool highLightGroups;
+ QTimer *onItemTimer;
+ QListViewItem *underCursorItem;
+ QListViewItem *openItem;
+ bool mouseDown;
+ bool easyOpen;
+ int actionIconSize;
+ int actionIconSpace;
+
+ TastyListViewToolTip *listItemTip;
+
+public:
+ TastyListView( QWidget * parent = 0, const char * name = 0);
+
+ ~TastyListView();
+
+ bool getHighLightGroups(){ return highLightGroups;}
+ void setHighLightGroups(bool highLight){highLightGroups = highLight;}
+
+ bool getEasyOpen(){ return easyOpen;}
+ void setEasyOpen(bool easy){easyOpen = easy;}
+ void startDrag();
+
+ void setActionIconSize(int newSize){ actionIconSize = newSize; actionIconSpace = newSize*2; }
+ int getActionIconSize(){return actionIconSize;}
+ int getActionIconSpace(){return actionIconSpace;}
+
+ QListViewItem * getOpenItem(){ return openItem;}
+ void setOpenItem( QListViewItem * listItem ){openItem = listItem;}
+
+public slots:
+ virtual void clear(){openItem = underCursorItem = NULL; KListView::clear();}
+
+
+protected:
+ virtual void leaveEvent( QEvent * e );
+ virtual void contentsMouseMoveEvent( QMouseEvent * e );
+ virtual void contentsMouseReleaseEvent( QMouseEvent * e );
+ virtual void keyPressEvent( QKeyEvent * e );
+
+
+private slots:
+ void slotOnItem( QListViewItem * listItem );
+ void slotTimeout();
+
+signals:
+ //Using own signal instead of clicked() in order to avoid launching two times the same app :-)
+ void activated(QListViewItem *, const QPoint &, int );
+
+};
+
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+*/
+class TastyListViewItem : public KListViewItem
+{
+ //Q_OBJECT
+friend class TastyListView;
+ public:
+ typedef enum
+ {
+ Service,
+ ServiceGroup,
+ DesktopFile,
+ Empty
+ }Type;
+
+ typedef enum
+ {
+ AddBookMark,
+ RemoveBookMark,
+ OpenGroup,
+ Expand,
+ Collapse,
+ NoAction
+ }ActionType;
+
+ TastyListViewItem( TastyListView * parent );
+ TastyListViewItem( TastyListViewItem * parent );
+ TastyListViewItem( TastyListView * parent, TastyListViewItem * after, QString label1 );
+ TastyListViewItem( TastyListViewItem * parent, TastyListViewItem * after, QString label1 );
+ TastyListViewItem( TastyListView * parent, TastyListViewItem * after );
+ TastyListViewItem( TastyListViewItem * parent, TastyListViewItem * after );
+ TastyListViewItem( TastyListView * parent, QString label1 );
+ TastyListViewItem( TastyListViewItem * parent, QString label1 );
+
+ ~TastyListViewItem();
+
+ //QString text(int column) const {return cellText;}
+ QString getCellText(int column) const {return cellText;}
+
+ //TastyListViewItem *parent();
+ void paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align );
+
+ Type getType(){return itemType;}
+ void setType( Type newItemType ){itemType = newItemType;}
+
+ ActionType getActionType(){return actionType;}
+ void setActionType( ActionType newActionType ){ actionType = newActionType;loadPixmap();}
+ void loadPixmap();
+
+ void setPath( QString newPath){ path = newPath;}
+ QString getPath(){return path;}
+
+ void setDeskopEntryPath( QString newPath){ desktopEntryPath = newPath;}
+ QString getDeskopEntryPath(){return desktopEntryPath;}
+
+ QString getSubText(){return subText;}
+ bool xOnDecoration( int x )
+ { QListView *lv = listView();
+ if( !lv ) return false;
+ return !( x > lv->header()->sectionPos( lv->header()->mapToIndex( 0 ) ) +
+ lv->treeStepSize() * ( depth() + ( lv->rootIsDecorated() ? 1 : 0) ) + lv->itemMargin() ||
+ x < lv->header()->sectionPos( lv->header()->mapToIndex( 0 ) ) );}
+
+ void setSubText(QString text) //FIXME: add the column
+ {if(cellText.isEmpty())cellText=KListViewItem::text(0);
+ KListViewItem::setText(0,cellText+text);subText = QString(text);}
+ void setText(int column, const QString & text )
+ {KListViewItem::setText(column, cellText+text); cellText = text;}
+ void setDisplaySubText( bool display ){ displaySubText = display; }
+
+ bool hasEllipsis(){return ellipsis;}
+ void setHighLight( bool newHighLight ){highLight=newHighLight;}
+ bool isHighLight(){return highLight;}
+
+ void setMenuId( QString newMenuId ){ menuId = newMenuId;}
+ QString getMenuId(){ return menuId; }
+
+ QString key( int column, bool ascending ) const;
+
+ int width( const QFontMetrics & fm, const QListView * lv, int c )
+ { TastyListView *tlv = dynamic_cast<TastyListView *>( listView() );
+ if( tlv )
+ return KListViewItem::width(fm, lv, c) + tlv->getActionIconSpace();
+ else
+ return KListViewItem::width(fm, lv, c);
+ }
+
+protected:
+ virtual void setup();
+
+private:
+
+ Type itemType;
+ ActionType actionType;
+ QString path;
+ QString desktopEntryPath;
+ QString cellText;
+ QString subText;
+ QString menuId;
+
+ bool ellipsis;
+ bool highLight;
+ bool displaySubText;
+ QPixmap actionPix;
+ KIconLoader *iconLoader;
+
+ void commonConstructor();
+ //a tiny reimplementation of max...
+ int max(int a, int b){return (a>b?a:b);}
+};
+
+
+#endif
diff --git a/src/tastymenu.cpp b/src/tastymenu.cpp
new file mode 100644
index 0000000..1ec371e
--- /dev/null
+++ b/src/tastymenu.cpp
@@ -0,0 +1,492 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kconfigdialog.h>
+#include <kaboutdata.h>
+#include <kaboutapplication.h>
+#include <kpopupmenu.h>
+#include <kkeydialog.h>
+#include <kuser.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <qstyle.h>
+
+
+#include "tastymenu.h"
+#include "appearance.h"
+#include "behaviour.h"
+
+
+
+TastyMenu::TastyMenu(const QString& configFile, Type type, int actions, QWidget *parent, const char *name)
+ : KPanelApplet(configFile, type, actions, parent, name), numNewApplications(0)
+{
+
+ // Get the current application configuration handle
+ kConfig = sharedConfig();
+ prefSkel = new Prefs(kConfig);
+ prefSkel->readConfig();
+
+ kickerConf = KGlobal::config();
+ kickerConf->setGroup("buttons");
+ _showBigToolTip = kickerConf->readBoolEntry("EnableIconZoom", true);
+
+ button = new TastyButton(this);
+
+ menuHandler = new MenuHandler(this, prefSkel, "MenuHandler",
+ prefSkel->isNormalWindow() ?
+ Qt::WType_Dialog :
+ Qt::WType_Popup|Qt::WNoAutoErase);
+
+ connect (button, SIGNAL (pressed()), this, SLOT (clickSlot ()));
+ connect (menuHandler, SIGNAL(hidden()), this, SLOT(setButtonUp()));
+ _menuButtonLabel = prefSkel->menuButtonLabel();
+ if(_menuButtonLabel.isEmpty())
+ button -> setTextLabel(i18n("Menu"), false);
+ else
+ button -> setTextLabel(_menuButtonLabel, false);
+
+ button -> setUsesTextLabel(prefSkel->menuButtonLabelType()
+ != Prefs::EnumMenuButtonLabelType::MenuButtonNone);
+ button -> setTextPosition(QToolButton::BesideIcon);
+ menuTip = new TastyToolTip(button);
+
+ _toolTipTitle = prefSkel->toolTipTitle();
+
+ if( !_toolTipTitle.isEmpty() )
+ menuTip->setTitle(_toolTipTitle);
+
+ if( height() >= KIcon::SizeMedium )
+ button->setUsesBigPixmap(true);
+ else
+ button->setUsesBigPixmap(false);
+
+ iconLoader = KGlobal::iconLoader();
+
+ loadMenuButtonIcon();
+
+ button->setAutoRaise(true);
+
+ _newAppsNotification = prefSkel->newAppsNotification();
+ if( _newAppsNotification )
+ {
+ setNewApplicationsMessage(prefSkel->newInstalledApps().count());
+ connect( menuHandler, SIGNAL(newApplications(int)),
+ this, SLOT(setNewApplicationsMessage(int)));
+ }
+ setGlobalAccel( prefSkel->overrideAltF1());
+
+ connect( menuHandler, SIGNAL(kickerConfChanged()),
+ this, SLOT(updateConfiguration()) );
+}
+
+
+TastyMenu::~TastyMenu()
+{
+ //delete prefSkel;
+ KGlobal::locale()->removeCatalogue("tastymenu");
+}
+
+void TastyMenu::loadMenuButtonIcon()
+{
+ _menuButtonIcon = prefSkel->menuButtonIcon();
+ //the tooltip has the same icon as the button
+ menuTip->loadIcon( _menuButtonIcon );
+
+ if( prefSkel->menuButtonIconType()
+ == Prefs::EnumMenuButtonIconType::IconNone )
+ {
+ button->setIconSet(QIconSet());
+ return;
+ }
+
+ if( position() == pTop || position() == pBottom )
+ _iconsize = height();
+ else if(position() == pLeft || position() == pRight)
+ _iconsize = width();
+
+ QPixmap btnPixmap(iconLoader->loadIcon(_menuButtonIcon, KIcon::Panel, _iconsize));
+ if( !btnPixmap.isNull() )
+ button->setIconSet(btnPixmap);
+ else
+ {
+ kdDebug() << "Failed to load custom icon" << endl;
+ button->setIconSet(iconLoader->loadIcon("kmenu", KIcon::Panel, height()));
+ }
+}
+
+QPoint TastyMenu::menupos(QWidget *widget)
+{
+ //now should look decent on all positions
+ switch( position() )
+ {
+ case pLeft:
+ {
+ return QPoint( this->mapToGlobal( this->geometry().topRight() ));
+ break;
+ }
+ case pRight:
+ {
+ QPoint buttonCoord = this->mapToGlobal(this->geometry().topLeft());
+ return QPoint( buttonCoord.x()-widget->width(), buttonCoord.y() );
+ break;
+ }
+ case pTop:
+ {
+ return QPoint( this->mapToGlobal( this->geometry().bottomLeft() ));
+ break;
+ }
+ default: //pBottom or floating
+ {
+ QPoint buttonCoord = this->mapToGlobal(this->geometry().topLeft());
+ return QPoint( buttonCoord.x(), buttonCoord.y()-widget->height() );
+ break;
+ }
+ }
+}
+
+void TastyMenu::clickSlot()
+{
+ menuTip->hideTip();
+
+ menuHandler->popup(menupos(menuHandler));
+
+ //QTimer::singleShot( 10000, this, SLOT(setButtonUp()) );
+}
+
+void TastyMenu::about()
+{
+ KAboutData data("tastymenu",
+ I18N_NOOP("Tasty Menu"),
+ "1.0.6",
+ I18N_NOOP("KMenu replacement"),
+ KAboutData::License_LGPL_V2,
+ "(c) 2006-2007, Marco Martin",0,0,"mart@notmart.org");
+
+ data.addAuthor("Marco Martin",
+ I18N_NOOP("Maintainer"),
+ "mart@notmart.org",
+ "http://www.notmart.org");
+
+ data.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\\nYour names")
+ ,I18N_NOOP("_: EMAIL OF TRANSLATORS\\nYour emails"));
+
+ data.addCredit("Yurkovsky Andrey",
+ I18N_NOOP("For the Russian translation"),
+ "anyr@tut.by");
+ data.addCredit("Jannick Kuhr",
+ I18N_NOOP("For the German translation"),
+ "jannick.kuhr@kdemail.net");
+ data.addCredit("Jesús S Fernández Prieto (xgoan)",
+ I18N_NOOP("For the Spanish translation"),
+ "jesus@infodps.com");
+ data.addCredit("Motsyo Vitaliy",
+ I18N_NOOP("For the Ukrainian translation"),
+ "vitalikmotsyo@gmail.com");
+ data.addCredit("Laurent Hilsz",
+ I18N_NOOP("For the French translation"),
+ "laurent.hilsz@gmail.com");
+ data.addCredit("Tommi Nieminen",
+ I18N_NOOP("For the Finnish translation"),
+ "translator@legisign.org");
+ data.addCredit("Matija Šuklje",
+ I18N_NOOP("For the Slovenian translation"),
+ "matija.suklje@rutka.net");
+ data.addCredit("Tomasz Argasiński",
+ I18N_NOOP("For the Polish translation"),
+ "targasinski@o2.pl");
+ data.addCredit("Ewerton de A. Dutra"
+ I18N_NOOP("For the Polish translation"),
+ "ea.dutra@gmail.com");
+
+
+ data.addCredit("Oswald Buddenhagen and Stephan Kulow",
+ I18N_NOOP("For the Switch user code from KDM"),
+ "ossi@kde.org and coolo@kde.org");
+
+ data.addCredit("The whole KBFX team",
+ I18N_NOOP("For some inspirations here and there."),
+ "http://www.kbfx.org");
+
+ data.addCredit("Seb Ruiz",
+ I18N_NOOP("For some code taken from Amarok's statistics list view"),
+ "me@sebruiz.net");
+
+ KIconLoader *iconLoader = KGlobal::iconLoader();
+ data.setProgramLogo(iconLoader->loadIcon("kmenu", KIcon::Panel).convertToImage());
+
+ KAboutApplication dialog(&data);
+ dialog.exec();
+}
+
+
+void TastyMenu::help()
+{
+ KApplication::kdeinitExec("khelpcenter", "help:/tastymenu");
+}
+
+
+void TastyMenu::preferences()
+{
+ if(KConfigDialog::showDialog("settings"))
+ return;
+
+ Appearance *appearanceDialog = new Appearance(0, "appearance" );
+ Behaviour *behaviourDialog = new Behaviour(0, "behaviour" );
+
+ KConfigDialog *dialog = new KConfigDialog(this, "settings", prefSkel,
+ KDialogBase::Tabbed,
+ KConfigDialog::Default|
+ KConfigDialog::Ok|
+ KConfigDialog::Apply|
+ KConfigDialog::Cancel );
+ dialog->addPage(appearanceDialog, i18n("Appearance"), "appearance" );
+ dialog->addPage(behaviourDialog, i18n("Behaviour"), "behaviour" );
+ connect( dialog, SIGNAL(settingsChanged()),
+ this, SLOT(updateConfiguration()) );
+ dialog->show();
+}
+
+void TastyMenu::setGlobalAccel( bool global )
+{
+ globalAccel = new KGlobalAccel(this);
+ globalAccel->insert("Toggle Tasty Menu", i18n("Toggle Tasty Menu"),
+ i18n("Toggle Tasty Menu"),
+ 0, 0, this, SLOT(clickSlot()));
+ globalAccel->readSettings();
+ globalAccel->updateConnections();
+
+ //deactivate or reactivate the global alt+f1 shotcut for kmenu
+ if( global )
+ {
+ if( !kickerConf )
+ kickerConf = KGlobal::config();
+
+ kickerConf->setGroup("Global Shortcuts");
+ QString kmenuShortcut = kickerConf->readEntry("Popup Launch Menu", "default(Alt+F1)");
+ if( kmenuShortcut=="none" )
+ return;
+ QString tastyMenuShortcut = kickerConf->readEntry("Toggle Tasty Menu", "");
+ KShortcut shortCutKey(tastyMenuShortcut);
+ kickerConf->writeEntry("Popup Launch Menu", "none");
+ kickerConf->writeEntry("Toggle Tasty Menu", kmenuShortcut);
+ kickerConf->sync();
+
+ }
+ else
+ {
+ if( !kickerConf )
+ kickerConf = KGlobal::config();
+ kickerConf->setGroup("Global Shortcuts");
+ kickerConf->deleteEntry("Popup Launch Menu");
+ kickerConf->sync();
+ }
+}
+
+
+void TastyMenu::updateConfiguration()
+{
+ kickerConf->setGroup("buttons");
+ _showBigToolTip = kickerConf->readBoolEntry("EnableIconZoom", true);
+
+ menuHandler->updateConfig();
+ setGlobalAccel(prefSkel->overrideAltF1());
+ _menuButtonLabel = prefSkel->menuButtonLabel();
+
+ if(_menuButtonLabel.isEmpty())
+ button -> setTextLabel(i18n("Menu"), false);
+ else
+ button -> setTextLabel(_menuButtonLabel, false);
+
+ button -> setUsesTextLabel(prefSkel->menuButtonLabelType()
+ != Prefs::EnumMenuButtonLabelType::MenuButtonNone);
+ loadMenuButtonIcon();
+
+ _newAppsNotification = prefSkel->newAppsNotification();
+
+ _toolTipTitle = prefSkel->toolTipTitle();
+
+ if( !_toolTipTitle.isEmpty() )
+ menuTip->setTitle(_toolTipTitle);
+}
+
+
+void TastyMenu::setNewApplicationsMessage( int number )
+{
+ if( number <= 0 )
+ {
+ menuTip ->setMessage("");
+ }
+ else
+ menuTip ->setMessage(i18n("There is one new installed application",
+ "There are %n new installed applications", number));
+ /*else if( number == 1)
+ menuTip ->setMessage(i18n("There is one new installed application"));
+ else
+ menuTip ->setMessage(i18n("There are")+" " + QString().setNum(number) +" "+ i18n("new installed applications"));*/
+
+ if( _showBigToolTip && number > numNewApplications )
+ menuTip->notify( menupos( menuTip ) );
+
+ numNewApplications = number;
+}
+
+
+int TastyMenu::widthForHeight(int height) const
+{
+ int buttonWidth = width();
+ if( position() == pTop || position() == pBottom )
+ {
+ button -> setTextPosition(QToolButton::BesideIcon);
+ if( prefSkel->menuButtonLabelType()
+ != Prefs::EnumMenuButtonLabelType::MenuButtonNone )
+ return ((button->fontMetrics()).width(button->textLabel())) + _iconsize + 10;
+ else
+ return height;
+ }
+ else
+ return buttonWidth;
+}
+
+int TastyMenu::heightForWidth(int width) const
+{
+ int buttonHeight = height();
+ if( position() == pLeft || position() == pRight )
+ {
+ if( prefSkel->menuButtonLabelType()
+ != Prefs::EnumMenuButtonLabelType::MenuButtonNone )
+ {
+ button -> setTextPosition(QToolButton::BelowIcon);
+ return ((button->fontMetrics()).height()) + _iconsize + 10;
+ }
+ else
+ return width;
+ }
+ else
+ return buttonHeight;
+}
+
+void TastyMenu::resizeEvent(QResizeEvent *e)
+{
+ int newHeight = e->size().height();
+ button->setFixedHeight(newHeight);
+ button->setFixedWidth(e->size().width());
+
+ if( newHeight >= KIcon::SizeMedium )
+ button->setUsesBigPixmap(true);
+ else
+ button->setUsesBigPixmap(false);
+
+
+ loadMenuButtonIcon();
+}
+
+void TastyMenu::mousePressEvent(QMouseEvent *e)
+{
+ menuTip->hideTip();
+
+ if(e->button()==RightButton)
+ {
+ KPopupMenu menu(this);
+
+ menu.insertTitle("Tasty Menu");
+ menu.insertItem(SmallIcon("kmenu"), i18n("&About"), 1);
+ menu.insertItem(SmallIcon("help"), i18n("&Help"), 2);
+ menu.insertItem(SmallIcon("kmenuedit"), i18n("&Edit Menu"), 3);
+ if( _newAppsNotification )
+ menu.insertItem(SmallIcon("locationbar_erase"), i18n("&Clear recently installed applications list"), 4);
+ menu.insertSeparator();
+ menu.insertItem(SmallIcon("configure_shortcuts"), i18n("&Configure Global Shortcuts..."), 5);
+ menu.insertItem(SmallIcon("configure"), i18n("&Configure..."), 6);
+
+ int choice = menu.exec(this->mapToGlobal(e->pos()));
+
+ switch( choice )
+ {
+ case 1:
+ about();
+ break;
+
+ case 2:
+ help();
+ break;
+
+ case 3:
+ KRun::runCommand ("kmenuedit");
+ break;
+
+ case 4:
+ menuHandler->clearNewInstalledApplications();
+ setNewApplicationsMessage(0);
+ menuHandler->slotUpdateApplications();
+ break;
+ case 5:
+ {
+ kickerConf->sync();
+ KKeyDialog::configure(globalAccel);
+ globalAccel->writeSettings(kickerConf);
+ globalAccel->updateConnections();
+ kickerConf->sync();
+ break;
+ }
+ case 6:
+ preferences();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void TastyMenu::enterEvent( QEvent * e )
+{
+ e=e;
+ if( _showBigToolTip && !menuHandler->isVisible() )
+ menuTip->showTip(menupos(menuTip));
+
+ KPanelApplet::enterEvent(e);
+}
+
+void TastyMenu::leaveEvent( QEvent * e )
+{
+ e=e;
+ menuTip->hideTip();
+
+ KPanelApplet::leaveEvent(e);
+}
+
+extern "C"
+{
+ KPanelApplet* init( QWidget *parent, const QString& configFile)
+ {
+ KGlobal::locale()->insertCatalogue("tastymenu");
+ return new TastyMenu(configFile, KPanelApplet::Normal,
+ KPanelApplet::About | KPanelApplet::Help | KPanelApplet::Preferences,
+ parent, "tastymenu");
+ }
+}
diff --git a/src/tastymenu.desktop b/src/tastymenu.desktop
new file mode 100644
index 0000000..475d8c0
--- /dev/null
+++ b/src/tastymenu.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Plugin
+Encoding=UTF-8
+Comment=A KMenu replacement
+
+Name=Tasty Menu
+
+Icon=kmenu
+X-KDE-Library=tastymenu_panelapplet
+X-KDE-UniqueApplet = false
diff --git a/src/tastymenu.h b/src/tastymenu.h
new file mode 100644
index 0000000..66900fe
--- /dev/null
+++ b/src/tastymenu.h
@@ -0,0 +1,165 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public *
+ * License as published by the Free Software Foundation; *
+ * either version 2 of the License, or (at your option) *
+ * any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+
+#ifndef TASTYMENU_H
+#define TASTYMENU_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kpanelapplet.h>
+#include <kiconloader.h>
+#include <qstring.h>
+#include <kconfig.h>
+#include <qpopupmenu.h>
+#include <kconfigskeleton.h>
+#include <kglobalaccel.h>
+#include <qpainter.h>
+
+#include "menuhandler.h"
+#include "prefs.h"
+#include "tastytooltip.h"
+#include "tastybutton.h"
+
+class TastyMenu : public KPanelApplet
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Construct a @ref KPanelApplet just like any other widget.
+ *
+ * @param configFile The configFile handed over in the factory function.
+ * @param Type The applet @ref type().
+ * @param actions Standard RMB menu actions supported by the applet (see @ref action() ).
+ * @param parent The pointer to the parent widget handed over in the factory function.
+ * @param name A Qt object name for your applet.
+ **/
+ TastyMenu(const QString& configFile, Type t = Normal, int actions = 0,
+ QWidget *parent = 0, const char *name = 0);
+ /** destructor */
+ ~TastyMenu();
+
+ /**
+ * Retrieve a suggested width for a given height.
+ *
+ * Every applet should reimplement this function.
+ *
+ * Depending on the panel orientation the height (horizontal panel) or the
+ * width (vertical panel) of the applets is fixed.
+ * The exact values of the fixed size component depend on the panel size.
+ *
+ * On a horizontal panel the applet height is fixed, the panel will
+ * call @ref widthForHeight(int height) with @p height
+ * equal to 'the fixed applet height'
+ * when laying out the applets.
+ *
+ * The applet can now choose the other size component (width)
+ * based on the given height.
+ *
+ * The width you return is granted.
+ **/
+ virtual int widthForHeight(int height) const;
+ /**
+ * @return A suggested height for a given width.
+ *
+ * Every applet should reimplement this function.
+ *
+ * Depending on the panel orientation the height (horizontal panel) or the
+ * width (vertical panel) of the applets is fixed.
+ * The exact values of the fixed size component depend on the panel size.
+ *
+ * On a vertical panel the applet width is fixed, the panel will
+ * call @ref heightForWidth(int width) with @p width
+ * equal to 'the fixed applet width'
+ * when laying out the applets.
+ *
+ * The applet can now choose the other size component (height)
+ * based on the given width.
+ *
+ * The height you return is granted.
+ **/
+ virtual int heightForWidth(int width) const;
+ /**
+ * Is called when the user selects "About" from the applets RMB menu.
+ * Reimplement this function to launch a about dialog.
+ *
+ * Note that this is called only when your applet supports the About action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ virtual void about();
+ /**
+ * Is called when the user selects "Help" from the applets RMB menu.
+ * Reimplement this function to launch a manual or help page.
+ *
+ * Note that this is called only when your applet supports the Help action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ virtual void help();
+ /**
+ * Is called when the user selects "Preferences" from the applets RMB menu.
+ * Reimplement this function to launch a preferences dialog or kcontrol module.
+ *
+ * Note that this is called only when your applet supports the preferences action.
+ * See @ref Action and @ref KPanelApplet().
+ **/
+ virtual void preferences();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void enterEvent( QEvent * e );
+ virtual void leaveEvent( QEvent * e );
+
+private:
+ KSharedConfig *kConfig;
+ Prefs *prefSkel;
+ KConfig *kickerConf;
+ MenuHandler *menuHandler;
+ TastyButton *button;
+ TastyToolTip *menuTip;
+ QPoint menupos(QWidget *widget);
+ KGlobalAccel *globalAccel;
+ KIconLoader *iconLoader;
+ int numNewApplications;
+
+
+ QString _menuButtonLabel;
+ QString _menuButtonIcon;
+ QString _toolTipTitle;
+ bool _newAppsNotification;
+ int _iconsize;
+ bool _showBigToolTip;
+
+ void setGlobalAccel( bool global );
+ void loadMenuButtonIcon();
+
+private slots:
+
+ void clickSlot();
+ void updateConfiguration();
+ void setNewApplicationsMessage( int number );
+ void setButtonUp(){ button->setDown(false); }
+};
+
+#endif
diff --git a/src/tastymenu.kcfg b/src/tastymenu.kcfg
new file mode 100644
index 0000000..792bbe7
--- /dev/null
+++ b/src/tastymenu.kcfg
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg>
+ <kcfgfile arg="true"/>
+
+ <group name="Appearance">
+ <entry name="IconSize1" type="Int">
+ <label>Size of the menu icons, first column.</label>
+ <default>22</default>
+ <min>16</min>
+ <max>64</max>
+ </entry>
+ <entry name="IconSize2" type="Int">
+ <label>Size of the menu icons, first column.</label>
+ <default>22</default>
+ <min>16</min>
+ <max>64</max>
+ </entry>
+ <entry name="IconSize3" type="Int">
+ <label>Size of the menu icons, first column.</label>
+ <default>22</default>
+ <min>16</min>
+ <max>64</max>
+ </entry>
+ <entry name="ActionIconSize" type="Int">
+ <label>Size of the menu icons.</label>
+ <default>16</default>
+ <min>16</min>
+ <max>48</max>
+ </entry>
+
+ <entry key="MenuButtonLabelType" type="Enum" >
+ <choices>
+ <choice name="MenuButtonText">
+ <label>Text</label>
+ </choice>
+ <choice name="MenuButtonNone">
+ <label>None</label>
+ </choice>
+ </choices>
+ <default>MenuButtonText</default>
+ <label>Botton label Type</label>
+ </entry>
+
+ <entry name="MenuButtonLabel" type="String">
+ <label>Button label text to be displayed.</label>
+ </entry>
+
+ <entry key="MenuButtonIconType" type="Enum" >
+ <choices>
+ <choice name="Icon">
+ <label>Icon</label>
+ </choice>
+ <choice name="IconNone">
+ <label>None</label>
+ </choice>
+ </choices>
+ <default>Icon</default>
+ <label>Button icon Type</label>
+ </entry>
+
+ <entry name="MenuButtonIcon" type="String">
+ <label>Button icon to be displayed.</label>
+ <default>kmenu</default>
+ </entry>
+
+ <entry name="DisplaySubText" type="Bool">
+ <label>If display the application descritption under the name</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="ToolTipTitle" type="String">
+ <label>Text of the main tooltip</label>
+ </entry>
+
+ <entry name="MenuWidth" type="Int">
+ <label>Percentage of the menu width compared to screen.</label>
+ <default>70</default>
+ <min>10</min>
+ <max>90</max>
+ </entry>
+
+ <entry name="MenuHeight" type="Int">
+ <label>Percentage of the menu height compared to screen.</label>
+ <default>70</default>
+ <min>10</min>
+ <max>90</max>
+ </entry>
+
+ <entry name="ShowExpander" type="Bool">
+ <label>If the three expanders should be shown in the applications list</label>
+ <default>false</default>
+ </entry>
+
+ <entry name="AlwaysCollapsed" type="Bool">
+ <label>If the applications categories should be collapsed by default</label>
+ <default>false</default>
+ </entry>
+ </group>
+
+ <group name="Behaviour">
+ <entry name="KerryIntegration" type="Bool">
+ <label>If the search field should perform queries with Kerry Beagle</label>
+ <default>false</default>
+ </entry>
+ <entry name="StrigiIntegration" type="Bool">
+ <label>If the search field should perform queries with Strigi.
+ It has no effect when Kerry integration is enabled</label>
+ <default>false</default>
+ </entry>
+
+ <entry name="OverrideAltF1" type="Bool">
+ <label>If Alt+F1 shortcut should be used by Tasty Menu</label>
+ <default>false</default>
+ </entry>
+
+ <entry name="NewAppsNotification" type="Bool">
+ <label>notify and highlight entries of recently installed applications.</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="HideOneChild" type="Bool">
+ <label>If Categories with only one child should be hidden</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="Alphabetical" type="Bool">
+ <label>Always show entries in alphabetical order</label>
+ <default>false</default>
+ </entry>
+
+ <entry name="ShowSaveSession" type="Bool">
+ <label>Show "Save session" entry in the user menu</label>
+ <default>false</default>
+ </entry>
+ </group>
+
+ <group name="AppState">
+ <entry name="MenuMode" type="Int">
+ <label>The current mode for the first column.</label>
+ <default>0</default>
+ </entry>
+
+ <entry name="CurrentCategory" type="String">
+ <label>currently open submenu.</label>
+ </entry>
+
+ <entry name="FavouriteApps" type="PathList">
+ <label>The list for favourite apps.</label>
+ </entry>
+
+ <entry name="OldInstalledApps" type="PathList">
+ <label>The list of all installed apps.</label>
+ </entry>
+ <entry name="OldInstalledAppsAge" type="Int">
+ <label>When the list of old installed apps was built.</label>
+ </entry>
+
+ <entry name="NewInstalledApps" type="PathList">
+ <label>The list of recently installed apps.</label>
+ </entry>
+ <entry name="NewInstalledAppsTimeStamps" type="IntList">
+ <label>Timestamps for the list of recently installed apps.</label>
+ </entry>
+
+
+ <entry name="IsNormalWindow" type="Bool">
+ <label>If the menu is a Popup or a normal window</label>
+ <default>false</default>
+ </entry>
+ <entry name="NormalWindowWidth" type="Int">
+ <label>Width of the normal window (ignored in PopUp mode)</label>
+ <default>400</default>
+ </entry>
+ <entry name="NormalWindowHeight" type="Int">
+ <label>Height of the normal window (ignored in PopUp mode)</label>
+ <default>300</default>
+ </entry>
+ <entry name="NormalWindowX" type="Int">
+ <label>X coord of the normal window (ignored in PopUp mode)</label>
+ <default>0</default>
+ </entry>
+ <entry name="NormalWindowY" type="Int">
+ <label>Y coord of the normal window (ignored in PopUp mode)</label>
+ <default>0</default>
+ </entry>
+ </group>
+</kcfg> \ No newline at end of file
diff --git a/src/tastymenu.lsm b/src/tastymenu.lsm
new file mode 100644
index 0000000..44d525c
--- /dev/null
+++ b/src/tastymenu.lsm
@@ -0,0 +1,16 @@
+Begin3
+Title: TastyMenu -- Some description
+Version: 0.1
+Entered-date:
+Description:
+Keywords: KDE Qt
+Author: Marco Martin <notmart@gmail.com>
+Maintained-by: Marco Martin <notmart@gmail.com>
+Home-page:
+Alternate-site:
+Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+ xxxxxx tastymenu-0.1.tar.gz
+ xxx tastymenu-0.1.lsm
+Platform: Linux. Needs KDE
+Copying-policy: GPL
+End
diff --git a/src/tastytooltip.cpp b/src/tastytooltip.cpp
new file mode 100644
index 0000000..27f6a12
--- /dev/null
+++ b/src/tastytooltip.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "tastytooltip.h"
+
+#include <qlabel.h>
+#include <qtimer.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <qbutton.h>
+
+
+TastyToolTip::TastyToolTip( QWidget * parent,const char * name, WFlags fl)
+ : QWidget(parent, name, fl|WX11BypassWM )
+{
+ iconName = "kmenu";
+ tastyToolTipLayout = new QVBoxLayout( this, 0, 0, "tastyToolTipLayout");
+ toolTipWidget = new TastyToolTipWidget(this);
+ tastyToolTipLayout->addWidget(toolTipWidget);
+}
+
+
+void TastyToolTip::loadIcon( QString icon )
+{
+ iconName = icon;
+ KIconLoader *iconLoader = KGlobal::iconLoader();
+ QPixmap btnPixmap(iconLoader->loadIcon(icon, KIcon::Panel, KIcon::SizeHuge));
+
+ if( !btnPixmap.isNull() )
+ toolTipWidget->iconPixmap->setPixmap(btnPixmap);
+ else
+ {
+ kdDebug() << "Failed to load custom icon" << endl;
+ toolTipWidget->iconPixmap->setPixmap(iconLoader->loadIcon("kmenu", KIcon::Panel, KIcon::SizeHuge));
+ }
+}
+
+TastyToolTip::~TastyToolTip()
+{
+}
+
+
+void TastyToolTip::showTip(const QPoint & point)
+{
+ move(point);
+ QTimer::singleShot(250, this, SLOT(show()));
+}
+
+void TastyToolTip::show()
+{
+ QButton *button = dynamic_cast<QButton *>(parent());
+ if(button && button->hasMouse() && !button->isDown())
+ QWidget::show();
+}
+
+void TastyToolTip::hideTip( )
+{
+ QTimer::singleShot(250, this, SLOT(hide()));
+}
+
+void TastyToolTip::notify(const QPoint & point )
+{
+ move(point);
+ show();
+ QTimer::singleShot(5000, this, SLOT(hide()));
+}
+
+void TastyToolTip::setMessage( QString message )
+{
+ KIconLoader *iconLoader = KGlobal::iconLoader();
+ toolTipWidget->MessageLabel->setText(message);
+
+ if( message.length() > 0 )
+ toolTipWidget->iconPixmap->setPixmap(iconLoader->loadIcon("messagebox_info", KIcon::Panel, KIcon::SizeHuge));
+ else
+ loadIcon(iconName);
+}
+
+void TastyToolTip::setTitle( QString title )
+{
+ if( !title.isEmpty() )
+ toolTipWidget->appNameLabel->setText( title );
+}
+
diff --git a/src/tastytooltip.h b/src/tastytooltip.h
new file mode 100644
index 0000000..aea0838
--- /dev/null
+++ b/src/tastytooltip.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Marco Martin *
+ * notmart@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef TASTYTOOLTIP_H
+#define TASTYTOOLTIP_H
+
+#include <qwidget.h>
+#include <qlayout.h>
+
+#include "tastytooltipwidget.h"
+
+/**
+ @author Marco Martin <notmart@gmail.com>
+*/
+class TastyToolTip : public QWidget
+{
+public:
+ TastyToolTip( QWidget * parent=0,const char * name=0, WFlags fl=WType_TopLevel);
+
+ ~TastyToolTip();
+
+ void showTip(const QPoint & point);
+ void hideTip( );
+ void loadIcon( QString iconName );
+ void notify(const QPoint & point );
+ void setMessage( QString message );
+ void setTitle( QString title );
+
+protected:
+ virtual void mousePressEvent( QMouseEvent * e ){e=e;hide();}
+
+private:
+
+ QString iconName;
+ TastyToolTipWidget * toolTipWidget;
+ QVBoxLayout *tastyToolTipLayout;
+
+public slots:
+ virtual void show();
+
+};
+
+#endif
diff --git a/src/tastytooltipwidget.ui b/src/tastytooltipwidget.ui
new file mode 100644
index 0000000..faacb2e
--- /dev/null
+++ b/src/tastytooltipwidget.ui
@@ -0,0 +1,109 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>TastyToolTipWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TastyToolTipWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>391</width>
+ <height>127</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Tasty Menu</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>iconPixmap</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>64</width>
+ <height>64</height>
+ </size>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>appNameLabel</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Tasty Menu&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>DescLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Applications, tasks and desktop sessions</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>MessageLabel</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>