summaryrefslogtreecommitdiffstats
path: root/starter
diff options
context:
space:
mode:
Diffstat (limited to 'starter')
-rw-r--r--starter/Makefile.am18
-rw-r--r--starter/Themes/Apple Aqua/bStarter.pngbin0 -> 1099 bytes
-rw-r--r--starter/Themes/Apple Aqua/bStarter_down.pngbin0 -> 1633 bytes
-rw-r--r--starter/Themes/Apple Aqua/bStarter_hover.pngbin0 -> 1558 bytes
-rw-r--r--starter/Themes/Apple Graphite/bStarter.pngbin0 -> 1363 bytes
-rw-r--r--starter/Themes/Apple Graphite/bStarter_down.pngbin0 -> 1070 bytes
-rw-r--r--starter/Themes/Apple Graphite/bStarter_hover.pngbin0 -> 1564 bytes
-rw-r--r--starter/Themes/Apple Panther/README1
-rw-r--r--starter/Themes/Apple Panther/base.pngbin0 -> 1162 bytes
-rw-r--r--starter/Themes/Apple Panther/down.pngbin0 -> 915 bytes
-rw-r--r--starter/Themes/Apple Panther/hover.pngbin0 -> 896 bytes
-rw-r--r--starter/Themes/kickerbg-b.pngbin0 -> 3285 bytes
-rw-r--r--starter/Themes/kickerbg-g.pngbin0 -> 2961 bytes
-rw-r--r--starter/baghiralinkdrag.cpp125
-rw-r--r--starter/baghiralinkdrag.h24
-rw-r--r--starter/config.ui575
-rw-r--r--starter/cr22-action-bStarter.pngbin0 -> 1209 bytes
-rw-r--r--starter/cr22-action-bStarter_down.pngbin0 -> 1409 bytes
-rw-r--r--starter/cr22-action-bStarter_hover.pngbin0 -> 1410 bytes
-rw-r--r--starter/help.ui123
-rw-r--r--starter/linkconfig.ui184
-rw-r--r--starter/menu.cpp2249
-rw-r--r--starter/menu.h320
-rw-r--r--starter/mykey.h73
-rw-r--r--starter/po/Makefile.am1
-rw-r--r--starter/po/de.po351
-rw-r--r--starter/po/starter.pot299
-rw-r--r--starter/starter.cpp483
-rw-r--r--starter/starter.desktop7
-rw-r--r--starter/starter.h72
-rw-r--r--starter/starterconfig.ui872
-rw-r--r--starter/starterhelp.ui121
-rw-r--r--starter/starteriface.h34
-rw-r--r--starter/subdirs1
34 files changed, 5933 insertions, 0 deletions
diff --git a/starter/Makefile.am b/starter/Makefile.am
new file mode 100644
index 0000000..6fee0e8
--- /dev/null
+++ b/starter/Makefile.am
@@ -0,0 +1,18 @@
+INCLUDES= $(all_includes)
+METASOURCES = AUTO
+KDE_ICON = AUTO
+
+lib_LTLIBRARIES = libbaghirastarter.la
+
+libbaghirastarter_la_SOURCES = baghiralinkdrag.cpp menu.cpp starter.cpp starterconfig.ui starterhelp.ui config.ui help.ui linkconfig.ui starteriface.skel
+libbaghirastarter_la_LDFLAGS = -module -avoid-version $(all_libraries)
+libbaghirastarter_la_LIBADD = -lXtst $(LIB_KDEUI)
+
+starter_DATA = starter.desktop
+starterdir = $(kde_datadir)/kicker/applets
+poof_DATA = ../imagebase/poof.png
+poofdir = $(kde_datadir)/baghira
+
+messages: rc.cpp
+ $(EXTRACTRC) *.ui >> rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/starter.pot
diff --git a/starter/Themes/Apple Aqua/bStarter.png b/starter/Themes/Apple Aqua/bStarter.png
new file mode 100644
index 0000000..6cb6924
--- /dev/null
+++ b/starter/Themes/Apple Aqua/bStarter.png
Binary files differ
diff --git a/starter/Themes/Apple Aqua/bStarter_down.png b/starter/Themes/Apple Aqua/bStarter_down.png
new file mode 100644
index 0000000..fdfae84
--- /dev/null
+++ b/starter/Themes/Apple Aqua/bStarter_down.png
Binary files differ
diff --git a/starter/Themes/Apple Aqua/bStarter_hover.png b/starter/Themes/Apple Aqua/bStarter_hover.png
new file mode 100644
index 0000000..1feeab9
--- /dev/null
+++ b/starter/Themes/Apple Aqua/bStarter_hover.png
Binary files differ
diff --git a/starter/Themes/Apple Graphite/bStarter.png b/starter/Themes/Apple Graphite/bStarter.png
new file mode 100644
index 0000000..6fcac0e
--- /dev/null
+++ b/starter/Themes/Apple Graphite/bStarter.png
Binary files differ
diff --git a/starter/Themes/Apple Graphite/bStarter_down.png b/starter/Themes/Apple Graphite/bStarter_down.png
new file mode 100644
index 0000000..d691c93
--- /dev/null
+++ b/starter/Themes/Apple Graphite/bStarter_down.png
Binary files differ
diff --git a/starter/Themes/Apple Graphite/bStarter_hover.png b/starter/Themes/Apple Graphite/bStarter_hover.png
new file mode 100644
index 0000000..914c5b8
--- /dev/null
+++ b/starter/Themes/Apple Graphite/bStarter_hover.png
Binary files differ
diff --git a/starter/Themes/Apple Panther/README b/starter/Themes/Apple Panther/README
new file mode 100644
index 0000000..8ff4799
--- /dev/null
+++ b/starter/Themes/Apple Panther/README
@@ -0,0 +1 @@
+Contributed by Arnaud
diff --git a/starter/Themes/Apple Panther/base.png b/starter/Themes/Apple Panther/base.png
new file mode 100644
index 0000000..d50edc6
--- /dev/null
+++ b/starter/Themes/Apple Panther/base.png
Binary files differ
diff --git a/starter/Themes/Apple Panther/down.png b/starter/Themes/Apple Panther/down.png
new file mode 100644
index 0000000..69e2884
--- /dev/null
+++ b/starter/Themes/Apple Panther/down.png
Binary files differ
diff --git a/starter/Themes/Apple Panther/hover.png b/starter/Themes/Apple Panther/hover.png
new file mode 100644
index 0000000..7bc9841
--- /dev/null
+++ b/starter/Themes/Apple Panther/hover.png
Binary files differ
diff --git a/starter/Themes/kickerbg-b.png b/starter/Themes/kickerbg-b.png
new file mode 100644
index 0000000..3ac9fa5
--- /dev/null
+++ b/starter/Themes/kickerbg-b.png
Binary files differ
diff --git a/starter/Themes/kickerbg-g.png b/starter/Themes/kickerbg-g.png
new file mode 100644
index 0000000..a59138f
--- /dev/null
+++ b/starter/Themes/kickerbg-g.png
Binary files differ
diff --git a/starter/baghiralinkdrag.cpp b/starter/baghiralinkdrag.cpp
new file mode 100644
index 0000000..9c54011
--- /dev/null
+++ b/starter/baghiralinkdrag.cpp
@@ -0,0 +1,125 @@
+#include <qbuffer.h>
+#include "baghiralinkdrag.h"
+
+static bool _accepted;
+
+#define _TLO_ 0
+#define _TO_ 4*sizeof(int)
+#define _CLO_ 1*sizeof(int)
+#define _CO_ 4*sizeof(int) + title.length()*sizeof(QChar)
+#define _CO2_ 4*sizeof(int) + title->length()*sizeof(QChar)
+#define _ILO_ 2*sizeof(int)
+#define _IO_ 4*sizeof(int) + (title.length()+command.length())*sizeof(QChar)
+#define _IO2_ 4*sizeof(int) + (title->length()+command->length())*sizeof(QChar)
+#define _IxO_ 3*sizeof(int)
+
+BaghiraLinkDrag::BaghiraLinkDrag(QString title, QString command, QString icon, int index, QWidget* dragSource) : QDragObject(dragSource, 0)
+
+{
+ _accepted = false;
+ a.resize((title.length()+command.length()+icon.length())*sizeof(QChar)+4*sizeof(int));
+
+ QChar* tmpChar;
+ int tmpLength;
+
+ tmpChar = const_cast<QChar*>(title.unicode());
+ tmpLength = title.length();
+ memcpy(a.data(), &tmpLength, sizeof(int));
+ memcpy(a.data() + _TO_ , tmpChar, tmpLength*sizeof(QChar));
+
+ tmpChar = const_cast<QChar*>(command.unicode());
+ tmpLength = command.length();
+ memcpy(a.data() + _CLO_ , &tmpLength, sizeof(int));
+ memcpy(a.data() + _CO_, tmpChar, tmpLength*sizeof(QChar));
+
+ tmpChar = const_cast<QChar*>(icon.unicode());
+ tmpLength = icon.length();
+ memcpy(a.data() + _ILO_, &tmpLength, sizeof(int));
+ memcpy(a.data() + _IO_, tmpChar, tmpLength*sizeof(QChar));
+
+ memcpy(a.data() + _IxO_, &index, sizeof(int));
+}
+
+BaghiraLinkDrag::~BaghiraLinkDrag()
+{
+}
+
+bool BaghiraLinkDrag::decode( const QMimeSource * e, QString * title, QString * command, QString * icon, int * index)
+{
+ QByteArray a = e->encodedData("application/baghiralink");
+
+ if (a.size() < 4*sizeof(int)) // some empty stuff
+ {
+ return false;
+ }
+
+ QChar* tmpChar;
+ int tmpLength;
+
+ memcpy(&tmpLength, a.data(), sizeof(int));
+ tmpChar = new QChar[tmpLength];
+ memcpy(tmpChar, a.data() + _TO_, tmpLength*sizeof(QChar));
+ title->setUnicode(tmpChar, tmpLength);
+ delete tmpChar;
+
+ memcpy(&tmpLength, a.data() + _CLO_, sizeof(int));
+ tmpChar = new QChar[tmpLength];
+ memcpy(tmpChar, a.data() + _CO2_, tmpLength*sizeof(QChar));
+ command->setUnicode(tmpChar, tmpLength);
+ delete tmpChar;
+
+ memcpy(&tmpLength, a.data() + _ILO_, sizeof(int));
+ tmpChar = new QChar[tmpLength];
+ memcpy(tmpChar, a.data() + _IO2_, tmpLength*sizeof(QChar));
+ icon->setUnicode(tmpChar, tmpLength);
+ delete tmpChar; tmpChar = 0L;
+
+ memcpy(index, a.data() + _IxO_, sizeof(int));
+
+ return true;
+}
+
+bool BaghiraLinkDrag::accepted()
+{
+ return _accepted;
+}
+
+bool BaghiraLinkDrag::canDecode( const QMimeSource * e )
+{
+ return e->provides("application/baghiralink");
+#if 0
+ if (!e->provides("application/baghiralink"))
+ {
+ return false;
+ }
+ QByteArray a = e->encodedData("application/baghiralink");
+ if (a.size() != BAGHIRALINK_BUFSIZE)
+ {
+ return false;
+ }
+ return true;
+#endif
+}
+
+void BaghiraLinkDrag::setAccepted()
+{
+ _accepted = true;
+}
+
+const char * BaghiraLinkDrag::format ( int i ) const
+{
+ if (i == 0)
+ {
+ return "application/baghiralink";
+ }
+ return 0;
+}
+
+QByteArray BaghiraLinkDrag::encodedData ( const char * mimeType) const
+{
+ if (QString("application/baghiralink") == mimeType)
+ {
+ return a;
+ }
+ return QByteArray();
+}
diff --git a/starter/baghiralinkdrag.h b/starter/baghiralinkdrag.h
new file mode 100644
index 0000000..3aca9ec
--- /dev/null
+++ b/starter/baghiralinkdrag.h
@@ -0,0 +1,24 @@
+#ifndef _BAGHIRALINKDRAG_H_
+#define _BAGHIRALINKDRAG_H_
+
+#include <qdragobject.h>
+#include <qstring.h>
+
+class BaghiraLinkDrag : public QDragObject
+{
+// Q_OBJECT
+
+public:
+ BaghiraLinkDrag(QString title, QString command, QString icon, int index = -1, QWidget* dragSource = 0);
+ ~BaghiraLinkDrag();
+ static bool decode( const QMimeSource * e, QString * title, QString * command, QString * icon, int * index);
+ static bool canDecode( const QMimeSource * e);
+ static void setAccepted( );
+ virtual const char * format ( int i = 0 ) const;
+ virtual QByteArray encodedData ( const char * ) const;
+ static bool accepted( );
+private:
+ QByteArray a;
+};
+
+#endif
diff --git a/starter/config.ui b/starter/config.ui
new file mode 100644
index 0000000..ebc7956
--- /dev/null
+++ b/starter/config.ui
@@ -0,0 +1,575 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ConfigDialog</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ConfigDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>658</width>
+ <height>629</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Entry</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QPushButton" row="1" column="0">
+ <property name="name">
+ <cstring>buttonDetail</cstring>
+ </property>
+ <property name="text">
+ <string>Extended Mode</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>baseGroup</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="title">
+ <string>Basic Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>category</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="insertionPolicy">
+ <enum>AfterCurrent</enum>
+ </property>
+ <property name="autoCompletion">
+ <bool>true</bool>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="contextMenuEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Is a</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>appName</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>command</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>genericName</cstring>
+ </property>
+ </widget>
+ <widget class="KIconButton" row="0" column="2" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>iconButton</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>60</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>60</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="iconSize">
+ <number>48</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Command&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;Keywords&lt;/i&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;&lt;b&gt;Name&lt;/b&gt;&lt;/i&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;&lt;b&gt;Category&lt;/b&gt;&lt;/i&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>keywords</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>startupFeedback</cstring>
+ </property>
+ <property name="text">
+ <string>Activate startup feedback</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>showInSystray</cstring>
+ </property>
+ <property name="text">
+ <string>Show in system tray</string>
+ </property>
+ </widget>
+ <widget class="KTextEdit" row="1" column="4" rowspan="4" colspan="1">
+ <property name="name">
+ <cstring>description</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ </widget>
+ <widget class="Line" row="0" column="3" rowspan="5" colspan="1">
+ <property name="name">
+ <cstring>line4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>VLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>extendedGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Extended Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="2" colspan="5">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Working directory</string>
+ </property>
+ </widget>
+ <widget class="Line" row="2" column="0" rowspan="1" colspan="6">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>startInTerminal</cstring>
+ </property>
+ <property name="text">
+ <string>Start in terminal</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel9</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Terminal settings</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="2" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>terminalSettings</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="Line" row="5" column="0" rowspan="1" colspan="6">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>startAsUser</cstring>
+ </property>
+ <property name="text">
+ <string>Start as different user</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="7" column="2" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>username</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="Line" row="8" column="0" rowspan="2" colspan="6">
+ <property name="name">
+ <cstring>line3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="10" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Shortcut</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="4" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>workingDir</cstring>
+ </property>
+ </widget>
+ <spacer row="11" column="5">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>250</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KKeyButton" row="9" column="3" rowspan="3" colspan="2">
+ <property name="name">
+ <cstring>shortcut</cstring>
+ </property>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </widget>
+ <spacer row="11" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>ConfigDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>ConfigDialog</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>startInTerminal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel9</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>startInTerminal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>terminalSettings</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>startAsUser</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel6</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>startAsUser</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>username</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>buttonDetail</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>extendedGroup</receiver>
+ <slot>setShown(bool)</slot>
+ </connection>
+ <connection>
+ <sender>buttonDetail</sender>
+ <signal>released()</signal>
+ <receiver>ConfigDialog</receiver>
+ <slot>adjustSize()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>appName</tabstop>
+ <tabstop>genericName</tabstop>
+ <tabstop>category</tabstop>
+ <tabstop>command</tabstop>
+ <tabstop>keywords</tabstop>
+ <tabstop>startupFeedback</tabstop>
+ <tabstop>showInSystray</tabstop>
+ <tabstop>iconButton</tabstop>
+ <tabstop>description</tabstop>
+ <tabstop>buttonDetail</tabstop>
+ <tabstop>workingDir</tabstop>
+ <tabstop>startInTerminal</tabstop>
+ <tabstop>terminalSettings</tabstop>
+ <tabstop>startAsUser</tabstop>
+ <tabstop>username</tabstop>
+ <tabstop>shortcut</tabstop>
+ <tabstop>buttonHelp</tabstop>
+ <tabstop>buttonOk</tabstop>
+ <tabstop>buttonCancel</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kicondialog.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>ktextedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kkeybutton.h</includehint>
+</includehints>
+</UI>
diff --git a/starter/cr22-action-bStarter.png b/starter/cr22-action-bStarter.png
new file mode 100644
index 0000000..51c829f
--- /dev/null
+++ b/starter/cr22-action-bStarter.png
Binary files differ
diff --git a/starter/cr22-action-bStarter_down.png b/starter/cr22-action-bStarter_down.png
new file mode 100644
index 0000000..069f417
--- /dev/null
+++ b/starter/cr22-action-bStarter_down.png
Binary files differ
diff --git a/starter/cr22-action-bStarter_hover.png b/starter/cr22-action-bStarter_hover.png
new file mode 100644
index 0000000..bb6932d
--- /dev/null
+++ b/starter/cr22-action-bStarter_hover.png
Binary files differ
diff --git a/starter/help.ui b/starter/help.ui
new file mode 100644
index 0000000..dbb5416
--- /dev/null
+++ b/starter/help.ui
@@ -0,0 +1,123 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>HelpDialog</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>HelpDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Help</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kTextEdit2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;&lt;font size="+3"&gt;&lt;b&gt;Menu entry editor&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;
+&lt;p align="center"&gt;----------------------------------------------------------------------------------&lt;/p&gt;
+&lt;h3&gt;Introduction&lt;/h3&gt;
+
+By default, you will only see the basic settings for the new entry. Clicking "Show More" will give you access to some extended settings that can be interesting but mostly useless for you.&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Bold options must be entered&lt;/b&gt; for a usefull entry, i&lt;i&gt;talic ones are respected by the search feature&lt;/i&gt;.
+&lt;br&gt;&lt;br&gt;
+&lt;h3&gt;Basic settings&lt;/h3&gt;
+
+&lt;b&gt;Name:&lt;/b&gt;&lt;br&gt;
+This is the visible name of your new entry and can be any string, e.g. "The Gimp".&lt;br&gt;
+(Necessary, searchkey)
+&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Is a:&lt;/b&gt;&lt;br&gt;
+Describes the applications genre (generic name), e.g. "Image manipulation"&lt;br&gt;
+(Optional, yet not searched - maybe later)
+&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Category:&lt;/b&gt;&lt;br&gt;
+Choose an existing group or add a new one. The hierarchy is represented by seperating slashes ("/"), if you want to enter a slash, you must escape it ("\/")&lt;br&gt;
+(Necessary, searchkey)
+&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Command:&lt;/b&gt;&lt;br&gt;
+The command to start the application, e.g. "gimp-remote". On *nix systems, is usually not necessary to pass the full path to the executably, but you can do so, if you want to start an executable that is shadowed by the executable in the path dir, e.g. "/usr/local/gimp-1.3/gimp-remote"&lt;br&gt;
+(Necessary, not searched)
+&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Keywords:&lt;/b&gt;&lt;br&gt;
+Comma separated list of keywords that refer to this application during search, e.g. "image manipulation,pixel,photoshop".&lt;br&gt;
+Please note:&lt;br&gt;
+1. search is &lt;i&gt;not&lt;/i&gt; case sensitive&lt;br&gt;
+2. search finds partial matches, so it's &lt;i&gt;not&lt;/i&gt; necessary to add e.g. "image,image manipulation"&lt;br&gt;
+3. different from the applications name, the keyword list will be translated (if) so if you think like "'KImage' allready contains 'image', so i don't need it as keyword" &lt;b&gt;you're wrong!&lt;/b&gt;&lt;br&gt;
+4. Finding good keywords is not simple, but in general use striking ones! "editor" is not a very good keyword, as allmost everything is an editor. (Gimp is a pixel-editor, KHexedit is a hex-editor, KEdit is a text-editor, a config dialog is a config-editor, ...)&lt;br&gt;
+(Optional, searchkey)
+&lt;br&gt;&lt;br&gt;
+&lt;b&gt;Description:&lt;/b&gt;&lt;br&gt;
+This is the longtext description of your application (not a helptext, though ;), e.g. "A powerfull image manipulator with a UI similar to photoshop. Supports Layers, filters, scripting, blahblahblah..."
+You can use Qt richtext tags and there's no limit on the size, but keep it usefull ;) let's say something about 200 chars at max.&lt;br&gt;
+(Optional, not searched)</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>buttonClose</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <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>231</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonClose</sender>
+ <signal>released()</signal>
+ <receiver>HelpDialog</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextedit.h</includehint>
+</includehints>
+</UI>
diff --git a/starter/linkconfig.ui b/starter/linkconfig.ui
new file mode 100644
index 0000000..b156900
--- /dev/null
+++ b/starter/linkconfig.ui
@@ -0,0 +1,184 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>LinkConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>LinkConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>438</width>
+ <height>173</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configure Link</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>206</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KIconButton" row="0" column="1">
+ <property name="name">
+ <cstring>icon</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="maximumSize">
+ <size>
+ <width>64</width>
+ <height>64</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSize">
+ <number>48</number>
+ </property>
+ <property name="strictIconSize">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Title&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>title</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Command&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>command</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>LinkConfig</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>LinkConfig</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kicondialog.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/starter/menu.cpp b/starter/menu.cpp
new file mode 100644
index 0000000..81611d0
--- /dev/null
+++ b/starter/menu.cpp
@@ -0,0 +1,2249 @@
+#include <qcheckbox.h>
+#include <qcursor.h>
+#include <qdatetime.h>
+#include <qdir.h>
+#include <kpopupmenu.h>
+#include <qobjectlist.h>
+#include <qpainter.h>
+#include <qptrlist.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qvbox.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <kdeversion.h>
+#include <kurl.h>
+#include <kfileitem.h>
+#include <kicondialog.h>
+#include <kiconloader.h>
+#include <kkeybutton.h>
+#include <klistbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpixmapeffect.h>
+#include <kprocess.h>
+#include <kurifilter.h>
+#include <kurl.h>
+#include <krun.h>
+#include <kservice.h>
+#include <kshortcut.h>
+#include <ksqueezedtextlabel.h>
+#include <kstandarddirs.h>
+#include <ksycocaentry.h>
+#include <ktextedit.h>
+#include <kurlrequester.h>
+#include <kwin.h>
+//WARNING: THIS IS NOT PORTABLE!
+// #include <X11/Xlib.h>
+// #include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XTest.h>
+#include <fixx11h.h>
+#include <stdlib.h>
+// TO HERE --------
+//#include "kdrawer.h"
+#include "baghiralinkdrag.h"
+#include "menu.h"
+#include "config.h"
+#include "help.h"
+#include "linkconfig.h"
+#define OPAQUE 0xffffffff
+#define OPACITY "_KDE_WM_WINDOW_OPACITY"
+
+#define _BIGSIZE_(_s_) ((_s_ == 16) ? 22 :\
+(_s_ == 22) ? 32 :\
+(_s_ == 32) ? 48 :\
+(_s_ == 48) ? 64 :\
+(_s_ == 64) ? 128 :\
+(int)(_s_*1.4))
+
+//TODO: sort functions alphabetically, split files by classes... refactoring sucks ;)
+
+static QColor commentColor;
+static QColor infoColor;
+static KConfig *config;
+static bool useKTTS;
+
+
+QString spell(const QString text)
+{
+ QString result;
+ for (uint i = 0; i < text.length(); i++)
+ {
+ result += " "; result += text[i];
+ }
+ return result;
+}
+
+/*
+ Internal class to get access to protected QBoxLayout-members
+*/
+class MyVBoxLayout : public QVBoxLayout
+{
+ friend class AppList;
+public:
+ MyVBoxLayout( QLayout * parentLayout, int spacing = -1, const char * name = 0 )
+ : QVBoxLayout( parentLayout, spacing, name ) {}
+};
+
+StartMenuButton::StartMenuButton( int size, QString icon, QString title, QString command, Orientation orientation, QWidget* parent, const char * name) : QWidget(parent, name), m_title(title), m_command(command), m_icon(icon), m_orientation(orientation), _moving(false)
+{
+ setBackgroundOrigin(QWidget::ParentOrigin);
+ int bigSize = _BIGSIZE_(size);
+ m_pix = KGlobal::iconLoader()->loadIcon(icon, KIcon::Desktop, size);
+ m_hoverPix = KGlobal::iconLoader()->loadIcon(icon, KIcon::Desktop, bigSize);
+ m_pixmapLabel = new QLabel(this, name);
+ m_pixmapLabel->setPixmap(m_pix);
+ m_pixmapLabel->setBackgroundOrigin(QWidget::AncestorOrigin);
+ QBoxLayout* layout;
+ if (orientation == Horizontal)
+ {
+ m_titleLabel = new QLabel("<qt><b>" + title + "</b></qt>", this, name);
+ m_titleLabel->setBackgroundOrigin(QWidget::AncestorOrigin);
+ m_titleLabel->setTextFormat( Qt::RichText );
+ m_titleLabel->setAlignment ( Qt::AlignLeft | Qt::AlignVCenter );
+ m_pixmapLabel->setFixedSize(bigSize+2,bigSize+2);
+ m_pixmapLabel->setAlignment ( Qt::AlignCenter );
+ layout = new QHBoxLayout ( this );
+ layout->addSpacing ( 5 );
+ layout->addWidget(m_pixmapLabel,0,Qt::AlignCenter);
+ layout->addSpacing ( 2 );
+ layout->addWidget(m_titleLabel,1);
+ layout->addSpacing ( 5 );
+ }
+ else if (orientation == Vertical)
+ {
+ m_titleLabel = new QLabel("<qt><b>" + title + "</b></qt>", this, name);
+ m_titleLabel->setBackgroundOrigin(QWidget::AncestorOrigin);
+ m_titleLabel->setTextFormat( Qt::RichText );
+ m_titleLabel->setAlignment ( Qt::AlignHCenter | Qt::AlignTop );
+ m_pixmapLabel->setFixedSize(bigSize+2,bigSize+2);
+ m_pixmapLabel->setAlignment ( Qt::AlignCenter );
+ layout = new QVBoxLayout ( this );
+ layout->addSpacing ( 5 );
+ layout->addWidget(m_pixmapLabel,0,Qt::AlignCenter);
+ layout->addSpacing ( 2 );
+ layout->addWidget(m_titleLabel,1);
+ layout->addSpacing ( 5 );
+ }
+ else
+ {
+ setFixedSize(bigSize+2,bigSize+2);
+ m_pixmapLabel->setAlignment ( Qt::AlignCenter );
+ m_pixmapLabel->setFixedSize(bigSize+2,bigSize+2);
+ }
+ setCursor(Qt::PointingHandCursor);
+}
+
+void StartMenuButton::reloadIcon(int size)
+{
+ int bigSize = _BIGSIZE_(size);
+ if (m_orientation == Status)
+ setFixedSize(bigSize+2,bigSize+2);
+ m_pixmapLabel->setFixedSize(bigSize+2,bigSize+2);
+ m_pix = KGlobal::iconLoader()->loadIcon(m_icon, KIcon::Desktop, size);
+ m_hoverPix = KGlobal::iconLoader()->loadIcon(m_icon, KIcon::Desktop, bigSize);
+ m_pixmapLabel->setPixmap(m_pix);
+}
+
+void StartMenuButton::smartMove(QPoint &pt)
+{
+}
+
+void StartMenuButton::smartMove(int x, int y)
+{
+ if (!dynamic_cast<Panel*>(parentWidget()))
+ return;
+ StartMenuButton *bt = 0L;
+ QObjectList *kids = const_cast<QObjectList*>(parentWidget()->children());
+ QRect dRect(QPoint(x,y), size());
+ QRect bRect;
+ if (kids && !kids->isEmpty())
+ {
+ QObject *o;
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((o != this) && (bt = (dynamic_cast<StartMenuButton*>(o))))
+ {
+ bRect = QRect(bt->pos(), bt->size());
+ if (dRect.intersects(bRect))
+ break;
+ bt = 0L;
+ }
+ }
+ if (!bt)
+ {
+ move(dRect.topLeft());
+ int dst;
+ if (((Panel*)parentWidget())->orientation() == Qt::Horizontal)
+ {
+ dst = pos().x() + width() - parentWidget()->width();
+ if (dst > 0)
+ emit updateSize(1);
+ else if (pos().x() < 0)
+ emit updateSize(-1);
+ }
+ else
+ {
+ dst = pos().y() + height() - parentWidget()->height();
+ if (dst > 0)
+ emit updateSize(1);
+ else if (pos().y() < 0)
+ emit updateSize(-1);
+ }
+ ((Panel*)parentWidget())->ensureVisible(dRect);
+ }
+ else if (
+ // left of center of left
+ (dRect.right() > bRect.right() && dRect.x() < bRect.right() - bRect.width() / 2) ||
+ // right of center of right
+ (dRect.x() < bRect.x() && dRect.right() > bRect.x() + bRect.width() / 2) ||
+ // up of center of upper
+ (dRect.bottom() > bRect.bottom() && dRect.y() < bRect.bottom() - bRect.height() / 2) ||
+ // below center of lower
+ (dRect.y() < bRect.y() && dRect.bottom() > bRect.y() + bRect.height() / 2)
+ )
+ {
+ QPoint bPt = bt->pos();
+ bt->move(pos());
+ move(bPt);
+ }
+}
+
+void StartMenuButton::mouseReleaseEvent ( QMouseEvent * mre)
+{
+ if (mre->state() & Qt::LeftButton)
+ {
+ if (_moving) { _moving = false; return; }
+ emit pressed(m_command);
+ return;
+ }
+ if (mre->state() & Qt::RightButton)
+ {
+ if (!dynamic_cast<Panel*>(parentWidget()))
+ return;
+ ((Panel*)parentWidget())->linkConfigDialog->setCaption ( i18n("Configure Link") );
+ ((Panel*)parentWidget())->linkConfigDialog->title->setText(m_title);
+ ((Panel*)parentWidget())->linkConfigDialog->command->setText(m_command);
+ ((Panel*)parentWidget())->linkConfigDialog->icon->setIcon(m_icon);
+ disconnect(((Panel*)parentWidget())->linkConfigDialog->buttonOk, SIGNAL(clicked()), 0, 0);
+ connect(((Panel*)parentWidget())->linkConfigDialog->buttonOk, SIGNAL(clicked()), ((Panel*)parentWidget())->linkConfigDialog, SLOT(accept()));
+ connect(((Panel*)parentWidget())->linkConfigDialog->buttonOk, SIGNAL(clicked()), this, SLOT(edit()));
+ ((Panel*)parentWidget())->linkConfigDialog->exec();
+ }
+}
+
+void StartMenuButton::edit()
+{
+ if (!dynamic_cast<Panel*>(parentWidget()))
+ return;
+ m_command = ((Panel*)parentWidget())->linkConfigDialog->command->text();
+ if (m_command.isEmpty())
+ {
+ deleteLater();
+ return;
+ }
+ m_icon = ((Panel*)parentWidget())->linkConfigDialog->icon->icon();
+ m_title = ((Panel*)parentWidget())->linkConfigDialog->title->text();
+ int bigSize = _BIGSIZE_(((Panel*)parentWidget())->_size);
+ m_pix = KGlobal::iconLoader()->loadIcon(m_icon, KIcon::Desktop, ((Panel*)parentWidget())->_size);
+ m_hoverPix = KGlobal::iconLoader()->loadIcon(m_icon, KIcon::Desktop, bigSize);
+ m_pixmapLabel->setPixmap(m_pix);
+ if (m_orientation == Horizontal || m_orientation == Vertical)
+ m_titleLabel->setText("<qt><b>" + m_title + "</b></qt>");
+ ((Panel*)parentWidget())->linkConfigDialog->close();
+}
+
+void Panel::addIcon()
+{
+ if (!linkConfigDialog->command->text().isEmpty())
+ addIcon ( linkConfigDialog->icon->icon(), linkConfigDialog->title->text(), linkConfigDialog->command->text(), iconAddPosition );
+}
+
+void StartMenuButton::mouseMoveEvent ( QMouseEvent * mme )
+{
+ if (!dynamic_cast<Panel*>(parentWidget()))
+ return;
+ if (mme->state() & Qt::LeftButton)
+ {
+ _moving = true;
+ QPoint pt = mapToParent(mme->pos());
+ if (!(mme->state() & Qt::ShiftButton))
+ {
+ if (pt.y() < -5 || pt.y() > parentWidget()->height() + 5 || pt.x() < -5 || pt.x() > parentWidget()->width() + 5)
+ {
+ BaghiraLinkDrag *d = new BaghiraLinkDrag( m_title, m_command, m_icon, -1, parentWidget() );
+ d->setPixmap(m_hoverPix, QPoint(m_hoverPix.width()/2, m_hoverPix.height()/2));
+ d->drag();
+ if ((mme->state() & Qt::ControlButton) || BaghiraLinkDrag::accepted())
+ return;
+ ((Panel*)parentWidget())->poof();
+ // do NOT delete d.
+ return;
+ }
+ }
+ if (((Panel*)parentWidget())->orientation() == Qt::Horizontal)
+ smartMove(pt.x() - width()/2, pos().y());
+ else
+ smartMove(pos().x(), pt.y() - height()/2);
+ }
+ else
+ _moving = false;
+}
+
+
+void StartMenuButton::enterEvent( QEvent * )
+{
+ if (m_orientation == Status) emit hovered(m_title);
+ m_pixmapLabel->setPixmap(m_hoverPix);
+}
+
+void StartMenuButton::leaveEvent( QEvent * )
+{
+ if (m_orientation == Status) emit unhovered();
+ m_pixmapLabel->setPixmap(m_pix);
+}
+
+
+StartMenuEntry::StartMenuEntry(KService * service, QString relPath, int size, bool newbie, QWidget * parent) : QWidget(parent)
+{
+ groupPath = relPath;
+ forNewbie = newbie;
+ if (config) // might be first use ever...
+ {
+ QString tmpString = config->readEntry(service->desktopEntryName());
+ if (tmpString != QString::null)
+ {
+ usage = tmpString.section ( ' ', 0, 0 ).toUInt();
+ lastUse = QDate::fromString(tmpString.section ( ' ', 1, 1 ), Qt::ISODate);
+ // ranking is naiv but hopefully usefull for the beginning: often usage increases rank, time to the last usage decreases. "8" is just a "random" offset - the idea is that apps that have been used within the last week should have a higher rank than apps that don't appear in the list - setting these to - infinity isn't a good idea as well, as they might be brand new
+ rank = 8 + usage - lastUse.daysTo(QDate::currentDate());
+ }
+ else
+ {
+ usage = 0;
+ rank = 0; // neutral rank
+ }
+ }
+ else
+ {
+ qWarning("no valid config!");
+ usage = 0;
+ rank = 0; // neutral rank
+ }
+ int bigSize = _BIGSIZE_(size);
+ isCurrent = false;
+ m_service = service;
+ exec = m_service->exec();
+ display = false;
+ m_pix = m_service->pixmap( KIcon::Desktop, size );
+ m_hoverPix = m_service->pixmap( KIcon::Desktop, bigSize );
+ m_titleLabel = new QLabel("<qt><h3>" + m_service->name() + "</h3></qt>", this);
+ m_titleLabel->setTextFormat( Qt::RichText );
+ m_commentLabel = new QLabel(m_service->comment(), this);
+ m_commentLabel->setPaletteForegroundColor(commentColor);
+ m_commentLabel->setTextFormat( Qt::RichText );
+ m_pixmapLabel = new QLabel(this);
+ m_pixmapLabel->setFixedSize ( bigSize+2, bigSize+2 );
+ m_pixmapLabel->setAlignment(Qt::AlignCenter);
+ m_pixmapLabel->setPixmap(m_pix);
+ QVBoxLayout* spacer = new QVBoxLayout ( this );
+ spacer->addSpacing ( 1 );
+ QHBoxLayout* layout = new QHBoxLayout ( spacer );
+ layout->addWidget(m_pixmapLabel);
+ layout->addSpacing ( 2 );
+ QVBoxLayout* textLayout = new QVBoxLayout ( layout );
+ layout->setStretchFactor ( textLayout, 1 );
+ textLayout->addWidget(m_titleLabel);
+ textLayout->addWidget(m_commentLabel);
+ layout->addStretch();
+ spacer->addSpacing ( 1 );
+ setCursor(Qt::PointingHandCursor);
+}
+
+void StartMenuEntry::reloadIcon(int size)
+{
+ int bigSize = _BIGSIZE_(size);
+ m_pixmapLabel->setFixedSize(bigSize+2,bigSize+2);
+ m_pix = m_service->pixmap( KIcon::Desktop, size );
+ m_hoverPix = m_service->pixmap( KIcon::Desktop, bigSize );
+ m_pixmapLabel->setPixmap(m_pix);
+}
+
+StartMenuEntry::~StartMenuEntry()
+{
+// if (m_service) delete m_service; m_service = 0L;
+}
+
+void StartMenuEntry::saveStats()
+{
+ if (usage > 0)
+ config->writeEntry(m_service->desktopEntryName(), QString::number(usage) + " " + lastUse.toString(Qt::ISODate));
+}
+
+bool StartMenuEntry::operator==( const StartMenuEntry& se ) const
+{
+ return rank == se.rank;
+}
+bool StartMenuEntry::operator!=( const StartMenuEntry& se ) const
+{
+ return rank != se.rank;
+}
+bool StartMenuEntry::operator<( const StartMenuEntry& se ) const
+{
+ /*
+ if (rank == se.rank)
+ return m_titleLabel->text() < se.title();
+ else
+ */
+ return rank > se.rank; // to have descending sort order (we could also use a negative ranking...)
+}
+bool StartMenuEntry::operator>( const StartMenuEntry& se ) const
+{
+ /*
+ if (rank == se.rank)
+ return m_titleLabel->text() > se.title();
+ else
+ */
+ return rank < se.rank; // to have descending sort order (we could also use a negative ranking...)
+}
+bool StartMenuEntry::operator==( const double& d ) const
+{
+ return rank == d;
+}
+bool StartMenuEntry::operator!=( const double& d ) const
+{
+ return rank != d;
+}
+bool StartMenuEntry::operator<( const double& d ) const
+{
+ return rank > d; // to have descending sort order (we could also use a negative ranking...)
+}
+bool StartMenuEntry::operator>( const double& d ) const
+{
+ return rank < d; // to have descending sort order (we could also use a negative ranking...)
+}
+
+void StartMenuEntry::mouseReleaseEvent ( QMouseEvent * e )
+//TODO: do funny stuff with other buttons (e.g. provide edit dialog)
+{
+ if (e->button() == Qt::LeftButton)
+ {
+ m_pixmapLabel->setPixmap(m_pix);
+ execute();
+ if (!(e->state() & Qt::ControlButton))
+ emit pressed();
+ }
+ if (e->button() == Qt::RightButton)
+ {
+ emit popup(this);
+ }
+}
+
+void StartMenuEntry::mouseMoveEvent ( QMouseEvent * mme )
+{
+ if (mme->state() & Qt::LeftButton && (mme->pos().y() < 0 || mme->pos().y() > height() || mme->pos().x() < 0 || mme->pos().x() > width()))
+ {
+ BaghiraLinkDrag *d = new BaghiraLinkDrag( m_service->name(), m_service->exec(), m_service->icon(), -1, parentWidget() );
+ d->setPixmap(m_hoverPix, QPoint(m_hoverPix.width()/2, m_hoverPix.height()/2));
+ d->dragCopy();
+ // do NOT delete d.
+ }
+}
+
+void StartMenuEntry::keyPressEvent ( QKeyEvent * e )
+{
+ switch (e->key())
+ {
+ case Qt::Key_Escape:
+ emit closeMenu();
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ execute();
+ if (!(e->state() & Qt::ControlButton))
+ emit pressed();
+ break;
+ case Qt::Key_Down:
+ emit appDown();
+ break;
+ case Qt::Key_Up:
+ emit appUp();
+ break;
+ case Qt::Key_Home: // ->searchline + select
+ case Qt::Key_Left:
+ emit appLeft();
+ break;
+ default:
+ break;
+ }
+}
+
+QString StartMenuEntry::title()
+{
+ return m_titleLabel->text();
+}
+
+void StartMenuEntry::focusInEvent ( QFocusEvent * )
+{
+ isCurrent = true;
+ emit hovered("[ " + groupPath + " ] " + exec);
+ if (useKTTS)
+ {
+ QString text = i18n("for TTS output, telling which item is focussed (keyboard) and than reads the comment", "%1 focussed. %2").arg(m_titleLabel->text()).arg(m_commentLabel->text());
+ emit sayText(text);
+ }
+ setPaletteBackgroundColor(KGlobalSettings::highlightColor());
+ m_commentLabel->setPaletteBackgroundColor(KGlobalSettings::highlightColor());
+ setPaletteForegroundColor(KGlobalSettings::highlightedTextColor());
+ m_commentLabel->setPaletteForegroundColor(KGlobalSettings::highlightedTextColor());
+}
+
+void StartMenuEntry::focusOutEvent ( QFocusEvent * )
+{
+ emit unhovered();
+ isCurrent = false;
+ setPaletteBackgroundColor(KGlobalSettings::baseColor());
+ m_commentLabel->setPaletteBackgroundColor(KGlobalSettings::baseColor());
+ if (hasMouse())
+ {
+ setPaletteForegroundColor(KGlobalSettings::highlightColor());
+ m_commentLabel->setPaletteForegroundColor(KGlobalSettings::highlightColor());
+ }
+ else
+ {
+ setPaletteForegroundColor(KGlobalSettings::textColor());
+ m_commentLabel->setPaletteForegroundColor(commentColor);
+ }
+}
+
+void StartMenuEntry::enterEvent( QEvent * )
+{
+ emit hovered("[ " + groupPath + " ] " + exec);
+ if (useKTTS)
+ {
+ QString text = i18n("for TTS output, telling which item is hovered (mouse) and than reads the comment", "%1 hovered. %2").arg(m_titleLabel->text()).arg(m_commentLabel->text());
+ emit sayText(text);
+ }
+ if (!isCurrent)
+ {
+ setPaletteForegroundColor(KGlobalSettings::highlightColor());
+ m_commentLabel->setPaletteForegroundColor(KGlobalSettings::highlightColor());
+ }
+ m_pixmapLabel->setPixmap(m_hoverPix);
+}
+
+void StartMenuEntry::leaveEvent( QEvent * )
+{
+ emit unhovered();
+ if (!isCurrent)
+ {
+ setPaletteForegroundColor(KGlobalSettings::textColor());
+ m_commentLabel->setPaletteForegroundColor(commentColor);
+ }
+ m_pixmapLabel->setPixmap(m_pix);
+}
+
+void StartMenuEntry::execute()
+{
+ usage++;
+ lastUse = QDate::currentDate();
+ rank = 8 + usage;
+ KApplication::startServiceByDesktopPath(m_service->desktopEntryPath(), QStringList(), 0, 0, 0, "", true);
+ emit executed();
+}
+
+Panel::Panel(int size, QWidget * parent, const char * name) : QWidget(parent, name), _size(size), _draggedMe(false), _count(0), _orientation(Qt::Horizontal), _poof(0), _poofIndex(0), _poofAnimPix(0), _poofPix(0)
+{
+ linkConfigDialog = new LinkConfig();
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+// setPaletteBackgroundColor(KGlobalSettings::highlightColor());
+ setAcceptDrops(true);
+ config->setGroup("Panel");
+ QStringList commands = config->readListEntry("Commands", '§');
+ QStringList icons = config->readListEntry("Icons", '§');
+ QStringList offsets = config->readListEntry("Offsets", '§');
+ QStringList titles = config->readListEntry("Titles", '§');
+ QStringList::Iterator it1 = commands.begin();
+ QStringList::Iterator it2 = icons.begin();
+ QStringList::Iterator it3 = offsets.begin();
+ QStringList::Iterator it4 = titles.begin();
+ while (it1 != commands.end() &&
+ it2 != icons.end() &&
+ it3 != offsets.end() &&
+ it4 != titles.end())
+ {
+ addIcon(*it2, *it4, *it1, QPoint((*it3).toInt(),0));
+ ++it1;
+ ++it2;
+ ++it3;
+ ++it4;
+ }
+}
+
+void Panel::save(KConfig *config)
+{
+ config->setGroup("Panel");
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ StartMenuButton *bt = 0;
+ if (kids && !kids->isEmpty())
+ {
+ QStringList icons;
+ QStringList titles;
+ QStringList commands;
+ QStringList offsets;
+ QObject *o;
+ for ( o = kids->first(); o; o = kids->next() )
+ if (bt = (dynamic_cast<StartMenuButton*>(o)))
+ {
+ icons.append(bt->icon());
+ titles.append(bt->title());
+ commands.append(bt->command());
+ _orientation == Qt::Horizontal ?
+ offsets.append(QString::number(bt->x())) :
+ offsets.append(QString::number(bt->y()));
+ }
+ config->writeEntry("Commands", commands, '§');
+ config->writeEntry("Icons", icons, '§');
+ config->writeEntry("Offsets", offsets, '§');
+ config->writeEntry("Titles", titles, '§');
+ }
+}
+
+void Panel::reloadIcons( int size)
+{
+ _size = size;
+ if (_orientation == Qt::Horizontal)
+ {
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ setFixedHeight(_BIGSIZE_(_size)+4);
+ setMaximumWidth(32767);
+ }
+ else
+ {
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ setFixedWidth(_BIGSIZE_(_size)+4);
+ setMaximumHeight(32767);
+ }
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ StartMenuButton *bt = 0;
+ if (kids && !kids->isEmpty())
+ {
+ QObject *o;
+ for ( o = kids->first(); o; o = kids->next() )
+ if (bt = (dynamic_cast<StartMenuButton*>(o)))
+ {
+ bt->reloadIcon(size);
+ }
+ }
+}
+
+void Panel::ensureVisible(QRect & rect)
+{
+ int dx = 0; int dy = 0;
+ if (rect.width() > clipRegion().boundingRect().width())
+ dx = (rect.width() - clipRegion().boundingRect().width())/2 - rect.x();
+ else if (rect.right() > clipRegion().boundingRect().right())
+ dx = clipRegion().boundingRect().right() - rect.right();
+ else if (rect.x() < clipRegion().boundingRect().x())
+ dx = clipRegion().boundingRect().x() - rect.x();
+ if (rect.height() > clipRegion().boundingRect().height())
+ dy = (rect.height() - clipRegion().boundingRect().height())/2 - rect.y();
+ else if (rect.bottom() > clipRegion().boundingRect().bottom())
+ dy = clipRegion().boundingRect().bottom() - rect.bottom();
+ else if (rect.y() < clipRegion().boundingRect().y())
+ dy = clipRegion().boundingRect().y() - rect.y();
+ scroll(dx, dy);
+}
+
+void Panel::updateSize(int dst)
+{
+ if (dst > 0)
+ {
+ if (_orientation == Qt::Horizontal)
+ {
+ resize(width()+dst, height());
+ }
+ else
+ {
+ resize(width(), height()+dst);
+ }
+ }
+ else // more complex: resize and reposition all children, so first one is on (0,0)
+ {
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ if (kids && !kids->isEmpty())
+ {
+ QObject *o;
+ StartMenuButton *bt;
+ if (_orientation == Qt::Horizontal)
+ {
+ resize(width()-dst, height());
+ for ( o = kids->first(); o; o = kids->next() )
+ if (bt = (dynamic_cast<StartMenuButton*>(o)))
+ bt->move(QPoint(bt->x()-dst, bt->y()));
+ }
+ else
+ {
+ resize(width(), height()-dst);
+ for ( o = kids->first(); o; o = kids->next() )
+ if (bt = (dynamic_cast<StartMenuButton*>(o)))
+ bt->move(QPoint(bt->x(), bt->y()-dst));
+ }
+ }
+ }
+}
+
+void Panel::wheelEvent ( QWheelEvent * we )
+{
+ if (_orientation == Qt::Vertical)
+ {
+ if (we->delta() > 0)
+ {
+ if (childrenRect().y() < clipRegion().boundingRect().y())
+ {
+ if (childrenRect().y() + we->delta() < clipRegion().boundingRect().y())
+ scroll ( 0, we->delta() );
+ else
+ scroll ( 0, clipRegion().boundingRect().y() - childrenRect().y() );
+ }
+ }
+ else
+ {
+ if (childrenRect().bottom() > clipRegion().boundingRect().bottom())
+ {
+ if (childrenRect().bottom() + we->delta() > clipRegion().boundingRect().bottom())
+ scroll ( 0, we->delta() );
+ else
+ scroll ( 0, clipRegion().boundingRect().bottom() - childrenRect().bottom() );
+ }
+ }
+ }
+ else
+ {
+ if (we->delta() > 0)
+ {
+ if (childrenRect().x() < clipRegion().boundingRect().x())
+ {
+ if (childrenRect().x() + we->delta() < clipRegion().boundingRect().x())
+ scroll ( we->delta(), 0 );
+ else
+ scroll ( clipRegion().boundingRect().x() - childrenRect().x(), 0 );
+ }
+ }
+ else
+ {
+ if (childrenRect().right() > clipRegion().boundingRect().right())
+ {
+ if (childrenRect().right() + we->delta() > clipRegion().boundingRect().right())
+ scroll ( we->delta(), 0 );
+ else
+ scroll ( clipRegion().boundingRect().right() - childrenRect().right(), 0 );
+ }
+ }
+ }
+}
+
+void Panel::resizeEvent ( QResizeEvent * e)
+{
+ if (_orientation == Qt::Horizontal)
+ {
+ if (e->size().height() != e->oldSize().height())
+ {
+ int h = e->size().height();
+ KPixmap bgPix = QPixmap(32, h);
+ KPixmap bgPix1 = QPixmap(32, h/2);
+ KPixmap bgPix2 = QPixmap(32, h - bgPix1.height());
+ QColor color = palette().color(QPalette::Active, QColorGroup::Background);
+ KPixmapEffect::gradient( bgPix1, color.light(130), color.dark(105), KPixmapEffect::VerticalGradient, 0);
+ KPixmapEffect::gradient( bgPix2, color.dark(120), color.light(110), KPixmapEffect::VerticalGradient, 0);
+ QPainter p(&bgPix);
+ p.drawPixmap(0,0,bgPix1);
+ p.drawPixmap(0,bgPix1.height(),bgPix2);
+ p.end();
+ setPaletteBackgroundPixmap( bgPix );
+ }
+ }
+ else if (_orientation == Qt::Vertical)
+ {
+ if (e->size().width() != e->oldSize().width())
+ {
+ int w = e->size().width();
+ KPixmap bgPix = QPixmap(w, 32);
+ KPixmap bgPix1 = QPixmap(w/2, 32);
+ KPixmap bgPix2 = QPixmap(w - bgPix1.width(), 32);
+ QColor color = palette().color(QPalette::Active, QColorGroup::Background);
+ KPixmapEffect::gradient( bgPix1, color.light(110), color.dark(120), KPixmapEffect::HorizontalGradient, 0);
+ KPixmapEffect::gradient( bgPix2, color.dark(105), color.light(130), KPixmapEffect::HorizontalGradient, 0);
+ QPainter p(&bgPix);
+ p.drawPixmap(0,0,bgPix1);
+ p.drawPixmap(bgPix1.width(),0,bgPix2);
+ p.end();
+ setPaletteBackgroundPixmap( bgPix );
+ }
+ }
+ QWidget::resizeEvent( e );
+}
+
+void Panel::poof()
+{
+ /*if (_draggedMe)
+ {
+ _draggedMe = false;
+ return;
+ }*/
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ if (kids && !kids->isEmpty())
+ {
+ QObject *o;
+ StartMenuButton *bt = 0L;
+ for ( o = kids->first(); o; o = kids->next() )
+ {
+ bt = 0L;
+ if ((bt = (dynamic_cast<StartMenuButton*>(o))) && bt->isMoving())
+ {
+ bt->hide(); bt->deleteLater(); bt = 0L;
+ --_count;
+ }
+ }
+ _poofIndex = 0;
+ _poofPix = new QPixmap(locateLocal("data", "baghira/poof.png"), "png");
+ _poofAnimPix = new QPixmap(_poofPix->width(), _poofPix->width());
+ if (!_poof)
+ _poof = new QWidget(0,0, Qt::WType_TopLevel | Qt::WStyle_NoBorder | Qt::WStyle_StaysOnTop | Qt::WX11BypassWM);
+#if KDE_IS_VERSION(3,3,91) //3.4 beta
+ KWin::setShadowSize(_poof->winId(), 0);
+#endif
+ _poof->setFixedSize(_poofPix->width(), _poofPix->width());
+ int x = QCursor::pos().x() - _poof->width()/2;
+ int y = QCursor::pos().y() - _poof->height()/2;
+ QPixmap bgPix = QPixmap::grabWindow( qt_xrootwin(), x, y, _poofPix->width(), _poofPix->width());
+ _poof->move(x,y);
+ _poof->show();
+ _poof->setBackgroundOrigin(QWidget::WidgetOrigin);
+ _poof->setPaletteBackgroundPixmap( bgPix );
+ runPoof();
+ }
+}
+
+void Panel::runPoof()
+{
+ if (_poofIndex > 4)
+ {
+ _poof->hide();
+ delete _poofPix;
+ _poofPix = 0L;
+// delete _poof;
+// _poof = 0L;
+ delete _poofAnimPix;
+ _poofAnimPix = 0L;
+ _poofIndex = 0;
+ return;
+ }
+ _poof->erase();
+ bitBlt(_poof, 0 ,0, _poofPix, 0, _poofIndex * _poofPix->width(), _poofPix->width(), _poofPix->width(), Qt::AndROP);
+ ++_poofIndex;
+ QTimer::singleShot ( 70, this, SLOT(runPoof()) ); // around 15 fps
+}
+
+void Panel::mouseReleaseEvent ( QMouseEvent * mre )
+{
+ if (mre->state() & Qt::RightButton)
+ {
+ iconAddPosition = mre->pos();
+ linkConfigDialog->setCaption ( i18n("New Link") );
+ linkConfigDialog->title->clear();
+ linkConfigDialog->command->clear();
+ linkConfigDialog->icon->resetIcon();
+ disconnect(linkConfigDialog->buttonOk, SIGNAL(clicked()), 0, 0);
+ connect(linkConfigDialog->buttonOk, SIGNAL(clicked()), linkConfigDialog, SLOT(accept()));
+ connect(linkConfigDialog->buttonOk, SIGNAL(clicked()), this, SLOT(addIcon()));
+ linkConfigDialog->exec();
+ }
+}
+
+void Panel::dragEnterEvent ( QDragEnterEvent *dee )
+{
+ if (BaghiraLinkDrag::canDecode(dee))
+ {
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ if (kids && !kids->isEmpty())
+ {
+ QObject *o;
+ StartMenuButton *bt = 0L;
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((bt = (dynamic_cast<StartMenuButton*>(o))) && bt->isMoving())
+ // this is just some icon the user drags around ad that accidently left the panel
+ {
+ BaghiraLinkDrag::setAccepted();
+ // as we cannot access Qts dragmanager and qdragobject doesn't provide a function to cancel the drag, we just emit a virtual escape key...
+ _draggedMe = true; // ensure to please not poof ;P
+ XTestFakeKeyEvent(qt_xdisplay(),XKeysymToKeycode(qt_xdisplay(), XK_Escape), true, 0);
+ XTestFakeKeyEvent(qt_xdisplay(),XKeysymToKeycode(qt_xdisplay(), XK_Escape), false, 0);
+ XFlush(qt_xdisplay());
+ repositionIcon(bt, mapFromGlobal(dee->pos()));
+ return;
+ }
+ }
+ dee->accept(TRUE);
+ }
+ else if (QUriDrag::canDecode(dee) || QTextDrag::canDecode(dee))
+ dee->accept(TRUE);
+}
+
+void Panel::dropEvent ( QDropEvent *de )
+{
+ QStrList list;
+ QString title;
+ QString command;
+ QString icon;
+ int index;
+ if ( BaghiraLinkDrag::decode(de, &title, &command, &icon, &index) )
+ {
+ addIcon ( icon, title, command, QPoint(de->pos().x() - (_BIGSIZE_(_size)/2), de->pos().y() - (_BIGSIZE_(_size)/2)));
+ BaghiraLinkDrag::setAccepted();
+ }
+ else if ( QUriDrag::decode(de, list) )
+ {
+ char *uri;
+ KURL url;
+ for ( uri = list.first(); uri; uri = list.next() )
+ {
+ url = KURL(uri);
+ if (url.protocol() == "http")
+ addIcon ( "html", url.host()+(url.path()=="/"?QString(""):url.path()), uri, de->pos() );
+ else
+ {
+ KFileItem item = KFileItem(KFileItem::Unknown, KFileItem::Unknown, url, true);
+ addIcon ( item.iconName(), url.fileName().isEmpty()?url.prettyURL():url.fileName(), uri, de->pos() );
+ }
+ }
+ }
+ else if (QTextDrag::decode(de, command))
+ {
+ KURL url(command);
+ if (url.isValid())
+ {
+ if (url.protocol() == "http")
+ addIcon ( "html", url.host()+(url.path()=="/"?QString(""):url.path()), command, de->pos() );
+ else
+ {
+ KFileItem item = KFileItem(KFileItem::Unknown, KFileItem::Unknown, url, true);
+ addIcon ( item.iconName(), url.fileName().isEmpty()?url.prettyURL():url.fileName(), command, de->pos() );
+ }
+ }
+ else if (command.contains('@'))
+ {
+ command.replace(" ","");
+ addIcon ( "kmail", command, "mailto:"+command, de->pos() );
+ }
+ else if (command.contains("'at'")) //last chance for anti-spam addy
+ {
+ command.replace(" ","");
+ command.replace("'at'","@");
+ addIcon ( "kmail", command, "mailto:"+command, de->pos() );
+ }
+ else // ok, just take this as siple unknown command and hope the user knows, what she's ;) doing...
+ {
+ StartMenuButton *bt = addIcon ( command, command, command, de->pos() );
+ }
+ }
+}
+
+void Panel::repositionIcon(StartMenuButton *button, QPoint pt)
+{
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ if (!kids || kids->isEmpty()) // the easy one ;)
+ return;
+ if (kids->count() == 1) // button's for certain the only child ;)
+ {
+ if (_orientation == Qt::Horizontal)
+ button->move(pt.x(),0);
+ else
+ button->move(0,pt.y());
+ return;
+ }
+ QObject *o;
+ StartMenuButton *bt = 0L;
+ int xy = 0;
+ if (_orientation == Qt::Horizontal)
+ {
+ if (pt.x() < 0) // append horizontally
+ {
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && bt != button && bt->x() + bt->width() > xy )
+ xy = bt->x() + bt->width();
+ button->move(xy,0);
+ }
+ else // inject horizontally
+ {
+ // first find possible icon under the position
+ for ( o = kids->first(); o; o = kids->next() )
+ {
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && QRect(bt->pos(), bt->size()).contains(pt))
+ break;
+ else
+ bt = 0l;
+ }
+ if (bt) // found? - decide whether to insert left or right
+ {
+ if (bt->x() + bt->width()/2 > pt.x()) // move to old icon place
+ {
+ button->move(bt->x(), 0);
+ }
+ else // move to right
+ {
+ button->move(bt->x() + bt->width(), 0);
+ }
+ // adjust right icons
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && bt->x() >= button->x() && bt != button )
+ {
+ bt->move(bt->x() + button->width(), 0);
+ }
+ }
+ else // no collision, just move there
+ button->move(pt.x(), 0);
+ }
+ }
+ else
+ {
+ if (pt.y() < 0) // append vertically
+ {
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && bt != button && bt->y() + bt->height() > xy )
+ xy = bt->y() + bt->height();
+ button->move(0, xy);
+ }
+ else // inject vertically
+ {
+ // first find possible icon under the position
+ for ( o = kids->first(); o; o = kids->next() )
+ {
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && QRect(bt->pos(), bt->size()).contains(pt))
+ break;
+ else
+ bt = 0l;
+ }
+ if (bt) // found? - decide whether to insert up or down
+ {
+ if (bt->y() + bt->height()/2 > pt.y()) // move to old icon place
+ button->move(0, bt->y());
+ else // move to right
+ button->move(0, bt->y() + bt->height());
+ // adjust lower icons
+ for ( o = kids->first(); o; o = kids->next() )
+ if ((bt = dynamic_cast<StartMenuButton*>(o)) && bt->y() >= button->y() && bt != button )
+ bt->move(0, bt->y() + button->height());
+ }
+ else // no collision, just move there
+ button->move(0, pt.y());
+ }
+ }
+}
+
+StartMenuButton* Panel::addIcon ( QString icon, QString title, QString command, QPoint pt )
+{
+ StartMenuButton *tmpButton = new StartMenuButton(_size, icon, title, command, StartMenuButton::Status, this);
+ // reposition icon
+ repositionIcon(tmpButton, pt);
+ // connections
+ connect (tmpButton, SIGNAL(hovered(const QString &)), this, SIGNAL(message(const QString &)));
+ connect (tmpButton, SIGNAL(unhovered()), this, SIGNAL(clearStatus()));
+ connect (tmpButton, SIGNAL(updateSize(int)), this, SLOT(updateSize(int)));
+ connect (tmpButton, SIGNAL(pressed(const QString &)), parent(), SLOT(execute(const QString &)));
+ connect (tmpButton, SIGNAL(pressed(const QString &)), parent(), SLOT(close()));
+ // done
+ // inc counter
+ _count++;
+ tmpButton->show();
+ return tmpButton;
+}
+
+void Panel::setOrientation ( Orientation ori )
+{
+ if (_orientation == ori)
+ return;
+ _orientation = ori;
+ QObjectList *kids = const_cast<QObjectList*>(children());
+ if (!kids || kids->isEmpty())
+ return;
+ QObject *o;
+ StartMenuButton *bt = 0L;
+ for ( o = kids->first(); o; o = kids->next() )
+ if (bt = (dynamic_cast<StartMenuButton*>(o)))
+ bt->move(QPoint(bt->pos().y(), bt->pos().x()));
+}
+
+AppList::AppList(int size, QWidget * parent) : QScrollView(parent), _size(size)
+{
+ popupBlocked_ = false;
+ enableClipper( true );
+ setFrameStyle(QFrame::LineEditPanel | QFrame::Sunken );
+ configDialog_ = new ConfigDialog;
+ helpDialog_ = new HelpDialog;
+ connect (((QObject*)configDialog_->buttonHelp), SIGNAL(clicked()), ((QObject*)helpDialog_), SLOT(exec()));
+ connect (((QObject*)configDialog_->buttonCancel), SIGNAL(clicked()), this, SLOT(unblockPopup()));
+ m_widget = new QFrame(viewport());
+ m_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_widget->setPaletteBackgroundColor(KGlobalSettings::baseColor());
+ addChild(m_widget,0,0);
+ setResizePolicy(QScrollView::AutoOneFit);
+ m_widget->show();
+ infoLayout = new QVBoxLayout(m_widget);
+ infoLabel = new QLabel(m_widget);
+ infoLabel->setPaletteBackgroundColor(infoColor);
+ infoLabel->setTextFormat( Qt::RichText );
+ infoLayout->addWidget(infoLabel);
+ m_VLayout = new QVBoxLayout(infoLayout);
+ m_iconLoader = KGlobal::iconLoader();
+ m_popup = new KPopupMenu(this);
+ m_popup->insertItem(i18n("Edit Entry"), this, SLOT(editDialog()));
+ m_popup->insertItem(i18n("Remove Entry"), this, SLOT(removeEntry()));
+ m_popup->insertSeparator();
+ m_popup->insertItem(i18n("Add Entry"), this, SLOT(addDialog()));
+ init();
+}
+
+void AppList::mouseReleaseEvent ( QMouseEvent * e )
+{
+ if (e->button() == Qt::RightButton)
+ addDialog();
+}
+
+void AppList::windowActivationChange ( bool oldActive )
+{
+ if (isActiveWindow() && entryList.current())
+ entryList.current()->setFocus();
+ QScrollView::windowActivationChange ( oldActive );
+}
+
+void AppList::reloadIcons( int size)
+{
+ _size = size;
+ QPtrListIterator<StartMenuEntry> it(entryList);
+ StartMenuEntry *runner;
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ runner->reloadIcon(size);
+ }
+}
+
+void AppList::addDialog()
+{
+ disconnect (((QObject*)configDialog_->buttonOk), SIGNAL(clicked()), this, 0);
+ connect (((QObject*)configDialog_->buttonOk), SIGNAL(clicked()), this, SLOT(addEntry()));
+ configDialog_->appName->clear();
+ configDialog_->category->clearEdit();
+ configDialog_->command->clear();
+ configDialog_->genericName->clear();
+ configDialog_->iconButton->resetIcon();
+ configDialog_->keywords->clear();
+ configDialog_->startupFeedback->setChecked( true );
+ configDialog_->showInSystray->setChecked( false );
+ configDialog_->description->clear();
+ configDialog_->startInTerminal->setChecked( false );
+ configDialog_->terminalSettings->clear();
+ configDialog_->startAsUser->setChecked( false );
+ configDialog_->username->clear();
+ configDialog_->workingDir->clear();
+ configDialog_->shortcut->setShortcut(KShortcut::null(), false);
+
+ configDialog_->setCaption ( i18n("New Entry") );
+ ((QWidget*)(configDialog_->extendedGroup))->hide();
+ configDialog_->buttonDetail->setDown ( false );
+ configDialog_->adjustSize();
+ configDialog_->show();
+}
+
+void AppList::addEntry()
+{
+ QString fullpath = configDialog_->category->currentText();
+ while (fullpath[0] == '/') // remove leading "/"'s
+ {
+ fullpath.remove(0,1);
+ }
+ fullpath = KService::newServicePath(true, fullpath + configDialog_->appName->text());
+//qWarning("%s",fullpath.ascii());
+ writeEntry(fullpath);
+ KService *s = new KService(fullpath);
+ QStringList list(KServiceGroup::group(configDialog_->category->currentText())->caption());
+ StartMenuEntry *sme = addApp(s, list, configDialog_->category->currentText());
+ sme->rank = 0xFFFFFF; // hype rank to max, i.e. keep this entry on top of everything - for this session or until first use
+ sme->show();
+ sort();
+}
+
+void AppList::removeEntry()
+{
+ popupBlocked_ = true;
+ if (KMessageBox::questionYesNo (this, i18n("<qt>Are you sure you want to remove<br> %1</qt>").arg(handledEntry->title()), i18n("Remove ALI entry")) == KMessageBox::Yes)
+ {
+ qWarning("gonna delete!");
+ writeEntry(handledEntry->m_service->locateLocal(), true);
+ handledEntry->hide();
+ entryList.removeRef(handledEntry);
+ delete handledEntry;
+ handledEntry = 0L;
+ }
+ popupBlocked_ = false;
+}
+
+void AppList::editDialog()
+{
+ if (!handledEntry)
+ return;
+ popupBlocked_ = true;
+ disconnect (((QObject*)configDialog_->buttonOk), SIGNAL(clicked()), this, 0);
+ connect (((QObject*)configDialog_->buttonOk), SIGNAL(clicked()), this, SLOT(editEntry()));
+ configDialog_->appName->setText(handledEntry->m_service->name());
+ configDialog_->category->setCurrentItem (handledEntry->groupPath, false);
+ configDialog_->showInSystray->setChecked( handledEntry->m_service->exec().contains("ksystraycmd ") );
+ if (!configDialog_->showInSystray->isChecked())
+ configDialog_->command->setURL(handledEntry->m_service->exec());
+ else
+ configDialog_->command->setURL(handledEntry->m_service->exec().right(handledEntry->m_service->exec().length() - (handledEntry->m_service->exec().findRev("ksystraycmd ") + 12)));
+ configDialog_->genericName->setText(handledEntry->m_service->genericName());
+ configDialog_->iconButton->setIcon(handledEntry->m_service->icon ());
+ configDialog_->keywords->setText(handledEntry->m_service->keywords().join(","));
+ configDialog_->startupFeedback->setChecked( handledEntry->m_service->property ( "StartupNotify" ).toBool());
+ configDialog_->description->setText(handledEntry->m_service->comment());
+ configDialog_->startInTerminal->setChecked( handledEntry->m_service->terminal() );
+ configDialog_->terminalSettings->setText(handledEntry->m_service->terminalOptions());
+ configDialog_->startAsUser->setChecked( handledEntry->m_service->substituteUid() );
+ configDialog_->username->setText(handledEntry->m_service->username());
+ configDialog_->workingDir->setURL(handledEntry->m_service->path());
+// KKeyButton* shortcut;
+
+ configDialog_->setCaption ( i18n("Edit Entry") );
+ ((QWidget*)(configDialog_->extendedGroup))->hide();
+ configDialog_->buttonDetail->setDown ( false );
+ configDialog_->adjustSize();
+ configDialog_->show();
+}
+
+void AppList::editEntry()
+{
+ QString fullpath;
+ if (handledEntry->groupPath == configDialog_->category->currentText()) // group not changed
+ fullpath = handledEntry->m_service->locateLocal(); // find a local replacement path
+ else // more complex: remove (del/shadow) entry from old group and create one in the new group
+ {
+ writeEntry(handledEntry->m_service->locateLocal(), true); //hide from old group
+ fullpath = configDialog_->category->currentText();
+ while (fullpath[0] == '/') // remove leading "/"'s
+ fullpath.remove(0,1);
+ fullpath = KService::newServicePath(true, fullpath + configDialog_->appName->text()); // find new path
+ }
+ writeEntry(fullpath);
+ handledEntry->hide();
+ QDate lu = handledEntry->lastUse;
+ uint u = handledEntry->usage;
+ entryList.removeRef(handledEntry);
+ delete handledEntry;
+ handledEntry = 0L;
+ KService *s = new KService(fullpath);
+ QStringList list(KServiceGroup::group(configDialog_->category->currentText())->caption());
+ StartMenuEntry *sme = addApp(s, list, configDialog_->category->currentText());
+ sme->lastUse = lu;
+ sme->usage = u;
+ sme->rank = 8 + u - lu.daysTo(QDate::currentDate());
+ if (!config) config = new KConfig("bStarter", false, false);
+ config->setGroup("Statistics");
+ sme->saveStats();
+ delete config;
+ config = 0L;
+ sme->show();
+ sort();
+ popupBlocked_ = false;
+}
+
+void AppList::writeEntry(QString path, bool hidden )
+{
+ KConfig *config = new KConfig(path);
+ config->setDesktopGroup();
+
+ if (!configDialog_->description->text().isEmpty())
+ config->writeEntry("Comment", configDialog_->description->text());
+ if (!configDialog_->command->url().isEmpty())
+ if (configDialog_->showInSystray->isChecked())
+ config->writeEntry("Exec", "ksystraycmd " + configDialog_->command->url());
+ else
+ config->writeEntry("Exec", configDialog_->command->url());
+ if (!configDialog_->genericName->text().isEmpty())
+ config->writeEntry("GenericName", configDialog_->genericName->text());
+ if (hidden)
+ config->writeEntry("Hidden", true);
+ else if (config->readBoolEntry("Hidden", false))
+ config->writeEntry("Hidden", false);
+ if (!configDialog_->iconButton->icon().isNull())
+ config->writeEntry("Icon", configDialog_->iconButton->icon());
+ if (!configDialog_->keywords->text().isEmpty())
+ config->writeEntry("Keywords", QStringList::split(',', configDialog_->keywords->text()));
+ if (!configDialog_->appName->text().isEmpty())
+ config->writeEntry("Name", configDialog_->appName->text());
+ if (!configDialog_->workingDir->url().isEmpty())
+ config->writeEntry("Path", configDialog_->workingDir->url());
+ if (configDialog_->startupFeedback->isChecked())
+ config->writeEntry("StartupNotify", true);
+ if (configDialog_->startInTerminal->isChecked())
+ {
+ config->writeEntry("Terminal", 1);
+ if (!configDialog_->terminalSettings->text().isEmpty())
+ config->writeEntry("TerminalOptions", configDialog_->terminalSettings->text());
+ }
+ config->writeEntry("Type", "Application");
+ if (configDialog_->startAsUser->isChecked())
+ {
+ config->writeEntry("X-KDE-SubstituteUID", true);
+ if (!configDialog_->username->text().isEmpty())
+ config->writeEntry("X-KDE-Username", configDialog_->username->text());
+ }
+
+ delete config;
+
+// configDialog_->category->setCurrentItem (handledEntry->m_service->categories().join("/"), true);
+}
+
+void AppList::popup(StartMenuEntry* entry)
+{
+ if (popupBlocked_ && configDialog_->isShown())
+ return;
+ handledEntry = entry;
+ m_popup->popup(QCursor::pos());
+}
+
+void AppList::sort()
+{
+ // first clean the layout (i assume that QLayout::remove() will search from beginning so removing over the current order will be quite fast)
+ QPtrListIterator<StartMenuEntry> it(entryList);
+ StartMenuEntry *runner;
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ m_VLayout->remove ( runner );
+ }
+ ((MyVBoxLayout*)m_VLayout)->deleteAllItems(); // get rid of the stretch
+ // then sort the list
+ entryList.sort();
+ it.toFirst();
+ // now rebuild the layout from new list
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ m_VLayout->addWidget ( runner );
+ }
+ m_VLayout->addStretch(1); // add final stretch
+}
+
+void AppList::init()
+{
+ m_root = KServiceGroup::group(QString::null);
+
+ if (!m_root || !m_root->isValid())
+ {
+ qWarning("ROOT NOT FOUND");
+ return;
+ }
+ favItemAmount = config->readNumEntry("FavItemAmount", 10);
+ neewbieApps << "konqueror" << "kmail" << "kppp";
+ if (newbie = config->readBoolEntry("firstUse", true)) // '/' is certainly not unescaped part of a filename ;)
+ {
+ infoLabel->setText ( i18n("<qt><b>First Session Applications</b></qt>") );
+// delete config;
+// config = 0L;
+ }
+ else
+ {
+ infoLabel->setText ( i18n("<qt><b>Favorite Applications</b><br></qt>") );
+ }
+ config->setGroup("Statistics");
+ QStringList captions, paths;
+ insertGroup(m_root, captions, paths);
+ paths.sort();
+ configDialog_->category->insertStringList(paths);
+ configDialog_->category->completionObject()->setCompletionMode( KGlobalSettings::CompletionPopupAuto );
+ configDialog_->category->completionObject()->insertItems(paths);
+// if (config) { delete config; config = 0L; }
+ sort();
+ reset();
+}
+
+void AppList::save(KConfig *config)
+{
+ config->setGroup("Statistics");
+ QPtrListIterator<StartMenuEntry> it(entryList);
+ StartMenuEntry *runner;
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ runner->saveStats();
+ }
+}
+
+void AppList::insertGroup(KServiceGroup *g, QStringList & captions, QStringList & paths)
+{
+ KServiceGroup::List list = g->entries(true, true, false, false);
+
+ if (list.isEmpty())
+ {
+ return;
+ }
+ else
+ {
+ captions.append(g->caption());
+ if (!categories.contains(g->caption()))
+ categories.append(g->caption());
+ if (!paths.contains(g->relPath()))
+ paths.append(g->relPath());
+ for( KServiceGroup::List::ConstIterator it = list.begin(); it != list.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *s = static_cast<KService *>(p);
+ if ((s->name().at(0) == '.'))
+ continue;
+ if (s->type() == "Application")
+ {
+ addApp(s, captions, g->relPath());
+ }
+ }
+ else if (p->isType(KST_KServiceGroup))
+ {
+ KServiceGroup *g2 = static_cast<KServiceGroup *>(p);
+ if ((g2->name().at(0) == '.'))
+ continue;
+ insertGroup(g2,captions, paths);
+ }
+ }
+ captions.remove(g->caption());
+ }
+}
+
+StartMenuEntry* AppList::addApp(KService * s, QStringList & captions, QString relPath)
+{
+ StartMenuEntry * tmp = new StartMenuEntry(s, relPath, _size, neewbieApps.find(s->desktopEntryName()) != neewbieApps.end(), m_widget);
+ connect (tmp, SIGNAL(appUp()), this, SLOT(appUp()));
+ connect (tmp, SIGNAL(appDown()), this, SLOT(appDown()));
+ connect (tmp, SIGNAL(appLeft()), this, SLOT(appLeft()));
+ connect (tmp, SIGNAL(hovered(const QString&)), this, SIGNAL(message(const QString&)));
+ if (useKTTS) connect (tmp, SIGNAL(sayText(const QString&)), this, SIGNAL(sayText(const QString&)));
+ connect (tmp, SIGNAL(unhovered()), this, SIGNAL(clearStatus()));
+ connect (tmp, SIGNAL(pressed()), parent(), SLOT(close()));
+ connect (tmp, SIGNAL(popup(StartMenuEntry*)), this, SLOT(popup(StartMenuEntry*)));
+ connect (tmp, SIGNAL(closeMenu()), parent(), SLOT(close()));
+ connect (tmp, SIGNAL(executed()), this, SLOT(sort()));
+ m_VLayout->addWidget(tmp);
+ tmp->hide();
+ entryList.append(tmp);
+ KeyWordList::Iterator it;
+ if (!(s->name().isNull() || s->name().isEmpty()))
+ {
+ it = m_keywordList.insert(s->name(), StartMenuEntryList(), false);
+ it.data().append( tmp );
+ }
+ QStringList kw;
+#if 0
+ kw = s->categories(); // THIS IS ****IMPORTANT***** kicker will crash on init if you try to grep through the pointers!
+ if (!kw.isEmpty())
+ {
+ QStringList::Iterator key;
+ for ( key = kw.begin(); key != kw.end(); ++key )
+ {
+ if (!((*key).isNull() || (*key).isEmpty()))
+ {
+ it = m_keywordList.insJediKnightert(*key, StartMenuEntryList(), false);
+ it.data().append( tmp );
+ }
+ }
+ }
+#endif
+ kw = s->keywords(); // THIS IS ****IMPORTANT***** kicker will crash on init if you try to grep through the pointers!
+ if (!kw.isEmpty())
+ {
+ for ( QStringList::Iterator key = kw.begin(); key != kw.end(); ++key )
+ {
+ if (!((*key).isNull() || (*key).isEmpty()))
+ {
+ it = m_keywordList.insert(*key, StartMenuEntryList(), false);
+ it.data().append( tmp );
+ }
+ }
+ }
+ // group captions (so Games/IDSoftware/Quake3 will appear in Games and IDSoftware)
+ if (!captions.isEmpty())
+ {
+ for ( QStringList::Iterator key = captions.begin(); key != captions.end(); ++key )
+ {
+ if (!((*key).isNull() || (*key).isEmpty()))
+ {
+ it = m_groupList.insert(*key, StartMenuEntryList(), false);
+ it.data().append( tmp );
+ }
+ }
+ }
+ return tmp;
+}
+
+void AppList::finish()
+{
+ entryList.last(); entryList.next();
+ m_VLayout->addStretch(1);
+ categories.sort();
+}
+
+void AppList::appDown()
+{
+ StartMenuEntry *save;
+ if (entryList.current() == 0L/*entryList.getLast()*/)
+ {
+ entryList.first();
+ save = 0L;
+ }
+ else
+ {
+ save = entryList.current();
+ entryList.next();
+ }
+ for ( StartMenuEntry *runner = entryList.current(); runner; runner = entryList.next() )
+ if (runner->isShown())
+ {
+ if (save) save->clearFocus();
+ runner->setFocus();
+ QPoint pt(0,runner->height());
+ pt = runner->mapToParent(pt);
+ ensureVisible ( pt.x(), pt.y());
+ return;
+ }
+// if (currentEntry == entryList.end())
+// currentEntry = entryList.begin(); // keep this somewhere valid
+}
+
+void AppList::appUp()
+{
+ if (entryList.current() == entryList.getFirst())
+ {
+ entryList.current()->clearFocus();
+ entryList.last(); entryList.next(); // we jump out
+ emit looseKey();
+ return;
+ }
+ StartMenuEntry *save = entryList.current();
+ StartMenuEntry *runner;
+ if (entryList.current())
+ runner = entryList.prev();
+ else
+ runner = entryList.last();
+ for ( ; runner != entryList.getFirst(); runner = entryList.prev())
+ if (runner->isShown())
+ {
+ if (save) save->clearFocus();
+ runner->setFocus();
+ QPoint pt(0,0);
+ pt = runner->mapToParent(pt);
+ ensureVisible ( pt.x(), pt.y());
+ return;
+ }
+ if (runner == entryList.getFirst())
+ {
+ if (save) save->clearFocus();
+ if (runner->isShown())
+ {
+ runner->setFocus();
+ QPoint pt(0,0);
+ pt = runner->mapToParent(pt);
+ ensureVisible ( pt.x(), pt.y());
+ }
+ else
+ {
+ entryList.last(); entryList.next();// we jump out
+ emit looseKey();
+ }
+ }
+}
+void AppList::appLeft()
+{
+ if (entryList.current())
+ {
+ entryList.current()->clearFocus();
+ entryList.last(); entryList.next(); // we jump out
+ }
+ emit looseKey();
+}
+
+void AppList::showCategory(const QString & string)
+{
+ infoLabel->setText(string);
+ infoLabel->show();
+ StartMenuEntry *it2;
+ KeyWordList::Iterator it;
+ for ( it = m_groupList.begin(); it != m_groupList.end(); ++it )
+ {
+ if (it.key() == string)
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = true;
+ }
+ else
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = it2->display || false;
+ }
+ }
+ uint visibleItems = 0;
+ for ( it2 = entryList.first(); it2; it2 = entryList.next())
+ {
+ if (it2->display)
+ {
+ visibleItems++;
+ it2->show();
+ }
+ else
+ it2->hide();
+ it2->display = false;
+ }
+ if (useKTTS && visibleItems == 0)
+ {
+ QString text = i18n("for TTS output, informs the user that no entries are in the currently selected group", "Warning! No Applications in group %1").arg(string);
+ emit sayText(text);
+ }
+}
+
+void AppList::search(const QString & string)
+{
+ StartMenuEntry *it2;
+ if (string == QString::null || string == "") // empty line - remove all and exit
+ {
+ infoLabel->setText ( i18n("<qt><b>Favorite Applications</b><br></qt>") );
+ infoLabel->show();
+ int i = 0;
+ for ( it2 = entryList.first(); it2; it2 = entryList.next() )
+ {
+ i < favItemAmount ? it2->show() : it2->hide();
+ i++;
+ }
+ return;
+ }
+ infoLabel->hide();
+ // ok, we need a 2pass search: 1st to figure out which to show, 2nd to show or hide things
+ // the implementation also prevents us from spending time on showing/hiding things and some onscreen flicker, O(k*n(k)*n)
+ KeyWordList::Iterator it;
+ //keywords
+ for ( it = m_keywordList.begin(); it != m_keywordList.end(); ++it )
+ {
+ if (it.key().contains(string, false) > 0)
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = true;
+ }
+ else
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = it2->display || false;
+ }
+ }
+ //groups
+ for ( it = m_groupList.begin(); it != m_groupList.end(); ++it )
+ {
+ if (it.key().contains(string, false) > 0)
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = true;
+ }
+ else
+ {
+ for ( it2 = it.data().first(); it2; it2 = it.data().next())
+ it2->display = it2->display || false;
+ }
+ }
+ //items
+ uint visibleItems = 0;
+ for ( it2 = entryList.first(); it2; it2 = entryList.next())
+ {
+ if (it2->display && visibleItems < 50) //limit this to a healthy size
+ {
+ visibleItems++;
+ it2->show();
+ }
+ else
+ it2->hide();
+ it2->display = false;
+ }
+ if (useKTTS && visibleItems == 0)
+ {
+ QString text = i18n("for TTS output, no entries match the current search text", "Warning! No more Applications left. The entered Text is %1").arg(spell(string));
+ emit sayText(text);
+ }
+}
+
+void AppList::clear()
+{
+ for ( StartMenuEntry *it = entryList.first(); it; it = entryList.next())
+ it->hide();
+}
+
+void AppList::reset()
+{
+ newbie ?
+ infoLabel->setText ( i18n("<qt><b>First Session Applications</b></qt>") ) :
+ infoLabel->setText ( i18n("<qt><b>Favorite Applications</b><br></qt>") );
+ infoLabel->show();
+ if (newbie)
+ {
+ for ( StartMenuEntry *it = entryList.first(); it; it = entryList.next())
+ {
+ it->forNewbie ? it->show() : it->hide();
+ }
+ }
+ else
+ {
+ uint i = 0;
+ for ( StartMenuEntry *it = entryList.first(); it; it = entryList.next())
+ {
+ i < favItemAmount ? it->show() : it->hide();
+ i++;
+ }
+ }
+ setContentsPos(0, 0);
+}
+
+StartMenu::StartMenu( int size, QWidget * parent, WFlags f ) : QWidget(parent, "StartMenu", f), _size(size), inMove(false)
+{
+ m_panelPos = StartMenu::Nowhere;
+ panelLayout = new QGridLayout ( this, 3, 3 );
+ config = new KConfig("bStarter", true, false);
+ config->setGroup("Shell");
+ history = config->readListEntry("History");
+ config->setGroup("Settings");
+ if (useKTTS = config->readBoolEntry("useKTTS", false))
+ m_spokenText = 0;
+ _filterData = new KURIFilterData();
+ int r,g,b,r2,g2,b2;
+ KGlobalSettings::baseColor().getRgb(&r,&g,&b);
+ KGlobalSettings::textColor().getRgb(&r2,&g2,&b2);
+ commentColor.setRgb((r+r2)/2,(g+g2)/2,(b+b2)/2);
+ infoColor.setRgb((3*r+r2)/4,(3*g+g2)/4,(3*b+b2)/4);
+ currentHistoryItem = history.end();
+ header = new QWidget(this, "_B_ALI_HEADER");
+ header->installEventFilter(this);
+ QHBoxLayout *headerLayout = new QHBoxLayout(header, 5, 3);
+ userButton = new StartMenuButton(_size, "folder_home", QString(getenv("USER")), "~", StartMenuButton::Status, header, "_B_ALI_HEADER");
+ headerLayout->addWidget(userButton);
+ header->setPaletteBackgroundColor(KGlobalSettings::highlightColor());
+ connect (userButton, SIGNAL(pressed(const QString &)), this, SLOT(execute(const QString &)));
+ connect (userButton, SIGNAL(pressed(const QString &)), this, SLOT(close()));
+ QBoxLayout *mainLayout = new QVBoxLayout();
+ panelLayout->addLayout(mainLayout, 1, 1);
+ mainLayout->addWidget(header);
+ mainLayout->addSpacing ( 3 );
+ QBoxLayout *centerLayout = new QHBoxLayout( mainLayout );
+ centerLayout->addSpacing ( 3 );
+
+ appList = new AppList(_size, this);
+ appList->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+ appList->finish();
+
+ searchLine = new SearchLine(header);
+ categoryCombo = new QComboBox(header, "_B_ALI_HEADER");
+ headerLayout->addWidget(categoryCombo);
+ categoryCombo->setLineEdit ( searchLine );
+ categoryCombo->insertStringList(appList->categories);
+ categoryCombo->setEditable ( true );
+ categoryCombo->setInsertionPolicy(QComboBox::NoInsertion);
+ searchLine->installEventFilter(this);
+ searchLine->setCompletionMode(KGlobalSettings::CompletionAuto);
+ config->setGroup("Shortcuts");
+ // read shortcuts...
+ QStringList cuts = config->readListEntry ("Shortcuts", ',');
+ QStringList cats = config->readListEntry ("Categories", ',');
+ QStringList::Iterator it;
+ QStringList::Iterator it2 = cats.begin();
+ for ( it = cuts.begin(); it != cuts.end(); ++it )
+ {
+ if (it2 == cats.end()) break;
+ shortcutList.insert(MyKey((*it)),(*it2));
+ it2++;
+ }
+ //---
+ QString PATH(getenv("PATH"));
+ int n = PATH.contains(':', false);
+ QStringList list;
+ for (int i = 0; i < n; i++)
+ {
+ QDir execDir(PATH.section(':', i, i));
+ list = execDir.entryList(QDir::Files | QDir::Executable, QDir::Name | QDir::IgnoreCase );
+ searchLine->completionObject()->insertItems(list);
+ }
+
+ connect (categoryCombo, SIGNAL(activated( const QString &)), appList, SLOT(showCategory(const QString &)));
+ connect (searchLine, SIGNAL(typedTextChanged(const QString &)), appList, SLOT(search(const QString &)));
+ connect (searchLine, SIGNAL(textChanged(const QString &)), this, SLOT(endHistory()));
+ connect (appList, SIGNAL(looseKey()), searchLine, SLOT(setFocus()));
+ connect (appList, SIGNAL(looseKey()), searchLine, SLOT(selectAll() ));
+ connect (kapp, SIGNAL(shutDown()), this, SLOT(save() ));
+ if (useKTTS) connect (appList, SIGNAL(sayText(const QString&)), this, SLOT(sayText(const QString&) ));
+
+ centerLayout->addWidget(appList,10);
+ centerLayout->addSpacing ( 3 );
+
+ m_panel = new Panel(_size, this, "_B_ALI_HEADER");
+// m_panel->installEventFilter(this);
+ m_panel->setFixedHeight(_BIGSIZE_(_size)+4);
+
+ statusBar = new KSqueezedTextLabel(this);
+ QFont tmpFnt = statusBar->font();
+ tmpFnt.setBold(true);
+ statusBar->setFont(tmpFnt);
+ connect (appList, SIGNAL(message(const QString&)), this, SLOT(message(const QString&) ));
+ connect (appList, SIGNAL(clearStatus()), this, SLOT(clearStatus() ));
+ connect (m_panel, SIGNAL(message(const QString&)), this, SLOT(centerMessage(const QString&) ));
+ connect (m_panel, SIGNAL(clearStatus()), this, SLOT(clearStatus() ));
+
+ mainLayout->addSpacing ( 3 );
+ mainLayout->addWidget ( statusBar );
+ panelLayout->addWidget ( m_panel, 2, 1 );
+ m_panel->hide();
+
+ if (config) { delete config; config = 0L; }
+// KDrawer *drawer = new KDrawer(this, KDrawer::Bottom);
+}
+
+void StartMenu::save()
+{
+ config = new KConfig("bStarter", false, false);
+ config->setGroup("Shell");
+ QStringList lst;
+ for ( QStringList::Iterator it = history.begin(); it != history.end(); ++it )
+ lst.prepend(*it);
+ config->writeEntry("History", lst);
+ config->setGroup("Settings");
+ config->writeEntry("firstUse", false);
+ appList->save(config);
+ m_panel->save(config);
+ delete config; config = 0L;
+}
+#if 0
+extern int kicker_screen_number;
+
+void StartMenu::slotLock()
+{
+ QCString appname( "kdesktop" );
+// if ( kicker_screen_number )
+// appname.sprintf("kdesktop-screen-%d", kicker_screen_number);
+ kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", "");
+}
+#endif
+
+void StartMenu::reloadIcons( int size)
+{
+ _size = size;
+ m_panel->reloadIcons(size);
+ appList->reloadIcons(size);
+}
+
+void StartMenu::setCategory(const QString & category)
+{
+ categoryCombo->setCurrentItem ( categoryCombo->listBox()->index(categoryCombo->listBox()->findItem(category, Qt::ExactMatch)));
+ //emit categoryCombo->activated ( category ); // dunno if i'll need that once, needs protected access
+ appList->showCategory(category);
+}
+
+void StartMenu::updateShortcuts(ShortcutList & list)
+{
+ shortcutList = list;
+}
+
+void StartMenu::toggleKTTS(bool on)
+{
+ useKTTS = on;
+ if (useKTTS)
+ {
+ m_spokenText = 0;
+ QPtrListIterator<StartMenuEntry> it(appList->entryList);
+ StartMenuEntry *runner;
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ connect (runner, SIGNAL(sayText(const QString&)), this, SIGNAL(sayText(const QString&)));
+ }
+ connect (appList, SIGNAL(sayText(const QString&)), this, SLOT(sayText(const QString&) ));
+ }
+ else
+ {
+ QPtrListIterator<StartMenuEntry> it(appList->entryList);
+ StartMenuEntry *runner;
+ while( (runner = it.current()) != 0 )
+ {
+ ++it;
+ disconnect (runner, SIGNAL(sayText(const QString&)), this, SIGNAL(sayText(const QString&)));
+ }
+ disconnect (appList, SIGNAL(sayText(const QString&)), this, SLOT(sayText(const QString&) ));
+ }
+}
+
+SearchLine::SearchLine( QWidget * parent ) : KLineEdit(parent){blocked = false;};
+
+void SearchLine::makeCompletion (const QString & string)
+{
+ if (blocked) {blocked = false; return;}
+ emit typedTextChanged(string);
+ KLineEdit::makeCompletion (string);
+}
+
+StartMenu::~StartMenu()
+{
+// appList->save();
+}
+
+void StartMenu::sayText(const QString &text)
+{
+ // strip tags
+ QString cleanText;
+ bool copy = true;
+ for (uint i = 0; i < text.length(); i++)
+ {
+ if (!copy && text[i] == '>') // end tag, set copy true and move on
+ {
+ copy = true;
+ continue;
+ }
+ if (copy && text[i] == '<') // tag start, set copy false and move on
+ {
+ copy = false;
+ continue;
+ }
+ if (copy) //copy char ;)
+ cleanText += text[i];
+ }
+ // done
+ QByteArray data1;
+ QDataStream arg1(data1, IO_WriteOnly);
+ arg1 << m_spokenText; // stop what we messaged before (if)
+ if (!kapp->dcopClient()->send("kttsd", "kspeech", "stopText(uint)", data1))
+ qDebug("there was some error using DCOP.");
+
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << cleanText << ""; // ask for the full list
+ if (!kapp->dcopClient()->call("kttsd", "kspeech", "sayText(QString, QString)", data, replyType, replyData))
+ qDebug("there was some error using DCOP.");
+ else
+ {
+ QDataStream reply(replyData, IO_ReadOnly);
+ if (replyType == "uint")
+ reply >> m_spokenText;
+ else
+ qWarning("properties() returned an unexpected type of reply (%s)!",QString(replyType).ascii());
+ }
+}
+
+void StartMenu::show()
+{
+ m_panel->setBackgroundOrigin(QWidget::WidgetOrigin);
+ statusBar->setBackgroundOrigin(QWidget::ParentOrigin);
+ searchLine->setText(i18n("Type to search or enter a command"));
+ searchLine->selectAll();
+ searchLine->setFocus();
+// KWin::setOpacity(winId(), 80);
+ QWidget::show();
+}
+
+void StartMenu::hide()
+{
+ emit aboutToHide();
+ searchLine->clear();
+ appList->reset();
+ QWidget::hide();
+}
+
+void StartMenu::message(const QString &text)
+{
+ statusBar->setAlignment ( Qt::AlignAuto | Qt::AlignVCenter );
+ statusBar->setText(text);
+}
+
+void StartMenu::centerMessage(const QString &text)
+{
+ statusBar->setAlignment ( Qt::AlignCenter );
+ statusBar->setText(text);
+}
+
+void StartMenu::clearStatus()
+{
+ statusBar->clear();
+}
+
+void StartMenu::setPanelPosition(PanelPosition p)
+{
+ if (p == m_panelPos)
+ return;
+ panelLayout->remove(m_panel);
+ switch (p)
+ {
+ case StartMenu::South:
+ m_panel->show();
+ if (m_panelPos == StartMenu::Nowhere || m_panelPos == StartMenu::West || m_panelPos == StartMenu::East )
+ {
+// m_panel->set2SizePolicies(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ m_panel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_panel->setOrientation ( Qt::Horizontal );
+ m_panel->setFixedHeight(_BIGSIZE_(_size)+4);
+ m_panel->setMaximumWidth(32767);
+ }
+ panelLayout->addWidget(m_panel, 2, 1);
+ break;
+ case StartMenu::West:
+ m_panel->show();
+ if (m_panelPos == StartMenu::Nowhere || m_panelPos == StartMenu::South || m_panelPos == StartMenu::North )
+ {
+// m_panel->set2SizePolicies(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
+ m_panel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ m_panel->setOrientation ( Qt::Vertical );
+ m_panel->setFixedWidth(_BIGSIZE_(_size)+4);
+ m_panel->setMaximumHeight(32767);
+ }
+ panelLayout->addWidget(m_panel, 1, 0);
+ break;
+ case StartMenu::East:
+ m_panel->show();
+ if (m_panelPos == StartMenu::Nowhere || m_panelPos == StartMenu::South || m_panelPos == StartMenu::North )
+ {
+// m_panel->set2SizePolicies(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
+ m_panel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ m_panel->setOrientation ( Qt::Vertical );
+ m_panel->setFixedWidth(_BIGSIZE_(_size)+4);
+ m_panel->setMaximumHeight(32767);
+ }
+ panelLayout->addWidget(m_panel, 1, 2);
+ break;
+ case StartMenu::North:
+ m_panel->show();
+ if (m_panelPos == StartMenu::Nowhere || m_panelPos == StartMenu::West || m_panelPos == StartMenu::East )
+ {
+// m_panel->set2SizePolicies(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ m_panel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_panel->setOrientation ( Qt::Horizontal );
+ m_panel->setFixedHeight(_BIGSIZE_(_size)+4);
+ m_panel->setMaximumWidth(32767);
+ }
+ panelLayout->addWidget(m_panel, 0, 1);
+ break;
+ default:
+ m_panel->hide();
+// break;
+ }
+ m_panelPos = p;
+}
+
+void StartMenu::execute(const QString& command)
+// adapted from kicker run applet - far more convenient ;)
+{
+ history.remove(command);
+ history.append(command); // all - the list is not stored and the user may want to easily correct mistypes of LOOOOOOOOOOOOOOOOOOOONG commands with a lot of "\ "... ;P
+ QString exec;
+
+ kapp->propagateSessionManager();
+
+ _filterData->setData( command.stripWhiteSpace() );
+ QStringList filters;
+ filters << "kurisearchfilter" << "kshorturifilter";
+ KURIFilter::self()->filterURI( *(_filterData), filters );
+
+ QString cmd = (_filterData->uri().isLocalFile() ? _filterData->uri().path():_filterData->uri().url());
+
+ // Nothing interesting. Quit!
+ if ( cmd.isEmpty() )
+ {
+ return;
+ }
+ else if (cmd == "logout")
+ {
+ close();
+ kapp->requestShutDown();
+ }
+ else
+ {
+ switch( _filterData->uriType() )
+ {
+ case KURIFilterData::LOCAL_FILE:
+ case KURIFilterData::LOCAL_DIR:
+ case KURIFilterData::NET_PROTOCOL:
+ case KURIFilterData::HELP:
+ {
+ (void) new KRun( _filterData->uri() );
+ return;
+ }
+ case KURIFilterData::EXECUTABLE:
+ case KURIFilterData::SHELL:
+ {
+ exec = cmd;
+ if( _filterData->hasArgsAndOptions() )
+ cmd += _filterData->argsAndOptions();
+ break;
+ }
+ case KURIFilterData::UNKNOWN:
+ case KURIFilterData::ERROR:
+ default:
+ return;
+ }
+ }
+ KRun::runCommand( cmd, exec, "" );
+ return;
+}
+
+
+void StartMenu::endHistory()
+{
+ currentHistoryItem = history.end();
+}
+
+void StartMenu::search(const QString & string)
+{
+ disconnect (searchLine, SIGNAL(textChanged ( const QString & )), this, SLOT(search(const QString &)));
+ appList->search(string);
+}
+
+bool StartMenu::eventFilter ( QObject * o, QEvent * e )
+{
+ if (o == header)
+ {
+ if (e->type() == QEvent::MouseButtonPress && ((QMouseEvent*)e)->button() == Qt::LeftButton)
+ {
+ inMove = true;
+ movePoint = ((QMouseEvent*)e)->pos();
+ header->grabMouse(Qt::SizeAllCursor);
+ return true;
+ }
+ else if (e->type() == QEvent::MouseButtonRelease && ((QMouseEvent*)e)->button() == Qt::LeftButton)
+ {
+ inMove = false;
+ header->releaseMouse();
+ return true;
+ }
+ else if (e->type() == QEvent::MouseMove && inMove)
+ {
+ move(((QMouseEvent*)e)->globalPos() - movePoint);
+ return true;
+ }
+ else if (e->type() == QEvent::Resize && ((QResizeEvent*)e)->size().height() != ((QResizeEvent*)e)->oldSize().height())
+ {
+ int height = ((QResizeEvent*)e)->size().height();
+ KPixmap bgPix = QPixmap(32, height);
+ KPixmap bgPix1 = QPixmap(32, height/2);
+ KPixmap bgPix2 = QPixmap(32, height - bgPix1.height());
+ QColor buttonColor = ((QWidget*)o)->palette().color(QPalette::Active, QColorGroup::Button);
+ KPixmapEffect::gradient( bgPix1, buttonColor.light(130), buttonColor, KPixmapEffect::VerticalGradient, 0);
+ KPixmapEffect::gradient( bgPix2, buttonColor.dark(120), buttonColor.light(110), KPixmapEffect::VerticalGradient, 0);
+ QPainter p(&bgPix);
+ p.drawPixmap(0,0,bgPix1);
+ p.drawPixmap(0,bgPix1.height(),bgPix2);
+ p.end();
+ ((QWidget*)o)->setPaletteBackgroundPixmap( bgPix );
+ }
+ return false;
+ }
+ if (o != searchLine)
+ return false;
+ QLineEdit *le = (QLineEdit *)o;
+ if (e->type() == QEvent::KeyPress)
+ {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if (ke->state() & Qt::ControlButton || ke->state() & Qt::AltButton)
+ // might be shortcut, set category
+ {
+ if (ke->state() == Qt::ControlButton)
+ {
+ if (ke->key() == Qt::Key_Up)
+ {
+ if (categoryCombo->currentItem() > 0)
+ {
+ categoryCombo->setCurrentItem ( categoryCombo->currentItem() - 1 );
+ appList->showCategory(categoryCombo->currentText());
+ }
+ return true;
+ }
+ if (ke->key() == Qt::Key_Down)
+ {
+ if (categoryCombo->currentItem() < categoryCombo->count())
+ {
+ categoryCombo->setCurrentItem ( categoryCombo->currentItem() + 1 );
+ appList->showCategory(categoryCombo->currentText());
+ }
+ return true;
+ }
+ }
+ if (ke->key() == Qt::Key_Shift || ke->key() == Qt::Key_Control || ke->key() == Qt::Key_Alt)
+ return false;
+ ShortcutList::Iterator it;
+ for ( it = shortcutList.begin(); it != shortcutList.end(); ++it )
+ {
+ if (it.key().modFlags() == ke->state() && it.key().key() == ke->key())
+ setCategory( it.data() );
+ }
+ return true; //fire event to prevent lienedit action like ctrl+d -> del etc.
+ }
+ switch(ke->key())
+ {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ {
+ execute(le->text());
+ if (!(ke->state() & Qt::ControlButton))
+ close(); //bye
+ return true; //don't do anything else
+ }
+ case Qt::Key_Backspace:
+ case Qt::Key_Delete:
+ {
+ connect (le, SIGNAL(textChanged ( const QString & )), this, SLOT(search(const QString &)));
+ break;
+ }
+ case Qt::Key_Down:
+ {
+ if (history.isEmpty() || currentHistoryItem == history.end())
+ {
+ appList->appDown();
+ }
+ else // navigate history
+ {
+ le->blockSignals(true);
+ le->setText(*currentHistoryItem);
+ le->blockSignals(false);
+ currentHistoryItem++;
+ if (currentHistoryItem == history.end())
+ le->selectAll();
+ }
+ return true; //don't scroll the categories
+ }
+ case Qt::Key_Up:
+ {
+ if (!(history.isEmpty() || currentHistoryItem == history.begin()))
+ {
+ currentHistoryItem--;
+ le->blockSignals(true);
+ le->setText(*currentHistoryItem);
+ le->blockSignals(false);
+ }
+ return true; //don't scroll the categories
+ }
+ case Qt::Key_Escape:
+ {
+ close(); //bye
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+ }
+ else if (isVisible() && useKTTS && e->type() == QEvent::FocusIn)
+ {
+ QString text = i18n("TTS output", "The searchline has now the focus.");
+ sayText(text);
+ }
+ return false;
+}
diff --git a/starter/menu.h b/starter/menu.h
new file mode 100644
index 0000000..d11a651
--- /dev/null
+++ b/starter/menu.h
@@ -0,0 +1,320 @@
+
+#ifndef STARTMENU_H
+#define STARTMENU_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qpoint.h>
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qmap.h>
+#include <qpixmap.h>
+#include <qsortedlist.h>
+#include <qptrlist.h>
+#include <klineedit.h>
+#include <kservicegroup.h>
+#include "mykey.h"
+
+class KIconLoader;
+class QPaintEvent;
+class QMouseEvent;
+class QEvent;
+class QPixmap;
+class QVBoxLayout;
+class QComboBox;
+class StartMenuButton;
+class KConfig;
+class LinkConfig;
+
+class Panel : public QWidget//QScrollView
+{
+ friend class StartMenu;
+ friend class StartMenuButton;
+Q_OBJECT
+
+public:
+ Panel(int size = 32, QWidget * parent = 0, const char * name = 0);
+ Orientation orientation(){ return _orientation; }
+ void setOrientation ( Orientation o );
+// void addItem ( QWidget *w );
+ StartMenuButton* addIcon ( QString icon, QString title, QString command, QPoint pt = QPoint(-1,-1) );
+ void save(KConfig* config);
+ void repositionIcon ( StartMenuButton* bt, QPoint pt );
+ void ensureVisible(QRect & rect);
+ void reloadIcons(int size);
+ void poof();
+public slots:
+ void updateSize(int);
+protected:
+ void wheelEvent ( QWheelEvent * );
+ void dragEnterEvent ( QDragEnterEvent * );
+ void dropEvent ( QDropEvent * );
+ void mouseReleaseEvent ( QMouseEvent * e );
+ void resizeEvent ( QResizeEvent * );
+ LinkConfig *linkConfigDialog;
+ int _size;
+private:
+ int _count;
+ Orientation _orientation;
+ bool _draggedMe;
+ int _poofIndex;
+ QPoint iconAddPosition;
+ QPixmap *_poofPix;
+ QPixmap *_poofAnimPix;
+ QWidget *_poof;
+private slots:
+ void addIcon();
+ void runPoof();
+signals:
+ void message(const QString&);
+ void clearStatus();
+};
+
+class QTextDrag;
+
+class StartMenuButton : public QWidget
+{
+ friend class Panel;
+ Q_OBJECT
+
+public:
+ enum Orientation { Horizontal = 0, Vertical, Status };
+ StartMenuButton ( int size, QString icon, QString title, QString command, Orientation orientation, QWidget* parent = 0, const char * name = 0);
+ void smartMove(QPoint & pt); // prevents collisions with other childs of parentWidget()
+ void smartMove(int x, int y);
+ void reloadIcon(int size);
+public slots:
+ void edit();
+protected:
+ QString & command(){return m_command;}
+ QString & title(){return m_title;}
+ QString & icon(){return m_icon;}
+ void mouseReleaseEvent ( QMouseEvent * e );
+ void mouseMoveEvent ( QMouseEvent * e );
+ void enterEvent( QEvent * );
+ void leaveEvent( QEvent * );
+ bool isMoving() {return _moving;}
+private:
+ Orientation m_orientation;
+ bool _moving;
+ QTextDrag *myDrag;
+ QString m_command;
+ QString m_title;
+ QString m_icon;
+ QLabel* m_titleLabel;
+ QLabel* m_pixmapLabel;
+ QPixmap m_pix;
+ QPixmap m_hoverPix;
+signals:
+ void pressed(const QString &);
+ void hovered(const QString &);
+ void unhovered();
+ void updateSize(int);
+};
+
+class KService;
+class QDate;
+class AppList;
+
+class StartMenuEntry : public QWidget
+{
+ friend class AppList;
+ Q_OBJECT
+public:
+ StartMenuEntry(KService * service, QString relPath, int size = 32, bool neewbie = false, QWidget * parent = 0);
+ ~StartMenuEntry();
+ void reloadIcon(int size);
+ bool display;
+ QString title();
+ void saveStats();
+ int rank;
+ bool forNewbie;
+ //--- operators to allow use of qHeapSort()
+ bool operator==( const StartMenuEntry& se ) const;
+ bool operator!=( const StartMenuEntry& se ) const;
+ bool operator<( const StartMenuEntry& se ) const;
+ bool operator>( const StartMenuEntry& se ) const;
+ bool operator==( const double& d ) const;
+ bool operator!=( const double& d ) const;
+ bool operator<( const double& d ) const;
+ bool operator>( const double& d ) const;
+protected:
+ void focusInEvent ( QFocusEvent * );
+ void focusOutEvent ( QFocusEvent * );
+ void mouseReleaseEvent ( QMouseEvent * e );
+ void mouseMoveEvent ( QMouseEvent * mme );
+ void keyPressEvent ( QKeyEvent * e );
+ void enterEvent( QEvent * );
+ void leaveEvent( QEvent * );
+ KService* m_service;
+ QString groupPath;
+ QDate lastUse;
+ uint usage;
+private:
+ void execute();
+ QString exec;
+ bool isCurrent;
+ QLabel* m_titleLabel;
+ QLabel* m_commentLabel;
+ QLabel* m_pixmapLabel;
+ QPixmap m_pix;
+ QPixmap m_hoverPix;
+signals:
+ void closeMenu();
+ void pressed();
+ void appDown();
+ void appUp();
+ void appLeft();
+ void hovered(const QString &);
+ void sayText(const QString&);
+ void unhovered();
+ void popup(StartMenuEntry*);
+ void executed();
+};
+
+class KPopupMenu;
+class ConfigDialog;
+class HelpDialog;
+
+class AppList : public QScrollView
+{
+ friend class StartMenu;
+Q_OBJECT
+
+public:
+ AppList(int size = 32, QWidget * parent = 0);
+ StartMenuEntry* addApp(KService * service, QStringList & captions, QString relPath);
+ void finish();
+ StartMenuEntry* handledEntry; // for rightclick menu action
+ void writeEntry(QString path, bool hidden = false); // for add/edit
+ void reloadIcons(int size);
+public slots:
+ void addEntry();
+ void addDialog();
+ void removeEntry();
+ void editEntry();
+ void editDialog();
+ void clear();
+ void reset();
+ void search(const QString & string);
+ void appDown();
+ void appUp();
+ void appLeft();
+ void sort();
+ void showCategory(const QString & string);
+ void unblockPopup(){popupBlocked_ = false;}
+protected:
+ QStringList categories;
+ int favItemAmount;
+ void save(KConfig* config);
+ void mouseReleaseEvent ( QMouseEvent * e );
+ void windowActivationChange ( bool oldActive );
+private:
+ void init();
+ void insertGroup(KServiceGroup *g, QStringList & captions, QStringList & paths);
+ KServiceGroup::Ptr m_root;
+ KIconLoader *m_iconLoader;
+ QLabel *infoLabel;
+ QVBoxLayout * infoLayout;
+ QVBoxLayout * m_VLayout;
+ QFrame * m_widget;
+ bool newbie;
+ QStringList neewbieApps;
+ KPopupMenu *m_popup;
+ bool popupBlocked_;
+ int _size;
+ typedef QSortedList<StartMenuEntry> StartMenuEntryList;
+ typedef QMap<QString,StartMenuEntryList> KeyWordList;
+ StartMenuEntryList entryList;
+ KeyWordList m_keywordList;
+ KeyWordList m_groupList;
+ ConfigDialog* configDialog_;
+ HelpDialog* helpDialog_;
+private slots:
+ void popup(StartMenuEntry*);
+signals:
+ void looseKey();
+ void message(const QString&);
+ void sayText(const QString&);
+ void clearStatus();
+};
+
+class QStringList;
+
+class SearchLine : public KLineEdit
+{
+ Q_OBJECT
+public:
+ SearchLine( QWidget * parent );
+ bool blocked;
+protected slots:
+ void makeCompletion (const QString &);
+ void block(){blocked = true;}
+signals:
+ void typedTextChanged(const QString & string);
+};
+
+class KURIFilterData;
+class StarterConfig;
+class QSignalMapper;
+class KSqueezedTextLabel;
+
+class StartMenu : public QWidget
+{
+ friend class starter; // to allow setting the shortcutlis directly
+ Q_OBJECT
+public:
+ enum PanelPosition { North = 0, South, West, East, Nowhere };
+ StartMenu ( int size = 32, QWidget * parent = 0, WFlags f = 0 );
+ ~StartMenu();
+ void show();
+ void hide();
+ void reloadIcons(int size);
+ QStringList & categories(){return appList->categories;};
+ typedef QMap<MyKey,QString> ShortcutList;
+ void updateShortcuts(ShortcutList &);
+ void setFavItemAmount(int i) {if (appList) appList->favItemAmount = i;}
+ void setPanelPosition(PanelPosition p);
+public slots:
+ void sayText(const QString &text);
+ void toggleKTTS(bool);
+ void setCategory(const QString & category);
+ void save();
+protected:
+ bool eventFilter ( QObject * o, QEvent * e );
+ ShortcutList shortcutList;
+private slots:
+ void message(const QString &text);
+ void centerMessage(const QString &text);
+ void clearStatus();
+ void execute(const QString & command);
+ void search(const QString & string);
+ void endHistory();
+// void slotLock();
+private:
+ bool inMove;
+ uint m_spokenText;
+ int _size;
+ QWidget *header;
+ QPoint movePoint;
+ KURIFilterData *_filterData;
+ AppList *appList;
+ QComboBox *categoryCombo;
+ SearchLine *searchLine;
+ KSqueezedTextLabel *statusBar;
+ Panel *m_panel;
+ QStringList history;
+ QStringList::Iterator currentHistoryItem;
+ PanelPosition m_panelPos;
+ StartMenuButton *userButton;
+ QGridLayout *panelLayout;
+
+signals:
+ void aboutToHide();
+};
+
+#endif
diff --git a/starter/mykey.h b/starter/mykey.h
new file mode 100644
index 0000000..36a32d2
--- /dev/null
+++ b/starter/mykey.h
@@ -0,0 +1,73 @@
+
+#ifndef MYKEY_H
+#define MYKEY_H
+#include <qstring.h>
+
+class MyKey
+{
+public:
+ MyKey(short key, short modFlags){modFlags_ = modFlags; key_ = key;}
+ MyKey(){modFlags_ = 0; key_ = 0;}
+ MyKey(QString & string)
+ {
+ QString tmpString = string.left(string.findRev('+'));
+ modFlags_ = 0;
+ if (tmpString.contains("256")) // QString.setNum(Qt::ShiftButton)
+ modFlags_ |= Qt::ShiftButton;
+ if (tmpString.contains("512")) // QString.setNum(Qt::ControlButton)
+ modFlags_ |= Qt::ControlButton;
+ if (tmpString.contains("1024")) // QString.setNum(Qt::AltButton)
+ modFlags_ |= Qt::AltButton;
+ tmpString = string.right(string.length() - string.findRev('+') - 1);
+ key_ = tmpString.toShort();
+ }
+ short modFlags() const {return modFlags_;}
+ short key()const {return key_;}
+ bool operator==( const MyKey& myKey ) const
+ {
+ return (modFlags_ == myKey.modFlags() && key_ == myKey.key());
+ }
+ bool operator!=( const MyKey& myKey ) const
+ {
+ return (modFlags_ != myKey.modFlags() || key_ != myKey.key());
+ }
+ bool operator<( const MyKey& myKey ) const
+ {
+ return (!(modFlags_ < myKey.modFlags()) || key_ < myKey.key());
+ }
+ bool operator>( const MyKey& myKey ) const
+ {
+ return (!(modFlags_ > myKey.modFlags()) && key_ > myKey.key());
+ }
+ QString toString() const
+ {
+ QString string;
+ QString numString;
+ if (modFlags_ & Qt::ShiftButton)
+ {
+ numString.setNum(Qt::ShiftButton);
+ string += numString;
+ string += '+';
+ }
+ if (modFlags_ & Qt::ControlButton)
+ {
+ numString.setNum(Qt::ControlButton);
+ string += numString;
+ string += '+';
+ }
+ if (modFlags_ & Qt::AltButton)
+ {
+ numString.setNum(Qt::AltButton);
+ string += numString;
+ string += '+';
+ }
+ numString.setNum(key_);
+ string += numString;
+ return string;
+ }
+private:
+ short modFlags_;
+ short key_;
+};
+
+#endif
diff --git a/starter/po/Makefile.am b/starter/po/Makefile.am
new file mode 100644
index 0000000..0fa209c
--- /dev/null
+++ b/starter/po/Makefile.am
@@ -0,0 +1 @@
+POFILES = AUTO
diff --git a/starter/po/de.po b/starter/po/de.po
new file mode 100644
index 0000000..1e9061d
--- /dev/null
+++ b/starter/po/de.po
@@ -0,0 +1,351 @@
+# translation of de.po to German
+# translation of starter.po to German
+# This file is put in the public domain.
+# Thomas Lübking <thomas.luebking@web.de>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"POT-Creation-Date: 2005-07-19 21:15+0200\n"
+"PO-Revision-Date: 2005-07-19 22:15+0200\n"
+"Last-Translator: Thomas Lübking <thomas.luebking@web.de>\n"
+"Language-Team: German <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file buttons.ui line 16
+#: buttons.cpp:98 rc.cpp:3 rc.cpp:141
+#, no-c-format
+msgid "Select Button Images"
+msgstr "Skins auswählen"
+
+#. i18n: file buttons.ui line 103
+#: buttons.cpp:103 rc.cpp:14 rc.cpp:152
+#, no-c-format
+msgid "<b>Down</b>"
+msgstr "Gedrückt"
+
+#. i18n: file buttons.ui line 111
+#: buttons.cpp:104 rc.cpp:17 rc.cpp:155
+#, no-c-format
+msgid "<b>Hover</b>"
+msgstr "Unter Maus"
+
+#. i18n: file buttons.ui line 119
+#: buttons.cpp:105 rc.cpp:20 rc.cpp:158
+#, no-c-format
+msgid "<b>Base</b>"
+msgstr "Normal"
+
+#. i18n: file config.ui line 16
+#: config.cpp:285 menu.cpp:419 rc.cpp:23 rc.cpp:161
+#, no-c-format
+msgid "New Entry"
+msgstr "Neue Verknüpfung"
+
+#. i18n: file config.ui line 47
+#: config.cpp:287 rc.cpp:29 rc.cpp:167
+#, no-c-format
+msgid "F1"
+msgstr ""
+
+#. i18n: file config.ui line 108
+#: config.cpp:292 rc.cpp:40 rc.cpp:178
+#, no-c-format
+msgid "Extended Mode"
+msgstr "Erweiterte Einstellungen"
+
+#. i18n: file config.ui line 122
+#: config.cpp:293 rc.cpp:43 rc.cpp:181
+#, no-c-format
+msgid "Basic Settings"
+msgstr "Basiseinstellungen"
+
+#. i18n: file config.ui line 153
+#: config.cpp:294 rc.cpp:46 rc.cpp:184
+#, no-c-format
+msgid "Is a"
+msgstr "Ist ein"
+
+#. i18n: file config.ui line 218
+#: config.cpp:296 rc.cpp:50 rc.cpp:188
+#, no-c-format
+msgid "<b>Command</b>"
+msgstr "<b>Kommando</b>"
+
+#. i18n: file config.ui line 226
+#: config.cpp:297 rc.cpp:53 rc.cpp:191
+#, no-c-format
+msgid "<i>Keywords</i>"
+msgstr "<i>Schlüsselworte</i>"
+
+#. i18n: file config.ui line 234
+#: config.cpp:298 rc.cpp:56 rc.cpp:194
+#, no-c-format
+msgid "<i><b>Name</b></i>"
+msgstr "<i><b>Name</b></i>"
+
+#. i18n: file config.ui line 242
+#: config.cpp:299 rc.cpp:59 rc.cpp:197
+#, no-c-format
+msgid "<i><b>Category</b></i>"
+msgstr "<i><b>Kategorie</b></i>"
+
+#. i18n: file config.ui line 255
+#: config.cpp:300 rc.cpp:62 rc.cpp:200
+#, no-c-format
+msgid "Activate startup feedback"
+msgstr "Startrückmeldung aktivieren"
+
+#. i18n: file config.ui line 263
+#: config.cpp:301 rc.cpp:65 rc.cpp:203
+#, no-c-format
+msgid "Show in system tray"
+msgstr "Im Systray anzeigen"
+
+#. i18n: file config.ui line 290
+#: config.cpp:302 rc.cpp:68 rc.cpp:206
+#, no-c-format
+msgid "Description"
+msgstr "Beschreibung"
+
+#. i18n: file config.ui line 314
+#: config.cpp:303 rc.cpp:71 rc.cpp:209
+#, no-c-format
+msgid "Extended Settings"
+msgstr "Erweiterte Einstellungen"
+
+#. i18n: file config.ui line 325
+#: config.cpp:304 rc.cpp:74 rc.cpp:212
+#, no-c-format
+msgid "Working directory"
+msgstr "Arbeitsverzeichnis"
+
+#. i18n: file config.ui line 347
+#: config.cpp:305 rc.cpp:77 rc.cpp:215
+#, no-c-format
+msgid "Start in terminal"
+msgstr "Im Terminal ausführen"
+
+#. i18n: file config.ui line 358
+#: config.cpp:306 rc.cpp:80 rc.cpp:218
+#, no-c-format
+msgid "Terminal settings"
+msgstr "Terminal Einstellungen"
+
+#. i18n: file config.ui line 388
+#: config.cpp:307 rc.cpp:83 rc.cpp:221
+#, no-c-format
+msgid "Start as different user"
+msgstr "Als anderer Benutzer starten"
+
+#. i18n: file config.ui line 399
+#: config.cpp:308 rc.cpp:86 rc.cpp:224
+#, no-c-format
+msgid "Username"
+msgstr "Benutzername"
+
+#. i18n: file config.ui line 429
+#: config.cpp:309 rc.cpp:89 rc.cpp:227
+#, no-c-format
+msgid "Shortcut"
+msgstr "Tastenkürzel"
+
+#. i18n: file config.ui line 459
+#: config.cpp:310 rc.cpp:92 rc.cpp:230
+#, no-c-format
+msgid "None"
+msgstr ""
+
+#. i18n: file help.ui line 73
+#: help.cpp:72 rc.cpp:98 rc.cpp:236
+#, no-c-format
+msgid ""
+"<p align=\"center\"><font size=\"+3\"><b>Menu entry editor</b></font></p>\n"
+"<p align=\"center"
+"\">----------------------------------------------------------------------------------"
+"</p>\n"
+"<h3>Introduction</h3>\n"
+"\n"
+"By default, you will only see the basic settings for the new entry. Clicking "
+"\"Show More\" will give you access to some extended settings that can be "
+"interesting but mostly useless for you.<br><br>\n"
+"<b>Bold options must be entered</b> for a usefull entry, i<i>talic ones are "
+"respected by the search feature</i>.\n"
+"<br><br>\n"
+"<h3>Basic settings</h3>\n"
+"\n"
+"<b>Name:</b><br>\n"
+"This is the visible name of your new entry and can be any string, e.g. \"The "
+"Gimp\".<br>\n"
+"(Necessary, searchkey)\n"
+"<br><br>\n"
+"<b>Is a:</b><br>\n"
+"Describes the applications genre (generic name), e.g. \"Image manipulation"
+"\"<br>\n"
+"(Optional, yet not searched - maybe later)\n"
+"<br><br>\n"
+"<b>Category:</b><br>\n"
+"Choose an existing group or add a new one. The hierarchy is represented by "
+"seperating slashes (\"/\"), if you want to enter a slash, you must escape it "
+"(\"\\/\")<br>\n"
+"(Necessary, searchkey)\n"
+"<br><br>\n"
+"<b>Command:</b><br>\n"
+"The command to start the application, e.g. \"gimp-remote\". On *nix systems, "
+"is usually not necessary to pass the full path to the executably, but you "
+"can do so, if you want to start an executable that is shadowed by the "
+"executable in the path dir, e.g. \"/usr/local/gimp-1.3/gimp-remote\"<br>\n"
+"(Necessary, not searched)\n"
+"<br><br>\n"
+"<b>Keywords:</b><br>\n"
+"Comma separated list of keywords that refer to this application during "
+"search, e.g. \"image manipulation,pixel,photoshop\".<br>\n"
+"Please note:<br>\n"
+"1. search is <i>not</i> case sensitive<br>\n"
+"2. search finds partial matches, so it's <i>not</i> necessary to add e.g. "
+"\"image,image manipulation\"<br>\n"
+"3. different from the applications name, the keyword list will be translated "
+"(if) so if you think like \"'KImage' allready contains 'image', so i don't "
+"need it as keyword\" <b>you're wrong!</b><br>\n"
+"4. Finding good keywords is not simple, but in general use striking ones! "
+"\"editor\" is not a very good keyword, as allmost everything is an editor. "
+"(Gimp is a pixel-editor, KHexedit is a hex-editor, KEdit is a text-editor, a "
+"config dialog is a config-editor, ...)<br>\n"
+"(Optional, searchkey)\n"
+"<br><br>\n"
+"<b>Description:</b><br>\n"
+"This is the longtext description of your application (not a helptext, "
+"though ;), e.g. \"A powerfull image manipulator with a UI similar to "
+"photoshop. Supports Layers, filters, scripting, blahblahblah...\"\n"
+"You can use Qt richtext tags and there's no limit on the size, but keep it "
+"usefull ;) let's say something about 200 chars at max.<br>\n"
+"(Optional, not searched)"
+msgstr ""
+"<p align=\"center\"><font size=\"+3\"><b>Verknüpfungseditor</b></font></p>\n"
+"<p align=\"center"
+"\">----------------------------------------------------------------------------------"
+"</p>\n"
+"<h3>Einführung</h3>\n"
+"\n"
+"Standardmäßig werden nur die Basiseinstellungen für die neue Verknüpfung angezeigt. Indem man auf \"Erweiterte Einstellungen\" clickt, erhält man Zugriff auf einige weniger gebräuchliche Optionen.<br><br>\n"
+"<b>Fettgedruckte Felder müssen</b> für eine brauchbare Verknüpfung ausgefüllt werden, <i>kursive werden von der Suchfunktion berücksichtigt</i>.\n"
+"<br><br>\n"
+"<h3>Basiseinstellungen</h3>\n"
+"\n"
+"<b>Name:</b><br>\n"
+"Der sichtbare Name der Verknüpfung. Jede Zeichenkette ist erlaubt, z.B.\"The "
+"Gimp\".<br>\n"
+"(Notwendig, Suchschlüssel)\n"
+"<br><br>\n"
+"<b>Ist ein:</b><br>\n"
+"Das Genre der Anwendung (genericName), z.B. \"Bildbearbeitung"
+"\"<br>\n"
+"(Optional, derzeit nicht bei der Suche berücksichtigt)\n"
+"<br><br>\n"
+"<b>Kategorie:</b><br>\n"
+"Wählen Sie eine existierende Gruppe oder fügen sie eine neue hinzu. Die Hierarchie wird durch den \"/\" als Trennzeichen gekennzeichnet,wenn \"/\" Teil des Namens sein soll, muß ein \"\\\" vorangestellt werden (\"\\/\")<br>\n"
+"(Notwendig, Suchschlüssel (Der übersetzte Begriff))\n"
+"<br><br>\n"
+"<b>Kommando:</b><br>\n"
+"Das Kommando zum starten der Anwendung, z.B. \"gimp-remote\". Auf *nix Systemen ist es normalerweise nicht notwendig den vollen Pfad anzugeben, aber Sie können das tun, um eine Anwendung zu starten die durch eine andere überlagert wird, z.B. \"/usr/local/gimp-1.3/gimp-remote\"<br>\n"
+"(Notewndig, nicht durchsucht)\n"
+"<br><br>\n"
+"<b>Schlüsselworte:</b><br>\n"
+"Kommagetrennte Liste von Schlüsselworten für diese Anwendung, z.B. \"bildbearbeitung,pixel,photoshop\".<br>\n"
+"Anmerkungen:<br>\n"
+"1. Die Suche unterscheidet nicht zwischen GROSS und kleinschreibung<br>\n"
+"2. Die Suche findet auch Teilbegriffe, es ist also <i>nicht</i> notwendig z.B.\"Bild,Bildbearbeitung\" einzutragen<br>\n"
+"3. Anders als der Name der Anwendung, werden die Schlüssel übersetzt (wenn).- KImage hätte zwar \"image\" als schlüsselwort, aber nicht \"bild\"<br>\n"
+"4. Die Suche nach guten Schlüsselworten ist nicht immer leicht, aber sie sollten vor allem aussagekräftig sein!"
+"\"editor\" ist kein besonders gutes Schlüsselwort, denn fast alles ist irgendwie ein Editor."
+"(Gimp ist ein Pixel-Editor, KHexedit ist ein Hex-Editor, KEdit ist ein Text-Editor, ein Konfigurationsdialog ist ein Config-Editor, ...)<br>\n"
+"(Optional, Suchschlüssel)\n"
+"<br><br>\n"
+"<b>Beschreibung:</b><br>\n"
+"Die (längere) Beschreibung der Anwendung (aber kein Hilfetext ;), z.B. \"Eine mächtige Bildbearbeitung mit einer Photoshop ähnlichen Oberfläche. Unterstützt Ebenen, Filter, Scripte, blahblahblah...\"\n"
+"Sie können Qt RichText tags verwenden und die Zeichenlänge ist nicht limitiert, sollte aber im vernünftigen Rahmen gehelten werden - maximal 200 Zeichen.<br>\n"
+"(Optional, nicht durchsucht)"
+
+#: menu.cpp:307
+msgid ""
+"for TTS output, telling which item is focussed (keyboard) and than reads the "
+"comment"
+msgstr ""
+
+#: menu.cpp:338
+msgid ""
+"for TTS output, telling which item is hovered (mouse) and than reads the "
+"comment"
+msgstr ""
+
+#: menu.cpp:392 menu.cpp:483
+msgid "Edit Entry"
+msgstr "Verknüpfung modifizieren..."
+
+#: menu.cpp:393
+msgid "Remove Entry"
+msgstr "Verknüpfung entfernen..."
+
+#: menu.cpp:395
+msgid "Add Entry"
+msgstr "Neue Verknüpfung..."
+
+#: menu.cpp:446
+msgid "<qt>Are you sure you want to remove<br> %1</qt>"
+msgstr "<qt>Sind Sie sicher, daß sie <br> %1 <br> eintfernen möchten?</qt>"
+
+#: menu.cpp:446
+msgid "Remove ALI entry"
+msgstr "ALI Verknüpung entfernen"
+
+#: menu.cpp:614
+msgid "<qt><b>First Session Applications</b></qt>"
+msgstr "<qt><b>Erstbenutzer Anwendungen</b></qt>"
+
+#: menu.cpp:620 menu.cpp:882 menu.cpp:954
+msgid "<qt><b>Favorite Applications</b><br></qt>"
+msgstr "<qt><b>Beliebte Anwendungen</b><br></qt>"
+
+#: menu.cpp:872
+msgid ""
+"for TTS output, informs the user that no entries are in the currently "
+"selected group"
+msgstr ""
+
+#: menu.cpp:939
+msgid "for TTS output, no entries match the current search text"
+msgstr ""
+
+#: menu.cpp:953
+msgid ""
+"<qt><b>First Session Applications</b><br>This is a list of Applications you "
+"might want to try out</qt>"
+msgstr ""
+
+#: menu.cpp:1049
+msgid "Lock Session"
+msgstr ""
+
+#: menu.cpp:1056
+msgid "Switch User"
+msgstr ""
+
+#: menu.cpp:1062
+msgid "Logout"
+msgstr ""
+
+#: menu.cpp:1160
+msgid "Type to search or enter a command"
+msgstr "Tippen sie, um zu suchen oder ein Kommando direkt einzugeben"
+
+#: menu.cpp:1326
+msgid "TTS output"
+msgstr ""
+
+#: starter.cpp:43
+msgid "Select Button Images ..."
+msgstr "Skins auswählen..."
+
diff --git a/starter/po/starter.pot b/starter/po/starter.pot
new file mode 100644
index 0000000..c2ecc2c
--- /dev/null
+++ b/starter/po/starter.pot
@@ -0,0 +1,299 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2005-07-19 22:15+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. i18n: file buttons.ui line 16
+#: buttons.cpp:98 rc.cpp:3 rc.cpp:141
+#, no-c-format
+msgid "Select Button Images"
+msgstr ""
+
+#. i18n: file buttons.ui line 103
+#: buttons.cpp:103 rc.cpp:14 rc.cpp:152
+#, no-c-format
+msgid "<b>Down</b>"
+msgstr ""
+
+#. i18n: file buttons.ui line 111
+#: buttons.cpp:104 rc.cpp:17 rc.cpp:155
+#, no-c-format
+msgid "<b>Hover</b>"
+msgstr ""
+
+#. i18n: file buttons.ui line 119
+#: buttons.cpp:105 rc.cpp:20 rc.cpp:158
+#, no-c-format
+msgid "<b>Base</b>"
+msgstr ""
+
+#. i18n: file config.ui line 16
+#: config.cpp:285 menu.cpp:419 rc.cpp:23 rc.cpp:161
+#, no-c-format
+msgid "New Entry"
+msgstr ""
+
+#. i18n: file config.ui line 47
+#: config.cpp:287 rc.cpp:29 rc.cpp:167
+#, no-c-format
+msgid "F1"
+msgstr ""
+
+#. i18n: file config.ui line 108
+#: config.cpp:292 rc.cpp:40 rc.cpp:178
+#, no-c-format
+msgid "Extended Mode"
+msgstr ""
+
+#. i18n: file config.ui line 122
+#: config.cpp:293 rc.cpp:43 rc.cpp:181
+#, no-c-format
+msgid "Basic Settings"
+msgstr ""
+
+#. i18n: file config.ui line 153
+#: config.cpp:294 rc.cpp:46 rc.cpp:184
+#, no-c-format
+msgid "Is a"
+msgstr ""
+
+#. i18n: file config.ui line 218
+#: config.cpp:296 rc.cpp:50 rc.cpp:188
+#, no-c-format
+msgid "<b>Command</b>"
+msgstr ""
+
+#. i18n: file config.ui line 226
+#: config.cpp:297 rc.cpp:53 rc.cpp:191
+#, no-c-format
+msgid "<i>Keywords</i>"
+msgstr ""
+
+#. i18n: file config.ui line 234
+#: config.cpp:298 rc.cpp:56 rc.cpp:194
+#, no-c-format
+msgid "<i><b>Name</b></i>"
+msgstr ""
+
+#. i18n: file config.ui line 242
+#: config.cpp:299 rc.cpp:59 rc.cpp:197
+#, no-c-format
+msgid "<i><b>Category</b></i>"
+msgstr ""
+
+#. i18n: file config.ui line 255
+#: config.cpp:300 rc.cpp:62 rc.cpp:200
+#, no-c-format
+msgid "Activate startup feedback"
+msgstr ""
+
+#. i18n: file config.ui line 263
+#: config.cpp:301 rc.cpp:65 rc.cpp:203
+#, no-c-format
+msgid "Show in system tray"
+msgstr ""
+
+#. i18n: file config.ui line 290
+#: config.cpp:302 rc.cpp:68 rc.cpp:206
+#, no-c-format
+msgid "Description"
+msgstr ""
+
+#. i18n: file config.ui line 314
+#: config.cpp:303 rc.cpp:71 rc.cpp:209
+#, no-c-format
+msgid "Extended Settings"
+msgstr ""
+
+#. i18n: file config.ui line 325
+#: config.cpp:304 rc.cpp:74 rc.cpp:212
+#, no-c-format
+msgid "Working directory"
+msgstr ""
+
+#. i18n: file config.ui line 347
+#: config.cpp:305 rc.cpp:77 rc.cpp:215
+#, no-c-format
+msgid "Start in terminal"
+msgstr ""
+
+#. i18n: file config.ui line 358
+#: config.cpp:306 rc.cpp:80 rc.cpp:218
+#, no-c-format
+msgid "Terminal settings"
+msgstr ""
+
+#. i18n: file config.ui line 388
+#: config.cpp:307 rc.cpp:83 rc.cpp:221
+#, no-c-format
+msgid "Start as different user"
+msgstr ""
+
+#. i18n: file config.ui line 399
+#: config.cpp:308 rc.cpp:86 rc.cpp:224
+#, no-c-format
+msgid "Username"
+msgstr ""
+
+#. i18n: file config.ui line 429
+#: config.cpp:309 rc.cpp:89 rc.cpp:227
+#, no-c-format
+msgid "Shortcut"
+msgstr ""
+
+#. i18n: file config.ui line 459
+#: config.cpp:310 rc.cpp:92 rc.cpp:230
+#, no-c-format
+msgid "None"
+msgstr ""
+
+#. i18n: file help.ui line 73
+#: help.cpp:72 rc.cpp:98 rc.cpp:236
+#, no-c-format
+msgid ""
+"<p align=\"center\"><font size=\"+3\"><b>Menu entry editor</b></font></p>\n"
+"<p align=\"center"
+"\">----------------------------------------------------------------------------------"
+"</p>\n"
+"<h3>Introduction</h3>\n"
+"\n"
+"By default, you will only see the basic settings for the new entry. Clicking "
+"\"Show More\" will give you access to some extended settings that can be "
+"interesting but mostly useless for you.<br><br>\n"
+"<b>Bold options must be entered</b> for a usefull entry, i<i>talic ones are "
+"respected by the search feature</i>.\n"
+"<br><br>\n"
+"<h3>Basic settings</h3>\n"
+"\n"
+"<b>Name:</b><br>\n"
+"This is the visible name of your new entry and can be any string, e.g. \"The "
+"Gimp\".<br>\n"
+"(Necessary, searchkey)\n"
+"<br><br>\n"
+"<b>Is a:</b><br>\n"
+"Describes the applications genre (generic name), e.g. \"Image manipulation"
+"\"<br>\n"
+"(Optional, yet not searched - maybe later)\n"
+"<br><br>\n"
+"<b>Category:</b><br>\n"
+"Choose an existing group or add a new one. The hierarchy is represented by "
+"seperating slashes (\"/\"), if you want to enter a slash, you must escape it "
+"(\"\\/\")<br>\n"
+"(Necessary, searchkey)\n"
+"<br><br>\n"
+"<b>Command:</b><br>\n"
+"The command to start the application, e.g. \"gimp-remote\". On *nix systems, "
+"is usually not necessary to pass the full path to the executably, but you "
+"can do so, if you want to start an executable that is shadowed by the "
+"executable in the path dir, e.g. \"/usr/local/gimp-1.3/gimp-remote\"<br>\n"
+"(Necessary, not searched)\n"
+"<br><br>\n"
+"<b>Keywords:</b><br>\n"
+"Comma separated list of keywords that refer to this application during "
+"search, e.g. \"image manipulation,pixel,photoshop\".<br>\n"
+"Please note:<br>\n"
+"1. search is <i>not</i> case sensitive<br>\n"
+"2. search finds partial matches, so it's <i>not</i> necessary to add e.g. "
+"\"image,image manipulation\"<br>\n"
+"3. different from the applications name, the keyword list will be translated "
+"(if) so if you think like \"'KImage' allready contains 'image', so i don't "
+"need it as keyword\" <b>you're wrong!</b><br>\n"
+"4. Finding good keywords is not simple, but in general use striking ones! "
+"\"editor\" is not a very good keyword, as allmost everything is an editor. "
+"(Gimp is a pixel-editor, KHexedit is a hex-editor, KEdit is a text-editor, a "
+"config dialog is a config-editor, ...)<br>\n"
+"(Optional, searchkey)\n"
+"<br><br>\n"
+"<b>Description:</b><br>\n"
+"This is the longtext description of your application (not a helptext, "
+"though ;), e.g. \"A powerfull image manipulator with a UI similar to "
+"photoshop. Supports Layers, filters, scripting, blahblahblah...\"\n"
+"You can use Qt richtext tags and there's no limit on the size, but keep it "
+"usefull ;) let's say something about 200 chars at max.<br>\n"
+"(Optional, not searched)"
+msgstr ""
+
+#: menu.cpp:307
+msgid ""
+"for TTS output, telling which item is focussed (keyboard) and than reads the "
+"comment"
+msgstr ""
+
+#: menu.cpp:338
+msgid ""
+"for TTS output, telling which item is hovered (mouse) and than reads the "
+"comment"
+msgstr ""
+
+#: menu.cpp:392 menu.cpp:483
+msgid "Edit Entry"
+msgstr ""
+
+#: menu.cpp:393
+msgid "Remove Entry"
+msgstr ""
+
+#: menu.cpp:395
+msgid "Add Entry"
+msgstr ""
+
+#: menu.cpp:446
+msgid "<qt>Are you sure you want to remove<br> %1</qt>"
+msgstr ""
+
+#: menu.cpp:446
+msgid "Remove ALI entry"
+msgstr ""
+
+#: menu.cpp:614 menu.cpp:953
+msgid "<qt><b>First Session Applications</b></qt>"
+msgstr ""
+
+#: menu.cpp:620 menu.cpp:882 menu.cpp:954
+msgid "<qt><b>Favorite Applications</b><br></qt>"
+msgstr ""
+
+#: menu.cpp:872
+msgid ""
+"for TTS output, informs the user that no entries are in the currently "
+"selected group"
+msgstr ""
+
+#: menu.cpp:939
+msgid "for TTS output, no entries match the current search text"
+msgstr ""
+
+#: menu.cpp:1049
+msgid "Lock Session"
+msgstr ""
+
+#: menu.cpp:1056
+msgid "Switch User"
+msgstr ""
+
+#: menu.cpp:1062
+msgid "Logout"
+msgstr ""
+
+#: menu.cpp:1160
+msgid "Type to search or enter a command"
+msgstr ""
+
+#: menu.cpp:1326
+msgid "TTS output"
+msgstr ""
+
+#: starter.cpp:43
+msgid "Select Button Images ..."
+msgstr ""
diff --git a/starter/starter.cpp b/starter/starter.cpp
new file mode 100644
index 0000000..9740888
--- /dev/null
+++ b/starter/starter.cpp
@@ -0,0 +1,483 @@
+
+#include <qcombobox.h>
+#include <qcursor.h>
+#include <qdesktopwidget.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+# include <kpopupmenu.h>
+#include <qimage.h>
+#include <qfile.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qtimer.h>
+#include <kiconloader.h>
+#include <dcopclient.h>
+#include <kdebug.h>
+#include <kkeybutton.h>
+#include <kurlrequester.h>
+#include "starter.h"
+#include "starterconfig.h"
+#include "starterhelp.h"
+#include "menu.h"
+
+#define _SIZE2VALUE_(_s_) (_s_ == 16) ? 0 :\
+(_s_ == 22) ? 1 :\
+(_s_ == 32) ? 2 :\
+(_s_ == 48) ? 3 : 4
+
+#define _VALUE2SIZE_(_v_) (_v_ == 0) ? 16 :\
+(_v_ == 1) ? 22 :\
+(_v_ == 2) ? 32 :\
+(_v_ == 3) ? 48 : 64
+
+starter::starter(const QString& configFile, Type type, int actions, QWidget *parent, const char *name)
+: DCOPObject("StarterIface"), KPanelApplet(configFile, type, actions, parent, name)
+{
+ configPopup = new KPopupMenu(this);
+ popupBlocked = false;
+ mainView = new QLabel(this);
+
+ configDialog = new StarterConfig(this);
+ QRect desktop = QDesktopWidget().availableGeometry( configDialog );
+ configDialog->move((desktop.width() - configDialog->width())/2, (desktop.height() - configDialog->height())/2);
+ KConfig config("bStarter", false, false);
+ config.setGroup("Settings");
+ configDialog->buttonShortcut->setEnabled(false);
+ configDialog->BaseURL->setURL(config.readEntry("BaseImage", "" ));
+ configDialog->HoverURL->setURL(config.readEntry("HoverImage", "" ));
+ configDialog->DownURL->setURL(config.readEntry("DownImage", "" ));
+ configDialog->useKTTS->setChecked(config.readBoolEntry("useKTTS", false ));
+
+ configDialog->customPopupSize->setChecked(config.readBoolEntry("CustomPopupSize", false ));
+ configDialog->customDialogSize->setChecked(config.readBoolEntry("CustomDialogSize", false ));
+ configDialog->customDialogPos->setChecked(config.readBoolEntry("CustomDialogPos", false ));
+ configDialog->fixedDialogPos->setChecked(config.readBoolEntry("FixedDialogPos", false ));
+ configDialog->dialogFollowMouse->setChecked(config.readBoolEntry("DialogFollowMouse", false ));
+ configDialog->showDialogTitlebar->setChecked(config.readBoolEntry("ShowDialogTitlebar", false ));
+ configDialog->popupW->setValue(config.readNumEntry("PopupW", 0 ));
+ configDialog->popupH->setValue(config.readNumEntry("PopupH", 0 ));
+ configDialog->dialogW->setValue(config.readNumEntry("DialogW", 0 ));
+ configDialog->dialogH->setValue(config.readNumEntry("DialogH", 0 ));
+ configDialog->dialogX->setValue(config.readNumEntry("DialogX", 0 ));
+ configDialog->dialogY->setValue(config.readNumEntry("DialogY", 0 ));
+ configDialog->favItemAmount->setValue(config.readNumEntry("FavItemAmount", 10 ));
+ configDialog->dialogPanelPos->setCurrentItem(config.readNumEntry("DialogPanelPos", 1 ));
+ configDialog->popupPanelPos->setCurrentItem(config.readNumEntry("PopupPanelPos", 2 ));
+ _iconSize = config.readNumEntry("IconSize", 32 );
+ configDialog->iconSize->setCurrentItem(_SIZE2VALUE_(_iconSize));
+
+ startMenu = new StartMenu(_iconSize, this, Qt::WType_Popup);
+ shortcutList = startMenu->shortcutList;
+ configDialog->categoryList->insertStringList(startMenu->categories());
+ connect (startMenu, SIGNAL(aboutToHide()), this, SLOT(unblockPopupDelayed()));
+ connect(configDialog->useKTTS, SIGNAL(toggled( bool )), startMenu, SLOT(toggleKTTS(bool)));
+
+ //---
+ connect(configDialog->categoryList, SIGNAL(highlighted(int)), this, SLOT(activateShortcutButton(int)));
+ connect(configDialog->buttonShortcut, SIGNAL(capturedShortcut (const KShortcut &)), this, SLOT(addShortcut(const KShortcut &)));
+ connect(configDialog->categoryList, SIGNAL(highlighted ( const QString & )), this, SLOT(updateShortcutButton(const QString &)));
+ connect(configDialog->buttonOk, SIGNAL(clicked()), this, SLOT(updateSettings()));
+ StarterHelp *helpDialog = new StarterHelp(configDialog);
+ connect(configDialog->buttonHelp, SIGNAL(clicked()), helpDialog, SLOT(show()));
+ //-----
+ configPopup->insertItem(i18n("Configure the Startmenu"), configDialog, SLOT(show()));
+ configDialog->BaseURL->setFilter( "*.png" );
+ configDialog->HoverURL->setFilter( "*.png" );
+ configDialog->DownURL->setFilter( "*.png" );
+ mainView->move(0,0);
+ if (parent) move(parent->x(),parent->y());
+ mainView->installEventFilter(this);
+ reloadImages();
+ mainView->setPixmap(pixmap);
+ mainView->show();
+}
+
+void starter::activateShortcutButton(int i)
+{
+ configDialog->buttonShortcut->setEnabled(bool(i));
+}
+
+void starter::addShortcut(const KShortcut &cut)
+{
+ // in case of empty shortcut, remove the entry from the list and return
+ if (!short(cut.keyCodeQt()))
+ {
+ ShortcutList::Iterator it;
+ for ( it = shortcutList.begin(); it != shortcutList.end(); ++it )
+ if (it.data() == configDialog->categoryList->currentText())
+ {
+ shortcutList.remove(it);
+ break;
+ }
+ configDialog->buttonShortcut->setShortcut(KShortcut::null(), false);
+ return;
+ }
+ // generate MyKey
+ short state = 0;
+ if (cut.seq(0).key(0).modFlags() & KKey::CTRL)
+ state |= Qt::ControlButton;
+ if (cut.seq(0).key(0).modFlags() & KKey::ALT)
+ state |= Qt::AltButton;
+ if (cut.seq(0).key(0).modFlags() & KKey::SHIFT)
+ state |= Qt::ShiftButton;
+ MyKey key(cut.seq(0).keyCodeQt(), state);
+ // Test if this is a valid shotrcut, i.e. contains 'ctrl' or 'alt', returns iff not
+ if (!(state & Qt::ControlButton || state & Qt::AltButton))
+ {
+ KMessageBox::sorry(this, i18n("<qt>To ensure usefull behaviour of the searchline, the shortcut <b>must contain</b> a metabutton, i.e. <b>'ctrl' and/or 'alt'</b></qt>"), i18n("Sorry, invalid Shortcut"));
+ return;
+ }
+ // test if the cut was allready bound to another category and ask the user whta to do (return iff not rebind)
+ ShortcutList::Iterator it = shortcutList.find(key);
+ if ((it != shortcutList.end() && KMessageBox::questionYesNo(this, i18n("<qt>The selected shortcut is allready bound to the category \"%1\".<br>Do you want to <b>rebind</b> it?</qt>").arg(it.data()), i18n("Rebind Shortcut?")) == KMessageBox::No))
+ return;
+ // if rebind (it is not end and we did not return ;) remove the old shortcut
+ if (it != shortcutList.end())
+ {
+ shortcutList.remove(it);
+ }
+ // test if another shortcut is bound to this category and remove it in case
+ for ( it = shortcutList.begin(); it != shortcutList.end(); ++it )
+ if (it.data() == configDialog->categoryList->currentText())
+ {
+ shortcutList.remove(it);
+ break;
+ }
+ // add new shortcut/category map entry
+ shortcutList[key] = configDialog->categoryList->currentText();
+ // update UI
+ configDialog->buttonShortcut->setShortcut(cut, false);
+}
+
+void starter::updateShortcutButton(const QString & category)
+{
+ ShortcutList::Iterator it;
+ for ( it = shortcutList.begin(); it != shortcutList.end(); ++it )
+ if (it.data() == category)
+ {
+ QKeyEvent qke( QEvent::KeyPress, it.key().key(), 0, it.key().modFlags());
+ KKey kkey(&qke);
+ KShortcut ksc(kkey);
+ configDialog->buttonShortcut->setShortcut(ksc, false);
+ return;
+ }
+ configDialog->buttonShortcut->setShortcut(KShortcut::null(), false);
+}
+
+starter::~starter()
+{
+}
+
+void starter::updateSettings()
+{
+ startMenu->updateShortcuts(shortcutList);
+ KConfig *config = new KConfig("bStarter", false, false);
+ config->setGroup("Settings");
+ config->writeEntry("BaseImage", configDialog->BaseURL->url());
+ config->writeEntry("HoverImage", configDialog->HoverURL->url());
+ config->writeEntry("DownImage", configDialog->DownURL->url());
+ config->writeEntry("useKTTS", configDialog->useKTTS->isChecked());
+ config->writeEntry("CustomPopupSize", configDialog->customPopupSize->isChecked());
+ config->writeEntry("CustomDialogSize", configDialog->customDialogSize->isChecked());
+ config->writeEntry("CustomDialogPos", configDialog->customDialogPos->isChecked());
+ config->writeEntry("FixedDialogPos", configDialog->fixedDialogPos->isChecked());
+ config->writeEntry("DialogFollowMouse", configDialog->dialogFollowMouse->isChecked());
+ config->writeEntry("ShowDialogTitlebar", configDialog->showDialogTitlebar->isChecked());
+ config->writeEntry("PopupW", configDialog->popupW->value());
+ config->writeEntry("PopupH", configDialog->popupH->value());
+ config->writeEntry("DialogW", configDialog->dialogW->value());
+ config->writeEntry("DialogH", configDialog->dialogH->value());
+ config->writeEntry("DialogX", configDialog->dialogX->value());
+ config->writeEntry("DialogY", configDialog->dialogY->value());
+ config->writeEntry("FavItemAmount", configDialog->favItemAmount->value());
+ config->writeEntry("DialogPanelPos", configDialog->dialogPanelPos->currentItem());
+ config->writeEntry("PopupPanelPos", configDialog->popupPanelPos->currentItem());
+ if (_iconSize != (_VALUE2SIZE_(configDialog->iconSize->currentItem())))
+ {
+ _iconSize = _VALUE2SIZE_(configDialog->iconSize->currentItem());
+ config->writeEntry("IconSize", _iconSize);
+ startMenu->reloadIcons(_iconSize);
+ }
+ startMenu->setFavItemAmount(configDialog->favItemAmount->value());
+ config->setGroup("Shortcuts");
+ QStringList cuts; QStringList cats;
+ ShortcutList::Iterator it;
+ for ( it = shortcutList.begin(); it != shortcutList.end(); ++it )
+ {
+ cuts.append(it.key().toString());
+ cats.append(it.data());
+ }
+ config->writeEntry("Shortcuts", cuts, ',');
+ config->writeEntry("Categories", cats, ',');
+ reloadImages();
+ delete config;
+}
+
+#define _VALID_(_url_) configDialog && !configDialog->_url_->url().isEmpty() && QFile::exists(configDialog->_url_->url())
+
+void starter::reloadImages()
+{
+ KIconLoader* iLoader = KGlobal::iconLoader();
+ QString pth;
+ if (_VALID_(BaseURL))
+ pth = configDialog->BaseURL->url();
+ else
+ pth = iLoader->iconPath("bStarter", KIcon::Small, true);
+ if (pth)
+ pixmap = QImage(pth);
+ if (!pth || pixmap.isNull())
+ {
+ pixmap = QPixmap(22,22);
+ pixmap.fill(Qt::black);
+ }
+ pth = QString();
+ if (_VALID_(HoverURL))
+ pth = configDialog->HoverURL->url();
+ else
+ pth = iLoader->iconPath("bStarter_hover", KIcon::Small, true);
+ if (pth)
+ hoverPixmap = QImage(pth);
+ if (!pth || hoverPixmap.isNull())
+ {
+ hoverPixmap = QPixmap(22,22);
+ hoverPixmap.fill(Qt::black);
+ }
+ pth = QString();
+ if (_VALID_(DownURL))
+ pth = configDialog->DownURL->url();
+ else
+ pth = iLoader->iconPath("bStarter_down", KIcon::Small, true);
+ if (pth)
+ downPixmap = QImage(pth);
+ if (!pth || downPixmap.isNull())
+ {
+ downPixmap = QPixmap(22,22);
+ downPixmap.fill(Qt::white);
+ }
+ int wd = pixmap.width();
+ int ht = pixmap.height();
+ if (wd < hoverPixmap.width()) wd = hoverPixmap.width();
+ if (wd < downPixmap.width()) wd = downPixmap.width();
+ if (ht < hoverPixmap.height()) ht = hoverPixmap.height();
+ if (ht < downPixmap.height()) ht = downPixmap.height();
+ mainView->setFixedSize(wd,ht);
+ repaint();
+}
+
+void starter::resizeEvent ( QResizeEvent *rev )
+{
+ pixmap = pixmap.convertToImage().smoothScale(rev->size().height()*pixmap.width()/pixmap.height(),rev->size().height());
+ downPixmap = downPixmap.convertToImage().smoothScale(rev->size().height()*downPixmap.width()/downPixmap.height(),rev->size().height());
+ hoverPixmap = hoverPixmap.convertToImage().smoothScale(rev->size().height()*hoverPixmap.width()/hoverPixmap.height(),rev->size().height());
+ mainView->setFixedSize(rev->size().height()*mainView->width()/mainView->height(),rev->size().height());
+ mainView->setPixmap(pixmap);
+ KPanelApplet::resizeEvent(rev);
+}
+
+void starter::configureMenu()
+{
+ KApplication::startServiceByDesktopName("kmenuedit", QStringList(), 0, 0, 0, "", true);
+}
+
+void starter::preferences()
+{
+ KApplication::startServiceByDesktopName("kmenuedit", QStringList(), 0, 0, 0, "", true);
+}
+
+int starter::widthForHeight(int height) const
+{
+ return mainView->width();
+}
+
+int starter::heightForWidth(int width) const
+{
+ return mainView->height();
+}
+
+void starter::unblockPopupDelayed()
+{
+ popupBlocked = true;
+ QTimer::singleShot ( 50, this, SLOT(unblockPopup()) );
+}
+
+void starter::unblockPopup()
+{
+ popupBlocked = false;
+ if (mainView->hasMouse())
+ mainView->setPixmap(hoverPixmap);
+ else
+ mainView->setPixmap(startMenu->isShown() ? downPixmap : pixmap);
+ mainView->repaint();
+}
+
+#define _MAX_(a,b) (a > b ? a : b)
+void starter::popupMenu()
+{
+ if (popupBlocked)
+ return;
+ {
+// if (!isDialog_)
+// return;
+ startMenu->setMinimumSize ( 0, 0 );
+ startMenu->setMaximumSize ( 32767, 32767 );
+ setActiveWindow();
+ startMenu->setPanelPosition((StartMenu::PanelPosition)configDialog->popupPanelPos->currentItem());
+ if (configDialog->customPopupSize->isChecked())
+ {
+ startMenu->resize(configDialog->popupW->value(),configDialog->popupH->value());
+ startMenu->setFixedSize(startMenu->size());
+// startMenu->setFixedSize(_MAX_(configDialog->popupW->value(), startMenu->minimumWidth()), _MAX_(configDialog->popupH->value(), startMenu->minimumHeight()));
+ }
+ else
+ {
+ QRect desktop = QDesktopWidget().availableGeometry( startMenu );
+ startMenu->resize(desktop.width()/5, 2*desktop.height()/3);
+ startMenu->setFixedSize(startMenu->size());
+// startMenu->setFixedSize(_MAX_(startMenu->minimumWidth(), desktop.width()/5) ,_MAX_(startMenu->minimumHeight(), 2*desktop.height()/3)); // 1/5 screen width, 2/3 screen height
+ }
+
+ QPoint pt = mapToGlobal(pos());
+ QRect desktop = QDesktopWidget().availableGeometry( startMenu );
+ int x = pt.x();
+ int y = pt.y();
+
+ switch(position())
+ {
+ case pTop:
+ y += height() + 1;
+ if (x + startMenu->width() > desktop.right())
+ x = desktop.right() - startMenu->width();
+ if (x < 0) x = 0;
+ break;
+ case pLeft:
+ x += width() + 1;
+ if (y + startMenu->height() > desktop.bottom())
+ y = desktop.bottom() - startMenu->height();
+ if (y < 0) y = 0;
+ break;
+ case pBottom:
+ y -= startMenu->height() - 1;
+ if (x + startMenu->width() > desktop.right())
+ x = desktop.right() - startMenu->width();
+ if (x < 0) x = 0;
+ break;
+ case pRight:
+ x -= startMenu->width() - 1;
+ if (y + startMenu->height() > desktop.bottom())
+ y = desktop.bottom() - startMenu->height();
+ if (y < 0) y = 0;
+ }
+ pt = QPoint(x, y);
+
+ startMenu->reparent(this, Qt::WType_Popup, pt, true);
+ }
+}
+
+void starter::showMenu()
+{
+ startMenu->setMinimumSize ( 0, 0 );
+ startMenu->setMaximumSize ( 32767, 32767 );
+ startMenu->setPanelPosition((StartMenu::PanelPosition)configDialog->dialogPanelPos->currentItem());
+ if (configDialog->customDialogSize->isChecked())
+ {
+ startMenu->resize(configDialog->dialogW->value(), configDialog->dialogH->value());
+ startMenu->setFixedSize(startMenu->size());
+// startMenu->setFixedSize(_MAX_(configDialog->dialogW->value(), startMenu->minimumWidth()), _MAX_(startMenu->minimumHeight(), configDialog->dialogH->value()));
+ }
+ else
+ {
+ QRect desktop = QDesktopWidget().availableGeometry( startMenu );
+// setActiveWindow();
+ startMenu->resize(desktop.width()/2, desktop.width()*9/32);
+ startMenu->setFixedSize(startMenu->size());
+// startMenu->setFixedSize(_MAX_(startMenu->minimumWidth(), desktop.width()/2) , _MAX_(startMenu->minimumHeight(), desktop.width()*9/32)); // 16:9 window, width == 1/2 screen
+ }
+ QPoint pt;
+ if (configDialog->customDialogPos->isChecked())
+ {
+ if (configDialog->dialogFollowMouse->isChecked())
+ {
+ QRect desktop = QDesktopWidget().availableGeometry( startMenu );
+ int x,y;
+ x = QCursor::pos().x() + startMenu->width()/2 < desktop.width() ? QCursor::pos().x() - startMenu->width()/2 : desktop.width() - startMenu->width();
+ if (x < 0) x = 0;
+ y = QCursor::pos().y() + startMenu->height()/2 < desktop.height() ? QCursor::pos().y() - startMenu->height()/2 : desktop.height() - startMenu->height();
+ if (y < 0) y = 0;
+ pt = QPoint(x, y);
+ }
+ else
+ pt = QPoint(configDialog->dialogX->value(), configDialog->dialogY->value());
+ }
+ else
+ {
+ QRect desktop = QDesktopWidget().availableGeometry( startMenu );
+ pt = QPoint((desktop.right() - startMenu->width())/2, (desktop.bottom() - startMenu->height())/2);
+ }
+ if (configDialog->showDialogTitlebar->isChecked())
+ startMenu->reparent(this, Qt::WType_TopLevel, pt, true);
+ else
+ startMenu->reparent(this, Qt::WType_TopLevel | Qt::WStyle_Customize | Qt::WStyle_NoBorder, pt, true);
+}
+
+bool starter::eventFilter( QObject*, QEvent *e )
+{
+ switch (e->type())
+ {
+ case QEvent::Enter:
+ {
+ mainView->setPixmap(hoverPixmap);
+ mainView->repaint();
+ return TRUE;
+ }
+ case QEvent::Leave:
+ {
+ mainView->setPixmap(startMenu->isShown() ? downPixmap : pixmap);
+ mainView->repaint();
+ return TRUE;
+ }
+ case QEvent::MouseButtonPress:
+ {
+ if (((QMouseEvent*)e)->button() == Qt::RightButton)
+ {
+ configPopup->popup(((QMouseEvent*)e)->globalPos());
+ return TRUE;
+ }
+ if (((QMouseEvent*)e)->button() == Qt::LeftButton)
+ {
+ mainView->setPixmap(downPixmap);
+ mainView->repaint();
+ popupMenu();
+ }
+ return TRUE;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ if (((QMouseEvent*)e)->button() != Qt::LeftButton)
+ return FALSE;
+ if (mainView->hasMouse())
+ mainView->setPixmap(hoverPixmap);
+ else
+ mainView->setPixmap(startMenu->isShown() ? downPixmap : pixmap);
+ mainView->repaint();
+ return TRUE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+extern "C"
+{
+ KPanelApplet* init( QWidget *parent, const QString& configFile)
+ {
+ KGlobal::locale()->insertCatalogue("starter");
+ return new starter(configFile, KPanelApplet::Normal,
+ KPanelApplet::Preferences,
+ parent, "baghirastarter");
+ }
+}
diff --git a/starter/starter.desktop b/starter/starter.desktop
new file mode 100644
index 0000000..cfc27dc
--- /dev/null
+++ b/starter/starter.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Baghira Starter
+Icon=bStarter
+X-KDE-Library=libbaghirastarter
+X-KDE-UniqueApplet=true
+
diff --git a/starter/starter.h b/starter/starter.h
new file mode 100644
index 0000000..39c72b9
--- /dev/null
+++ b/starter/starter.h
@@ -0,0 +1,72 @@
+
+#ifndef STARTER_H
+#define STARTER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kpanelapplet.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qpixmap.h>
+// #include <qpainter.h>
+#include <kconfig.h>
+#include <kshortcut.h>
+#include "starteriface.h"
+#include "mykey.h"
+
+class DCOPClient;
+class QLabel;
+class KPopupMenu;
+class StartMenu;
+class StarterConfig;
+
+class starter : public KPanelApplet, virtual public StarterIface
+{
+ Q_OBJECT
+
+public:
+ starter(const QString& configFile, Type t = Normal, int actions = 0,
+ QWidget *parent = 0, const char *name = 0);
+ ~starter();
+
+ virtual int widthForHeight(int height) const;
+ virtual int heightForWidth(int width) const;
+ virtual void preferences();
+ void popupMenu();
+ void showMenu();
+protected:
+ virtual void resizeEvent ( QResizeEvent * );
+
+private:
+ enum State {Default, Hover, Down};
+ State state;
+ int _iconSize;
+ bool eventFilter( QObject *o, QEvent *e );
+ bool popupBlocked;
+// bool isDialog_;
+ QLabel *mainView;
+// QPainter m_painter;
+ DCOPClient *client;
+ KPopupMenu *configPopup;
+ StartMenu *startMenu;
+ QPixmap pixmap;
+ QPixmap hoverPixmap;
+ QPixmap downPixmap;
+ StarterConfig *configDialog;
+ typedef QMap<MyKey,QString> ShortcutList;
+ ShortcutList shortcutList;
+private slots:
+ void addShortcut(const KShortcut&);
+ void updateShortcutButton(const QString&);
+ void configureMenu();
+ void reloadImages();
+ void updateSettings();
+// void blockMenu();
+ void unblockPopupDelayed();
+ void unblockPopup();
+ void activateShortcutButton(int);
+};
+
+#endif
diff --git a/starter/starterconfig.ui b/starter/starterconfig.ui
new file mode 100644
index 0000000..a703e45
--- /dev/null
+++ b/starter/starterconfig.ui
@@ -0,0 +1,872 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>StarterConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>StarterConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>492</width>
+ <height>674</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Baghira Starter Config</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Startbutton images</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>BaseURL</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Hover&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>HoverURL</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Base&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Down&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>DownURL</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup" row="3" column="0">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Dialog options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>customDialogSize</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Custom dialog size</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>dialogW</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>3000</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>dialogH</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>2000</number>
+ </property>
+ </widget>
+ <spacer>
+ <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>111</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QRadioButton" row="4" column="0">
+ <property name="name">
+ <cstring>dialogFollowMouse</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Show dialog under mouse</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>fixedDialogPos</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Fixed</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>dialogX</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>dialogY</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>customDialogPos</cstring>
+ </property>
+ <property name="text">
+ <string>Custom dialog position</string>
+ </property>
+ </widget>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="8" column="0">
+ <property name="name">
+ <cstring>showDialogTitlebar</cstring>
+ </property>
+ <property name="text">
+ <string>Show titlebar for dialog</string>
+ </property>
+ </widget>
+ <widget class="Line" row="7" column="0">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="Line" row="5" column="0">
+ <property name="name">
+ <cstring>line2_3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="6" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Panel Position</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>North</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>South</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>West</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>East</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Nowhere</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>dialogPanelPos</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="currentItem">
+ <number>1</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>Popup options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>customPopupSize</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Custom popup size</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>popupW</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>3000</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>popupH</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>2000</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout6_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Panel Position</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>North</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>South</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>West</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>East</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Nowhere</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>popupPanelPos</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="currentItem">
+ <number>2</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>Items in favorite list</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>favItemAmount</cstring>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ <spacer>
+ <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>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>useKTTS</cstring>
+ </property>
+ <property name="text">
+ <string>Talk to me (via KTTS)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Icon SIze</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>16/22</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>22/32</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>32/48</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>48/64</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>64/128</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>iconSize</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="0" column="1" rowspan="4" colspan="1">
+ <property name="name">
+ <cstring>groupBox7</cstring>
+ </property>
+ <property name="title">
+ <string>Shortcuts</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox" row="0" column="0">
+ <property name="name">
+ <cstring>categoryList</cstring>
+ </property>
+ <property name="hScrollBarMode">
+ <enum>AlwaysOff</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KKeyButton">
+ <property name="name">
+ <cstring>buttonShortcut</cstring>
+ </property>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>StarterConfig</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>StarterConfig</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>customPopupSize</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>popupW</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customPopupSize</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>popupH</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogX</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogSize</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogW</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogSize</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogH</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fixedDialogPos</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogFollowMouse</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fixedDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogX</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fixedDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogY</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fixedDialogPos</receiver>
+ <slot>setChecked(bool)</slot>
+ </connection>
+ <connection>
+ <sender>customDialogPos</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dialogFollowMouse</receiver>
+ <slot>setChecked(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kkeybutton.h</includehint>
+</includehints>
+</UI>
diff --git a/starter/starterhelp.ui b/starter/starterhelp.ui
new file mode 100644
index 0000000..a0bf868
--- /dev/null
+++ b/starter/starterhelp.ui
@@ -0,0 +1,121 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>StarterHelp</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>StarterHelp</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>582</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Baghira Starter Config Help</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Filterline</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;qt&gt;The filterline provides several functions
+&lt;ul&gt;
+&lt;li&gt;It filters the below entry list&lt;/li&gt;
+&lt;li&gt;It autocompletes to executable entries in $PATH&lt;/li&gt;
+&lt;li&gt;The applied listbox lets you select the available categories&lt;/li&gt;
+&lt;li&gt;You can navigate through the categories either by using the mousewheel or by holding &lt;b&gt;ctrl+up/down&lt;/b&gt;&lt;/li&gt;
+&lt;li&gt;The category is also selected when calling the applied shortcut&lt;/li&gt;
+&lt;li&gt;It supports all protocols you know from Konqueror, e.g. "gg:Baghira" will google for "Baghira" etc.&lt;/li&gt;
+&lt;/ul&gt;
+Pressing &lt;b&gt;Enter&lt;/b&gt; will execute the (autocompleted) binary in $PATH or the entered kfm protocol call&lt;br&gt;
+Pressing &lt;b&gt;down&lt;/b&gt; will move the keyboard focus to the below entry list
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Entry Field</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;qt&gt;The entry field shows up all your menu entries (filtered)&lt;br&gt;&lt;br&gt;
+You can start an application by clicking the &lt;b&gt;left mouse button&lt;/b&gt; above the item (highlighted text) or by pressing &lt;b&gt;Enter&lt;/b&gt; if the entry has the keyboard focus (highlighted background).&lt;br&gt;&lt;br&gt;
+You may navigate by either scrolling the &lt;b&gt;mousewheel&lt;/b&gt; or using the &lt;b&gt;up/down&lt;/b&gt; keys (this will also shift the keyboard focus)&lt;br&gt;&lt;br&gt;
+Pressing the &lt;b&gt;left&lt;/b&gt; key will put focus on the filterline and select the whole text (i.e. start typing will change a complete new filter action)&lt;br&gt;&lt;br&gt;
+Pressing the &lt;b&gt;up&lt;/b&gt; key on the topmost item will act as above.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Panel</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;qt&gt;The panel allow you to store often used links, independent from the application links in the entry list&lt;br&gt;&lt;br&gt;
+To &lt;b&gt;add a link&lt;/b&gt;, either:&lt;br&gt;
+- rightclick the panel&lt;br&gt;
+- drag and drop a link out of the entry list&lt;br&gt;
+- drag and drop any url or text or command (uris and mails are handled, the rest is interpreted as simple command, any command that works on the filterline works here as well)&lt;br&gt;
+&lt;br&gt;
+To &lt;b&gt;remove a link&lt;/b&gt;, simply drag it out and drop it outside. (The panel interacts with the linklist from the baghira sidebar, links won't be removed, but copied if dragged from one to the other)&lt;br&gt;
+&lt;br&gt;
+To &lt;b&gt;configure a link&lt;/b&gt;, simply rightclick it&lt;br&gt;&lt;br&gt;
+To &lt;b&gt;move a link&lt;/b&gt;, just drag it and move i around.&lt;br&gt;&lt;br&gt;
+
+Te panel is &lt;b&gt;scrollable (mousewheel)&lt;/b&gt; and you can configure &lt;b&gt;individual positions&lt;/b&gt; for the popup and the dialog&lt;br&gt;&lt;br&gt;
+More poofs can be found e.g. here: &lt;a href="http://www.resexcellence.com/user_poofs.shtml"&gt;www.resexcellence.com/user_poofs.shtml&lt;/a&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/starter/starteriface.h b/starter/starteriface.h
new file mode 100644
index 0000000..be1469f
--- /dev/null
+++ b/starter/starteriface.h
@@ -0,0 +1,34 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Thomas Lübking *
+ * thomas.luebking@web.de *
+ * *
+ * 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 _STARTERIFACE_H_
+#define _STARTERIFACE_H_
+
+#include <dcopobject.h>
+
+class StarterIface : virtual public DCOPObject
+{
+ K_DCOP
+ k_dcop:
+ virtual void popupMenu() = 0;
+ virtual void showMenu() = 0;
+};
+
+#endif
diff --git a/starter/subdirs b/starter/subdirs
new file mode 100644
index 0000000..6cddb31
--- /dev/null
+++ b/starter/subdirs
@@ -0,0 +1 @@
+po