diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 4aed2c8219774f5d797760606b8489a92ddc5163 (patch) | |
tree | 3f8c130f7d269626bf6a9447407ef6c35954426a /kicker | |
download | tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kicker')
513 files changed, 69941 insertions, 0 deletions
diff --git a/kicker/AUTHORS b/kicker/AUTHORS new file mode 100644 index 000000000..b4c787bb2 --- /dev/null +++ b/kicker/AUTHORS @@ -0,0 +1,17 @@ +Copyright (c) 1999-2000 Matthias Ettrich <ettrich@kde.org> +Copyright (c) 1999-2000 Daniel M. Duley <mosfet@kde.org> +Copyright (c) 1999-2002 Matthias Elter <elter@kde.org> +Copyright (c) 1999-2000 Preston Brown <pbrown@kde.org> +Copyright (c) 2000 Rik Hemsley <rik@kde.org> +Copyright (c) 2000 Wilco Greven <j.w.greven@student.utwente.nl> +Copyright (c) 2001 John Firebaugh <jfirebaugh@kde.org> +Copyright (c) 2000-2001 Richard Moore <rich@kde.org> +Copyright (c) 2002-2005 Aaron J. Seigo <aseigo@kde.org> +Copyright (c) 2002-2003 Allan Sandfeld Jensen <carewolf@kde.org> + +The panel concept is based on kpanel which is: +Copyright (c) 1996-99 Matthias Ettrich <ettrich@kde.org> +Copyright (c) 1997 Christoph Neerfeld <Christoph.Neerfeld@bonn.netsurf.de> +Copyright (c) 1998 Pietro Iglio <iglio@kde.org> + +Current maintainer: Aaron J. Seigo <aseigo@kde.org> diff --git a/kicker/ChangeLog b/kicker/ChangeLog new file mode 100644 index 000000000..6ba662f7e --- /dev/null +++ b/kicker/ChangeLog @@ -0,0 +1,25 @@ +2004-06-10 Dan Bullok <dan.kde@bullok.com> + * Fixed Bug 42278 - Strange layout with Kicker and custom size. Now buttons are never wider (for horizontal) or taller (for vertical) than 58 pixels. + * Added some symbolic constants for some kicker values (max size, min size, default custom size), that were previously hard-coded in a few places. + +2002-01-03 John Firebaugh <jfirebaugh@kde.org> + * Use mouse polling instead of enter/leave events to trigger auto-unhiding. Much more reliable and will allow us to do things like only unhide at the corners or when the mouse hits the edge of the screen with a certain velocity. Also fixes #27660. + * New class core/panelmanager.cpp. For now, just has code for auto-hide, but will soon handle the screen layout of the panels. + +2002-01-02 John Firebaugh <jfirebaugh@kde.org> + * Now you can set the alignment by dnd. +2002-01-01 John Firebaugh <jfirebaugh@kde.org> + * Make the action taken for each mouse button on a task container configurable. + * Add Task::lower() method. +2002-01-01 John Firebaugh <jfirebaugh@kde.org> + * Add "Custom" item to size menu, restore checkmark next to current size. + * Add "Custom" radio button to kcmkicker, handle custom sizes correctly, i.e. don't keep resetting it to normal. +2001-12-30 John Firebaugh <jfirebaugh@kde.org> + * Split panelbutton.{h|cpp} into separate files. + * Rename each Panel*Button to *Button. + * Rename PanelExeButton to NonKDEAppButton. + * Fix crash in BrowserMenu after changing the directory. + * If a button saves its own config, it should also load its own config. + * Delete the config groups of removed applets and buttons. + * New application buttons are of a new class that saves only the relative path of the .desktop file. (Fixes 18289) + diff --git a/kicker/DESIGN b/kicker/DESIGN new file mode 100644 index 000000000..ca7fa7b2c --- /dev/null +++ b/kicker/DESIGN @@ -0,0 +1,180 @@ +This is the start of documentation for the design of Kicker. Add as motivated. + +Contents +-------- +1. Kicker Startup +2. The Extension Manager +3. The Plugin Manager +4. Files Important To Kicker That Aren't In kdebase/kicker +5. Top Level Directories +6. Class Overview +7. KIOSK features in Kicker + + +1. Kicker Startup + -------------- +NOTE: This is the design which we are working towards, not the design as it +currently is, but there's no point in documenting yesterday. + +The class Kicker is a subclass of KUniqueApplication and is where all the +fun begins. It is always available via the static Kicker::kicker() method. +Upon creation, Kicker::kicker() ensures that its resources are added to the +standard dirs. This includes tile, background and various plugin directories. + +Next the global keyboard accels are registered. When registering the "Popup +Launch Menu" accel, it then references the MenuManager. This creates the KMenu +and the facilities to update the KMenu when the installed .desktop files +change. This KMenu is shared by all items that provide access to it to keep +performance up and memory usage down. + +Next the ExtensionManager (EM), another singleton, is created. The EM loads +and manages all the KPanelExtension subclasses, or "panels". If +on load there are no extensions loaded by the EM, then Kicker creates a +default panel with a default setup. This default setup is based off of the +template file <TODO: decide where to store this file and what it is called>. + +Kicker then checks to see if the menubar panel has been selected and if so +sets up a panel at the top of the screen. It uses the kickermenubarrc +file for this panel, creating it if it does not exist. + +The individual extensions may end up loading various applets and even other +extensions, which they use the PluginManager (PM) and EM to do. + + +2. The Extension Manager + --------------------- + + +3. The Plugin Manager + ------------------ + + +4. Files Important To Kicker That Aren't In kdebase/kicker + ------------------------------------------------------- +There are two important sets of kicker-related files that aren't in this +source tree. The first is the kicker configuration panels, the second are +the applet and extentions classes. + +For historical reasons, the configuration panels can be found in +kdebase/kcontrol/kicker. When we move to a better RCS (e.g. subversion) +these files should be moved to kdebase/kicker/kcm + +(... add docu here about the structure of the kcm stuff and how it uses +DCOP to communicate with the panels ...) + +In kdelibs/kdeui there are two classes that are quite important to kicker. +The first is KPanelApplet, which is the base class of all kicker applets. +The other class is KPanelExtension, which is the base class of all kicker +extensions. + +These classes are in kdeui so that other applications besides kicker may +use these facilities, either to provide their own applet/extension +facilities or so as to provide kicker applets/extensions. This strategy +should be re-examined in KDE4 and the APIs of both classes cleaned up +extensively. + +5. Top Level Directories + --------------------- +applets/ +The basic set of applets. Everything here subclasses from KPanelApplet found +in kdelibs/kdeui. These can be assumed to exist at startup and are allowed, +if not encouraged to, access kicker internals. + +buttons/ +Anything button-like that you can click on in kicker. Includes the KMenu, +quickbrowsers and application buttons. + +core/ +As the name suggests, this is the main kicker code. This include the main() +and various containers and collection classes needed to glue everything +together. + +data/ +Icons, button tiles, backgrounds and the KMenu side images. + +extensions/ +Extensions, aka panels. Everything here subclasses from KPanelExtension. +Includes the external taskbar, kasbar, windowmaker doc applet bar, child +panel and universal sidebar. + +menuext/ +Like buttons, but also like menus. These are plugins that provide both +a button for the panel and a menu that appear in the KMenu. These are +generally encouraged over creating buttons in buttons/ that popup menus. + +proxy/ +Small applications that wrap applets and extensions allowing for out-of- +process execution of these items. This is used to safeguard kicker against +instiating an applet or extension that may crash, taking kicker with it if +they were loaded internally. + +share/ +Some basic classes that were meant for use beyond what is in core/. Should +probably be moved / consolidated with core/ eventually. + +ui/ +Menus and dialogs. Menus tend to contain "_mnu" in the file name. Kicker's +control panels are not found here, however. Those are in i +kdebase/kcontrol/kicker. + +taskbar/ +The code that implements the actual taskbar widget. This is wrapped by the +taskbar applet (applets/taskbar) and the taskbar extension (extensions/taskbar) + +taskmanager/ +Classes representing tasks and collections of tasks. Used by taskbar/ + + +6. Class Overview + -------------- + + +The Building Blocks Of A Panel +------------------------------ +Fittslawframe, Panner, ContainerArea, ContainerPanel + + +Applets +------- +KPanelApplet, AppletInfo, .desktop file description, PluginManager/PluginLoader + + +Extensions (aka "Panels") +------------------------- +KPanelExtension, .desktop file description, PluginLoader, ExtensionContainer, +ExtensionManager + + +7. KIOSK features in Kicker + ------------------------ + +Several aspects of the panel can be restricted: + +* Individual elements (buttons, applets, etc.) can be marked immutable. +This means that they can not be removed and their properties/configuration +can not be changed. + +How: The configuration group in kickerrc corresponding to the element is +marked immutable, OR, the configuration file associated with the element +(ConfigFile= entry, or additionally for Buttons FreeSpace2=) is marked +immutable. + +* The addition/removal of Applets, Application Buttons, Special Buttons +and Panels can be restricted. + +How: "General/Applets2" key is marked immutable. If this is done in the +kickerrc it applies to ALL panels. If done in a secondary panel's rc +it applies to that one panel only. + +* Panel configuration can be restricted. This affects appearance as wells +as menu-editing (see below) + +How: ??? "General" group in kickerrc is marked immutable (??? that would +imply that buttons can't be added either, loss of flexibility) +How: Use "kde-panel.desktop" control module restriction. + +* Menu editing can be restricted. Kicker offers several menu items in the +KDE menu beyond the applications menu itself. See "Configure Panel -> Menus" +How: Restrict action/menuedit (??? Are their cases where you would want to +restrict editing of the applications menu but not the other elements in +the KDE menu? diff --git a/kicker/HACKING b/kicker/HACKING new file mode 100644 index 000000000..c03925cdc --- /dev/null +++ b/kicker/HACKING @@ -0,0 +1,261 @@ +The Short Story +--------------- +Four space tabs, braces on their own lines, 80 character lines. +Code should look something like this: + +QString ExtensionManager::uniqueId() +{ + QString idBase = "Extension_%1"; + QString newId; + int i = 0; + bool unique = false; + + while (!unique) + { + ++i; + newId = idBase.arg(i); + + unique = true; + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); + it != itEnd; + ++it) + { + if ((*it)->extensionId() == newId) + { + unique = false; + break; + } + } + } + + return newId; +} + +Full Explanation +---------------- +As of 2004 kicker's codebase isn't the prettiest thing in the world. It's seen +a lot of work over a number of years without any sort of consistent coding +style being enforced. We are attempting to change this and bring some order +and consistency to the codebase. + +You may (will) notice that there are many discrepencies between the current +code base and this document. All new development should follow the coding style +as described below and one day the codebase will actually be consistent! Also +feel free to clean up the code around code you work on. For example, if you +change a number of lines in a method, reindent the whole method while you +are in there. However, wholescale reformatting of code is not appropriate. +This would make `cvs log` and `cvs ann` far less useful and that information +is even more important than re-indenting old code. + +General Principles +------------------ +Never use modal dialogs in kicker. This blocks EVERYTHING else in the kicker +UI, not just whatever bit of code has popped up the dialog. Since kicker is +one of the primary means for the user to interact with their desktop +environment, kicker must *always* be available for the user. + +NULL vs 0 +--------- +The use of 0 to express a null pointer is preferred over the use of NULL. +0 is not a magic value, it's the defined value of the null pointer in C++. +NULL, on the other hand, is a preprocessor directive (#define) and not only is +it more typing than '0' but I find preprocessor directives less elegant. + + SomeClass* instance = 0; + +Naming Conventions +------------------ +Class names start with a capital letter, member variables begin with m_. +Methods and functions start with a lower case letter. + +Names should be descriptive. If you can't tell what a variable or a method +does by its name, the name is wrong. Saving a dozen keystrokes today by +using cryptic variable names will only lead to maintenance headaches tomorrow. +Names longer than 20 characters is probably going overboard, however. Just +use your best judgement. + +Singletons will use a static method called the() to return the instatiated +object. + +Use 'true' and 'false', not 'TRUE' and 'FALSE' + +Comments +-------- +Code should be written with enough clarity that comments are not needed +above each line. However, if the code does something in a particular way +for a specific reason that may not be obvious to the next person who has to +work on it do provide a short comment describing what it does and why. + +Excessive commenting should be avoided since if there are too many comments +they tend to get ignored and won't be maintained, causing the comments and +the actual code to drift apart. Innacurate comments are worse than accurate +comments! + +While using the /* style */ of comments is ok, comments should use // wherever +possible. + +Comments can also provide notes for future work, including: + + // TODO: this is a todo item + // and should explain the todo in detail + + // BIC: this is a binary incompatible change, or a massive change that + // should wait until we are doing massive things like breaking binary + // compat + + // BUG: this is documenting a bug. It is preferred that they are fixed. + // but if you don't fix it, at least document it to save the next + // person some time in tracking down the problem. + +Indenting +--------- +Tabstop is 4 spaces. No tabs, only spaces. + +Try to keep lines under 80 characters in width. When wrapping a single +logical line of code across multiple lines, new lines should be indented +at least once and should preferably line up with parentheses, if any, on +the line above. e.g.: + + someMethod(parameterOne, parameterTwo, + parameterThree, parameterFour); + +If a boolean expression is spread out over several lines, the boolean +operator is always the last item on the line, e.g.: + + if ((condition1 || condition2) && + condition3 && + (condition4 || condition5)) + { + +Switch statements should have the case line indented and the case block +itsel further indented, e.g.: + + switch (condition) + { + case 1: + ... + break; + case 2: + ... + break; + default: + ...; + } + +Spaces +------ +A single space should appear between keywords and parentheses, eg: + + if ( + while ( + for ( + +No spaces appear between function/method names and parentheses: + + function( + someObject->method( + +No spaces appear between opening closing parens and the arguments: + + for (int i = 0; i < count; ++i) + +Spaces appear between operators, e.g.: + + int i = i + 3; + someObject.setValue(someObject.currentValue() + 1) + + +Braces +------ +Braces always appear on a line by themself, indented to align with the +above keyword: + + if (foo) + { + ... + } + else + { + ... + } + +Unless it uglifies the code, use braces even for one-liner conditionals: + + if (foo) + { + return 1; + } + +Always use braces if the conditional expression wraps across multiple +physical lines. + +Braces around case blocks in switch statements are optional. + + +Constructors +------------ +Constructors are written as: + + MyClass::MyClass(...) + : SuperClass(...), + m_member1(...), + m_member2(...), + ... + { + + +Class Definitions +----------------- +Class definitions will follow the following order: + + class <name> : <scope> <superclass> + { + <macros[1]> + <typedefs> + + public: + <ctors> + <dtors> + <operators> + <other methods> + + <members> + + public slots: + <methods> + + signals: + <methods> + + protected: + <ctors> + <dtors> + <operators> + + <members> + + protected slots: + <methods> + + private: + <ctors> + <dtors> + <operators> + + <members> + + private slots: + <methods> + }; + +Methods implementations may be in the class definition if doing so will +result in a measurable performance enhancement (e.g. it is called very often +from tight loops or is in a hot path) or if it is a simple, one-liner +setter/getter method. Otherwise methods should be implemented outside of +the class definition. + +[1] macros include things like Q_OBJECT and K_DCOP. the should ONLY appear in +files where they are actually necessary and not just randomly thrown in there +for fun. ;-) + diff --git a/kicker/Makefile.am b/kicker/Makefile.am new file mode 100644 index 000000000..6cce278cc --- /dev/null +++ b/kicker/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = libkicker taskmanager taskbar kicker extensions applets menuext proxy data + diff --git a/kicker/TODO b/kicker/TODO new file mode 100644 index 000000000..cf43fa146 --- /dev/null +++ b/kicker/TODO @@ -0,0 +1,119 @@ +Here are the top things that need to be or are being worked on in Kicker. +They are rated as to expected difficulty, from one to five stars. +They are also rated as to desirability, from one to five plusses. + +Issues Of Import +---------------- +Layout management + autoexpending panels on the same side of the screen need to stop expanding + at the point they run into each other. + make autohiding panels respect layout geometry too? e.g. don't overlap + autounhiding panels should not obscure other panels +ContainerArea completness + doesn't autoscroll when moving a container + doesn't add items near the mouse even position +Bring some standardization to how the various plugins are handled +Allow menubar == mainpanel +Move more of the buttons/ classes into menuext/ +Move appropriate applets into menuext/ +revisit libtaskbar and libtaskmanager + coordinate with kasbar authors + add support for composite +revisit DCOP interface + remove old/nonsensical calls + extend with calls to: + retrieve a panel dcop ref + hide/unhide + ... ? +libkicker + document functions + namespace it all (KickerLib?) + prep for binary compat + move + Panner -> core/ + does taskbar really need to use Panner? + rename + global.h/cpp -> util.h/cpp + add: + ServiceMenu? + PanelDrag? + KPanelExtension + KPanelApplet + allow usage of KickerTip + ExtensionSettings + ExtensionButton + poor name =/ + shouldn't be so menu-centric either +Optimize! + hiding: it seems there are more geometry calls made than really needed + get rid of movies (which nobody really uses) in PanelButton +Code clean ups + remove pseudo transparency in favour of composite + means handling composite properly, e.g. just the background and not + the actual icons, text, etc. + flatten the PanelExtension -> ContainerArea -> ContainerAreaLayout + hierarchy. perhaps merge PanelExtension and ContainerArea? + get rid of the insane number of classes in ui/? +A _good_ theming system + +Being Worked On +--------------- + +Applets +------- +Clock + Use styleclock.nextVersion() +Get rid of swallow applet +Make trash an extension button + +Unnasigned +----------------------- ++++++ Keyboard accessability +**** + We will follow the lead of the GNOME panel accessability work: + http://developer.gnome.org/projects/gap/keynav/panelnav.html + + To summarise: + + - Ctrl-Alt-Tab cycles focus between panels [Shift to reverse] + - Tab cycles focus between objects on the focused panel [Shift to + reverse] + - Arrow keys move focus within a focused applet + - Space activates focused control (on panel or within an applet) + ++++++ Settings dialog fix up +*** Now that we have KConfigXT, use it in the settings dialogs + Convert the "Arrangement" and "Hiding" modules. "Menus" and + "Appearance" are done as far as possible. + +++++ Floating panels +**** When a panel is set to "floating" the following entries are added + to the [General] config group: + FloatingPosition <-- geometry.topLeft(); + FloatingOrientation <-- horizontal or vertical + +++++ Drag and drop enhancements +*** Drag and drop behaviour is broken in various ways in kicker. + A popup menu should appear on drop like in Konqueror and KMail. + Dropping on buttons like QuickBrowsers, the Home icon, etc should + behave consistently and like dropping to a file manager window. + There are many DnD reports on bugs.kde.org which can provide + further inspiration. + +++++ Systray icon layout +**** The systray applet does a very basic homebrew layout of the icons + that currently has several flawed assumptions that break when used + with certain applications. These assumptions include that all icons + in a given row will be approximately the same width and that things + are always LTR (left to right). It should use a QGridLayout and + do some semi-intelligent packing of the icons. + +++ Dialog for adding elements to the panel +*** Context menus are primarily used by advanced users, and yet this is + the only way to manage the items on the panel. There used to be a + control panel that allowed turning on or off applets on the main panel + but this is obviously too restrictive and I'd prefer not to see yet + another tab in the kicker control panels. A dialog that shows previews + of the specials buttons and applets and allows one to either drag and + drop or with a button add items to a given panel would make kicker that + much more accessable to more of our users. diff --git a/kicker/applets/Makefile.am b/kicker/applets/Makefile.am new file mode 100644 index 000000000..6079814ce --- /dev/null +++ b/kicker/applets/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = clock systemtray minipager taskbar run launcher naughty lockout menu media trash diff --git a/kicker/applets/clock/Makefile.am b/kicker/applets/clock/Makefile.am new file mode 100644 index 000000000..b87e0d8e7 --- /dev/null +++ b/kicker/applets/clock/Makefile.am @@ -0,0 +1,29 @@ +pic_DATA = lcd.png +picdir = $(kde_datadir)/clockapplet/pics + +INCLUDES = -I$(top_srcdir)/kicker/libkicker -I../../libkicker $(all_includes) + +kde_module_LTLIBRARIES = clock_panelapplet.la + +clock_panelapplet_la_SOURCES = clock.skel clock.cpp datepicker.cpp zone.cpp analog.ui digital.ui fuzzy.ui settings.ui prefs.kcfgc + +METASOURCES = AUTO +noinst_HEADERS = clock.h datepicker.h zone.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = clockapplet.desktop + +EXTRA_DIST = $(lnk_DATA) $(pic_DATA) + +clock_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +clock_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KDEUI) + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/clockapplet clockapplet *.h -lqt -lkdecore -lkdeui -lkfile + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/clockapplet.pot + +KDE_OPTIONS=nofinal + +clock_skel.lo: settings.h diff --git a/kicker/applets/clock/analog.ui b/kicker/applets/clock/analog.ui new file mode 100644 index 000000000..4a20312ec --- /dev/null +++ b/kicker/applets/clock/analog.ui @@ -0,0 +1,344 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AnalogWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>AnalogWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>524</width> + <height>307</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>ButtonGroup2_3_2</cstring> + </property> + <property name="title"> + <string>Display</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_AnalogShowDate</cstring> + </property> + <property name="text"> + <string>Dat&e</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_AnalogShowSeconds</cstring> + </property> + <property name="text"> + <string>Seco&nds</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_AnalogShowDayOfWeek</cstring> + </property> + <property name="text"> + <string>Da&y of week</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_AnalogShowFrame</cstring> + </property> + <property name="text"> + <string>&Frame</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer20</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="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Time</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton" row="2" column="1"> + <property name="name"> + <cstring>kcfg_AnalogBackgroundColor</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_AnalogShadowColor</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>foregroundAnalogLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_AnalogForegroundColor</cstring> + </property> + </widget> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer13</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>backgroundAnalogLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Background color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_AnalogBackgroundColor</cstring> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_AnalogForegroundColor</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>shadowAnalogLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Shadow color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_AnalogShadowColor</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1_3</cstring> + </property> + <property name="text"> + <string>Antialias:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_AnalogAntialias</cstring> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>None</string> + </property> + </item> + <item> + <property name="text"> + <string>Low Quality</string> + </property> + </item> + <item> + <property name="text"> + <string>High Quality</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_AnalogAntialias</cstring> + </property> + <property name="currentItem"> + <number>0</number> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>Spacer18_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>310</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_AnalogLCDStyle</cstring> + </property> + <property name="text"> + <string>&LCD look</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer54</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>50</height> + </size> + </property> + </spacer> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>foregroundAnalogLabel</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>backgroundAnalogLabel</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>shadowAnalogLabel</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AnalogForegroundColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AnalogShadowColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AnalogLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AnalogBackgroundColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>kcfg_AnalogShowDate</tabstop> + <tabstop>kcfg_AnalogShowSeconds</tabstop> + <tabstop>kcfg_AnalogShowFrame</tabstop> + <tabstop>kcfg_AnalogAntialias</tabstop> + <tabstop>kcfg_AnalogLCDStyle</tabstop> + <tabstop>kcfg_AnalogForegroundColor</tabstop> + <tabstop>kcfg_AnalogShadowColor</tabstop> + <tabstop>kcfg_AnalogBackgroundColor</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">kfontrequester.h</include> +</includes> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/clock/clock.cpp b/kicker/applets/clock/clock.cpp new file mode 100644 index 000000000..19e91be5c --- /dev/null +++ b/kicker/applets/clock/clock.cpp @@ -0,0 +1,1871 @@ +/************************************************************ + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <cstdlib> +#include <ctime> +#include <time.h> + +#include <qcheckbox.h> +#include <qcursor.h> +#include <qgroupbox.h> +#include <qimage.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qtooltip.h> +#include <qclipboard.h> +#include <qtabwidget.h> +#include <qwidgetstack.h> +#include <qcombobox.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kcolorbutton.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kprocess.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kstringhandler.h> +#include <kfiledialog.h> +#include <kfontrequester.h> +#include <kglobalsettings.h> +#include <kconfigdialogmanager.h> +#include <kcalendarsystem.h> +#include <kicontheme.h> +#include <kiconloader.h> + +#include <global.h> // libkickermain + +#include "kickerSettings.h" +#include "clock.h" +#include "datepicker.h" +#include "zone.h" +#include "analog.h" +#include "digital.h" +#include "fuzzy.h" +#include "prefs.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("clockapplet"); + KGlobal::locale()->insertCatalogue("timezones"); // For time zone translations + return new ClockApplet(configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, parent, "clockapplet"); + } +} + +// Settings + +KConfigDialogSingle::KConfigDialogSingle(Zone *zone, QWidget *parent, + const char *name, Prefs * prefs, + KDialogBase::DialogType dialogType, + bool modal) : + KConfigDialog(parent, name, prefs, dialogType, + KDialogBase::Default | KDialogBase::Ok | + KDialogBase::Apply | KDialogBase::Cancel, + KDialogBase::Ok, + modal), _prefs(prefs) +{ + // As a temporary mesure until the kicker applet's app name is set to the + // applets name so KDialogBase gets the right info. + setPlainCaption(i18n("Configure - Clock")); + setIcon(SmallIcon("date")); + + settings = new SettingsWidgetImp(prefs, zone, 0, "General"); + connect(settings->kcfg_Type, SIGNAL(activated(int)), SLOT(selectPage(int))); + + settings->kcfg_PlainBackgroundColor->setDefaultColor(KApplication::palette().active().background()); + settings->kcfg_DateBackgroundColor->setDefaultColor(KApplication::palette().active().background()); + + // Digital + digitalPage = new DigitalWidget(0, "DigitalClock"); + settings->widgetStack->addWidget(digitalPage, 1); + digitalPage->kcfg_DigitalBackgroundColor->setDefaultColor(KApplication::palette().active().background()); + + // Analog + analogPage = new AnalogWidget(0, "AnalogClock"); + settings->widgetStack->addWidget(analogPage, 2); + analogPage->kcfg_AnalogBackgroundColor->setDefaultColor(KApplication::palette().active().background()); + + // Fuzzy + fuzzyPage = new FuzzyWidget(0, "FuzzyClock"); + settings->widgetStack->addWidget(fuzzyPage, 3); + fuzzyPage->kcfg_FuzzyBackgroundColor->setDefaultColor(KApplication::palette().active().background()); + + connect(settings->kcfg_PlainShowDate, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(settings->kcfg_PlainShowDayOfWeek, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(digitalPage->kcfg_DigitalShowDate, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(digitalPage->kcfg_DigitalShowDayOfWeek, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(digitalPage->kcfg_DigitalShowDate, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(analogPage->kcfg_AnalogShowDate, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(analogPage->kcfg_AnalogShowDayOfWeek, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(fuzzyPage->kcfg_FuzzyShowDate, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + connect(fuzzyPage->kcfg_FuzzyShowDayOfWeek, SIGNAL(toggled(bool)), + SLOT(dateToggled())); + + addPage(settings, i18n("General"), QString::fromLatin1("package_settings")); +} + +void KConfigDialogSingle::updateSettings() +{ + settings->OkApply(); +} + +void KConfigDialogSingle::updateWidgets() +{ + selectPage( _prefs->type() ); +} + +void KConfigDialogSingle::updateWidgetsDefault() +{ + KConfigSkeletonItem *item = _prefs->findItem("Type"); + item->swapDefault(); + selectPage( _prefs->type() ); + item->swapDefault(); + // This is ugly, but kcfg_Type does not have its correct setting + // at this point in time. + QTimer::singleShot(0, this, SLOT(dateToggled())); +} + +void KConfigDialogSingle::selectPage(int p) +{ + settings->widgetStack->raiseWidget( p ); + dateToggled(); +} + +void KConfigDialogSingle::dateToggled() +{ + bool showDate; + switch( settings->kcfg_Type->currentItem() ) + { + case Prefs::EnumType::Plain: + showDate = settings->kcfg_PlainShowDate->isChecked() || + settings->kcfg_PlainShowDayOfWeek->isChecked(); + break; + case Prefs::EnumType::Digital: + showDate = digitalPage->kcfg_DigitalShowDate->isChecked() || + digitalPage->kcfg_DigitalShowDayOfWeek->isChecked(); + break; + case Prefs::EnumType::Analog: + showDate = analogPage->kcfg_AnalogShowDate->isChecked() || + analogPage->kcfg_AnalogShowDayOfWeek->isChecked(); + break; + case Prefs::EnumType::Fuzzy: + default: + showDate = fuzzyPage->kcfg_FuzzyShowDate->isChecked() || + fuzzyPage->kcfg_FuzzyShowDayOfWeek->isChecked(); + break; + } + settings->dateBox->setEnabled(showDate); +} + +SettingsWidgetImp::SettingsWidgetImp(Prefs *p, Zone *z, QWidget* parent, const char* name, WFlags fl) : + SettingsWidget(parent, name, fl), prefs(p), zone(z) +{ + zone->readZoneList(tzListView); +} + +void SettingsWidgetImp::OkApply() +{ + zone->getSelectedZonelist(tzListView); + zone->writeSettings(); +} + +//************************************************************ + + +ClockWidget::ClockWidget(ClockApplet *applet, Prefs* prefs) + : _applet(applet), _prefs(prefs), _force(false) +{} + + +ClockWidget::~ClockWidget() +{} + + +//************************************************************ + + +PlainClock::PlainClock(ClockApplet *applet, Prefs *prefs, QWidget *parent, const char *name) + : QLabel(parent, name), ClockWidget(applet, prefs) +{ + setWFlags(WNoAutoErase); + setBackgroundOrigin(AncestorOrigin); + loadSettings(); + updateClock(); +} + + +int PlainClock::preferedWidthForHeight(int ) const +{ + QString maxLengthTime = KGlobal::locale()->formatTime( QTime( 23, 59 ), _prefs->plainShowSeconds()); + return fontMetrics().width( maxLengthTime ) + 8; +} + + +int PlainClock::preferedHeightForWidth(int /*w*/) const +{ + return fontMetrics().lineSpacing(); +} + + +void PlainClock::updateClock() +{ + QString newStr = KGlobal::locale()->formatTime(_applet->clockGetTime(), _prefs->plainShowSeconds()); + + if (_force || newStr != _timeStr) { + _timeStr = newStr; + update(); + } +} + +void PlainClock::loadSettings() +{ + setFrameStyle(_prefs->plainShowFrame() ? Panel | Sunken : NoFrame); + setAlignment(AlignVCenter | AlignHCenter | SingleLine); + + setFont(_prefs->plainFont()); +} + +bool PlainClock::showDate() +{ + return _prefs->plainShowDate(); +} + +bool PlainClock::showDayOfWeek() +{ + return _prefs->plainShowDayOfWeek(); +} + +void PlainClock::paintEvent(QPaintEvent *) +{ + QPainter p; + QPixmap buf(size()); + buf.fill(this, 0, 0); + p.begin(&buf); + p.setFont(font()); + p.setPen(paletteForegroundColor()); + drawContents(&p); + drawFrame(&p); + p.end(); + p.begin(this); + p.drawPixmap(0, 0, buf); + p.end(); +} + +void PlainClock::drawContents(QPainter *p) +{ + QRect tr(0, 0, width(), height()); + + if (!KickerSettings::transparent()) + p->drawText(tr, AlignCenter, _timeStr); + else + _applet->shadowEngine()->drawText(*p, tr, AlignCenter, _timeStr, size()); +} + +//************************************************************ + + +DigitalClock::DigitalClock(ClockApplet *applet, Prefs *prefs, QWidget *parent, const char *name) + : QLCDNumber(parent, name), ClockWidget(applet, prefs) +{ + setWFlags(WNoAutoErase); + setBackgroundOrigin(AncestorOrigin); + loadSettings(); + updateClock(); +} + + +DigitalClock::~DigitalClock() +{ + delete _buffer; +} + + +int DigitalClock::preferedWidthForHeight(int h) const +{ + if (h > 29) h = 29; + if (h < 0) h = 0; + return (numDigits()*h*5/11)+2; +} + + +int DigitalClock::preferedHeightForWidth(int w) const +{ + if (w < 0) w = 0; + return((w / numDigits() * 2) + 6); +} + + +void DigitalClock::updateClock() +{ + static bool colon = true; + QString newStr; + QTime t(_applet->clockGetTime()); + + int h = t.hour(); + int m = t.minute(); + int s = t.second(); + + QString format("%02d"); + + QString sep(!colon && _prefs->digitalBlink() ? " " : ":"); + + if (_prefs->digitalShowSeconds()) + format += sep + "%02d"; + + if (KGlobal::locale()->use12Clock()) { + if (h > 12) + h -= 12; + else if( h == 0) + h = 12; + + format.prepend("%2d" + sep); + } else + format.prepend("%02d" + sep); + + + if (_prefs->digitalShowSeconds()) + newStr.sprintf(format.latin1(), h, m, s); + else + newStr.sprintf(format.latin1(), h, m); + + if (_force || newStr != _timeStr) + { + _timeStr = newStr; + setUpdatesEnabled( FALSE ); + display(_timeStr); + setUpdatesEnabled( TRUE ); + update(); + } + + if (_prefs->digitalBlink()) + colon = !colon; +} + +void DigitalClock::loadSettings() +{ + setFrameStyle(_prefs->digitalShowFrame() ? Panel | Sunken : NoFrame); + setMargin( 4 ); + setSegmentStyle(QLCDNumber::Flat); + + if (_prefs->digitalLCDStyle()) + lcdPattern = KIconLoader("clockapplet").loadIcon("lcd", KIcon::User); + + setNumDigits(_prefs->digitalShowSeconds() ? 8:5); + + _buffer = new QPixmap(width(), height()); +} + +void DigitalClock::paintEvent(QPaintEvent*) +{ + QPainter p(_buffer); + + if (_prefs->digitalLCDStyle()) + { + p.drawTiledPixmap(0, 0, width(), height(), lcdPattern); + } + else if (_prefs->digitalBackgroundColor() != + KApplication::palette().active().background()) + { + p.fillRect(0, 0, width(), height(), _prefs->digitalBackgroundColor()); + } + else if (paletteBackgroundPixmap()) + { + QPoint offset = backgroundOffset(); + p.drawTiledPixmap(0, 0, width(), height(), *paletteBackgroundPixmap(), offset.x(), offset.y()); + } + else + { + p.fillRect(0, 0, width(), height(), _prefs->digitalBackgroundColor()); + } + + drawContents(&p); + if (_prefs->digitalShowFrame()) + { + drawFrame(&p); + } + + p.end(); + bitBlt(this, 0, 0, _buffer, 0, 0); +} + + +// yes, the colors for the lcd-lock are hardcoded, +// but other colors would break the lcd-lock anyway +void DigitalClock::drawContents( QPainter * p) +{ + setUpdatesEnabled( FALSE ); + QPalette pal = palette(); + if (_prefs->digitalLCDStyle()) + pal.setColor( QColorGroup::Foreground, QColor(128,128,128)); + else + pal.setColor( QColorGroup::Foreground, _prefs->digitalShadowColor()); + setPalette( pal ); + p->translate( +1, +1 ); + QLCDNumber::drawContents( p ); + if (_prefs->digitalLCDStyle()) + pal.setColor( QColorGroup::Foreground, Qt::black); + else + pal.setColor( QColorGroup::Foreground, _prefs->digitalForegroundColor()); + setPalette( pal ); + p->translate( -2, -2 ); + setUpdatesEnabled( TRUE ); + QLCDNumber::drawContents( p ); + p->translate( +1, +1 ); +} + + +// reallocate buffer pixmap +void DigitalClock::resizeEvent ( QResizeEvent *) +{ + delete _buffer; + _buffer = new QPixmap( width(), height() ); +} + + +bool DigitalClock::showDate() +{ + return _prefs->digitalShowDate(); +} + +bool DigitalClock::showDayOfWeek() +{ + return _prefs->digitalShowDayOfWeek(); +} + + +//************************************************************ + + +AnalogClock::AnalogClock(ClockApplet *applet, Prefs *prefs, QWidget *parent, const char *name) + : QFrame(parent, name), ClockWidget(applet, prefs), _spPx(NULL) +{ + setWFlags(WNoAutoErase); + setBackgroundOrigin(AncestorOrigin); + loadSettings(); +} + + +AnalogClock::~AnalogClock() +{ + delete _spPx; +} + +void AnalogClock::initBackgroundPixmap() +{ + //if no antialiasing, use pixmap as-is + if (_prefs->analogAntialias() == 0) + { + lcdPattern = KIconLoader("clockapplet").loadIcon("lcd",KIcon::User); + _bgScale = 1; + } + else + { + //make a scaled pixmap -- so when image is reduced it'll look "OK". + _bgScale = _prefs->analogAntialias()+1; + QImage bgImage = KIconLoader("clockapplet").loadIcon("lcd", KIcon::User).convertToImage(); + lcdPattern = QPixmap(bgImage.scale(bgImage.width() * _bgScale, + bgImage.height() * _bgScale)); + + } +} + +void AnalogClock::updateClock() +{ + if (!_force) + { + if (!_prefs->analogShowSeconds() && (_time.minute() == _applet->clockGetTime().minute())) + return; + } + + _time = _applet->clockGetTime(); + update(); +} + +void AnalogClock::loadSettings() +{ + if (_prefs->analogLCDStyle()) + { + initBackgroundPixmap(); + } +/* this may prevent flicker, but it also prevents transparency + else + { + setBackgroundMode(NoBackground); + }*/ + + setFrameStyle(_prefs->analogShowFrame() ? Panel | Sunken : NoFrame); + _time = _applet->clockGetTime(); + _spPx = new QPixmap(size().width() * _prefs->analogAntialias()+1, + size().height() * _prefs->analogAntialias()+1); + + update(); +} + +void AnalogClock::paintEvent( QPaintEvent * ) +{ + if ( !isVisible() ) + return; + + int aaFactor = _prefs->analogAntialias()+1; + int spWidth = size().width() * aaFactor; + int spHeight = size().height() * aaFactor; + + if ((spWidth != _spPx->size().width()) || + (spHeight != _spPx->size().height())) + { + delete _spPx; + _spPx = new QPixmap(spWidth, spHeight); + } + + QPainter paint; + paint.begin(_spPx); + + if (_prefs->analogLCDStyle()) + { + if (_bgScale != aaFactor) + { + //check to see if antialiasing has changed -- bg pixmap will need + //to be re-created + initBackgroundPixmap(); + } + + paint.drawTiledPixmap(0, 0, spWidth, spHeight, lcdPattern); + } + else if (_prefs->analogBackgroundColor() != KApplication::palette().active().background()) + { + _spPx->fill(_prefs->analogBackgroundColor()); + } + else if (paletteBackgroundPixmap()) + { + QPixmap bg(width(), height()); + QPainter p(&bg); + QPoint offset = backgroundOffset(); + p.drawTiledPixmap(0, 0, width(), height(), *paletteBackgroundPixmap(), offset.x(), offset.y()); + p.end(); + QImage bgImage = bg.convertToImage().scale(spWidth, spHeight); + paint.drawImage(0, 0, bgImage); + } + else + { + _spPx->fill(_prefs->analogBackgroundColor()); + } + + QPointArray pts; + QPoint cp(spWidth / 2, spHeight / 2); + + int d = KMIN(spWidth,spHeight) - (10 * aaFactor); + + if (_prefs->analogLCDStyle()) + { + paint.setPen( QPen(QColor(100,100,100), aaFactor) ); + paint.setBrush( QColor(100,100,100) ); + } + else + { + paint.setPen( QPen(_prefs->analogShadowColor(), aaFactor) ); + paint.setBrush( _prefs->analogShadowColor() ); + } + + paint.setViewport(2,2,spWidth,spHeight); + + for ( int c=0 ; c < 2 ; c++ ) { + QWMatrix matrix; + matrix.translate( cp.x(), cp.y()); + matrix.scale( d/1000.0F, d/1000.0F ); + + // hour + float h_angle = 30*(_time.hour()%12-3) + _time.minute()/2; + matrix.rotate( h_angle ); + paint.setWorldMatrix( matrix ); + pts.setPoints( 4, -20,0, 0,-20, 300,0, 0,20 ); + paint.drawPolygon( pts ); + matrix.rotate( -h_angle ); + + // minute + float m_angle = (_time.minute()-15)*6; + matrix.rotate( m_angle ); + paint.setWorldMatrix( matrix ); + pts.setPoints( 4, -10,0, 0,-10, 400,0, 0,10 ); + paint.drawPolygon( pts ); + matrix.rotate( -m_angle ); + + if (_prefs->analogShowSeconds()) { // second + float s_angle = (_time.second()-15)*6; + matrix.rotate( s_angle ); + paint.setWorldMatrix( matrix ); + pts.setPoints(4,0,0,0,0,400,0,0,0); + paint.drawPolygon( pts ); + matrix.rotate( -s_angle ); + } + + QWMatrix matrix2; + matrix2.translate( cp.x(), cp.y()); + matrix2.scale( d/1000.0F, d/1000.0F ); + + // quadrante + for ( int i=0 ; i < 12 ; i++ ) { + paint.setWorldMatrix( matrix2 ); + paint.drawLine( 460,0, 500,0 ); // draw hour lines + // paint.drawEllipse( 450, -15, 30, 30 ); + matrix2.rotate( 30 ); + } + + if (_prefs->analogLCDStyle()) { + paint.setPen( QPen(Qt::black, aaFactor) ); + paint.setBrush( Qt::black ); + } else { + paint.setPen( QPen(_prefs->analogForegroundColor(), aaFactor) ); + paint.setBrush( _prefs->analogForegroundColor() ); + } + + paint.setViewport(0,0,spWidth,spHeight); + } + paint.end(); + + QPainter paintFinal; + paintFinal.begin(this); + + if (aaFactor != 1) + { + QImage spImage = _spPx->convertToImage(); + QImage displayImage = spImage.smoothScale(size()); + + paintFinal.drawImage(0, 0, displayImage); + } + else + { + paintFinal.drawPixmap(0, 0, *_spPx); + } + + if (_prefs->analogShowFrame()) + { + drawFrame(&paintFinal); + } +} + + +// the background pixmap disappears during a style change +void AnalogClock::styleChange(QStyle &) +{ + if (_prefs->analogLCDStyle()) + { + initBackgroundPixmap(); + } +} + +bool AnalogClock::showDate() +{ + return _prefs->analogShowDate(); +} + +bool AnalogClock::showDayOfWeek() +{ + return _prefs->analogShowDayOfWeek(); +} + + +//************************************************************ + + +FuzzyClock::FuzzyClock(ClockApplet *applet, Prefs *prefs, QWidget *parent, const char *name) + : QFrame(parent, name), ClockWidget(applet, prefs) +{ + setBackgroundOrigin(AncestorOrigin); + loadSettings(); + hourNames << i18n("hour","one") << i18n("hour","two") + << i18n("hour","three") << i18n("hour","four") << i18n("hour","five") + << i18n("hour","six") << i18n("hour","seven") << i18n("hour","eight") + << i18n("hour","nine") << i18n("hour","ten") << i18n("hour","eleven") + << i18n("hour","twelve"); + + // xgettext:no-c-format + normalFuzzy << i18n("%0 o'clock") // xgettext:no-c-format + << i18n("five past %0") // xgettext:no-c-format + << i18n("ten past %0") // xgettext:no-c-format + << i18n("quarter past %0") // xgettext:no-c-format + << i18n("twenty past %0") // xgettext:no-c-format + << i18n("twenty five past %0") // xgettext:no-c-format + << i18n("half past %0") // xgettext:no-c-format + << i18n("twenty five to %1") // xgettext:no-c-format + << i18n("twenty to %1") // xgettext:no-c-format + << i18n("quarter to %1") // xgettext:no-c-format + << i18n("ten to %1") // xgettext:no-c-format + << i18n("five to %1") // xgettext:no-c-format + << i18n("%1 o'clock"); + + // xgettext:no-c-format + normalFuzzyOne << i18n("one","%0 o'clock") // xgettext:no-c-format + << i18n("one","five past %0") // xgettext:no-c-format + << i18n("one","ten past %0") // xgettext:no-c-format + << i18n("one","quarter past %0") // xgettext:no-c-format + << i18n("one","twenty past %0") // xgettext:no-c-format + << i18n("one","twenty five past %0") // xgettext:no-c-format + << i18n("one","half past %0") // xgettext:no-c-format + << i18n("one","twenty five to %1") // xgettext:no-c-format + << i18n("one","twenty to %1") // xgettext:no-c-format + << i18n("one","quarter to %1") // xgettext:no-c-format + << i18n("one","ten to %1") // xgettext:no-c-format + << i18n("one","five to %1") // xgettext:no-c-format + << i18n("one","%1 o'clock"); + + dayTime << i18n("Night") + << i18n("Early morning") << i18n("Morning") << i18n("Almost noon") + << i18n("Noon") << i18n("Afternoon") << i18n("Evening") + << i18n("Late evening"); + + _time = _applet->clockGetTime(); + alreadyDrawing=false; + update(); +} + +void FuzzyClock::deleteMyself() +{ + if(alreadyDrawing) // try again later + QTimer::singleShot(1000, this, SLOT(deleteMyself())); + else + delete this; +} + + +int FuzzyClock::preferedWidthForHeight(int ) const +{ + QFontMetrics fm(_prefs->fuzzyFont()); + return fm.width(_timeStr) + 8; +} + + +int FuzzyClock::preferedHeightForWidth(int ) const +{ + QFontMetrics fm(_prefs->fuzzyFont()); + return fm.width(_timeStr) + 8; +} + + +void FuzzyClock::updateClock() +{ + if (!_force) + { + if (_time.hour() == _applet->clockGetTime().hour() && + _time.minute() == _applet->clockGetTime().minute()) + return; + } + + _time = _applet->clockGetTime(); + update(); +} + +void FuzzyClock::loadSettings() +{ + setFrameStyle(_prefs->fuzzyShowFrame() ? Panel | Sunken : 0); +} + +void FuzzyClock::drawContents(QPainter *p) +{ + if (!isVisible()) + return; + + if(!_applet) + return; + + alreadyDrawing = true; + QString newTimeStr; + + if (_prefs->fuzzyness() == 1 || _prefs->fuzzyness() == 2) { + int minute = _time.minute(); + int sector = 0; + int realHour = 0; + + if (_prefs->fuzzyness() == 1) { + if (minute > 2) + sector = (minute - 3) / 5 + 1; + } else { + if (minute > 6) + sector = ((minute - 7) / 15 + 1) * 3; + } + + newTimeStr = normalFuzzy[sector]; + int phStart = newTimeStr.find("%"); + if (phStart >= 0) { // protect yourself from translations + int phLength = newTimeStr.find(" ", phStart) - phStart; + + // larrosa: we want the exact length, in case the translation needs it, + // in other case, we would cut off the end of the translation. + if (phLength < 0) phLength = newTimeStr.length() - phStart; + int deltaHour = newTimeStr.mid(phStart + 1, phLength - 1).toInt(); + + if ((_time.hour() + deltaHour) % 12 > 0) + realHour = (_time.hour() + deltaHour) % 12 - 1; + else + realHour = 12 - ((_time.hour() + deltaHour) % 12 + 1); + if (realHour==0) { + newTimeStr = normalFuzzyOne[sector]; + phStart = newTimeStr.find("%"); + // larrosa: Note that length is the same, + // so we only have to update phStart + } + if (phStart >= 0) + newTimeStr.replace(phStart, phLength, hourNames[realHour]); + newTimeStr.replace(0, 1, QString(newTimeStr.at(0).upper())); + } + } else if (_prefs->fuzzyness() == 3) { + newTimeStr = dayTime[_time.hour() / 3]; + } else { + int dow = _applet->clockGetDate().dayOfWeek(); + + if (dow == 1) + newTimeStr = i18n("Start of week"); + else if (dow >= 2 && dow <= 4) + newTimeStr = i18n("Middle of week"); + else if (dow == 5) + newTimeStr = i18n("End of week"); + else + newTimeStr = i18n("Weekend!"); + } + + if (_timeStr != newTimeStr) { + _timeStr = newTimeStr; + _applet->resizeRequest(); + } + + p->setFont(_prefs->fuzzyFont()); + p->setPen(_prefs->fuzzyForegroundColor()); + + QRect tr; + + if (_applet->getOrientation() == Vertical) + { + p->rotate(90); + tr = QRect(4, -2, height() - 8, -(width()) + 2); + } + else + tr = QRect(4, 2, width() - 8, height() - 4); + + if (!KickerSettings::transparent()) + p->drawText(tr, AlignCenter, _timeStr); + else + _applet->shadowEngine()->drawText(*p, tr, AlignCenter, _timeStr, size()); + + alreadyDrawing = false; +} + +bool FuzzyClock::showDate() +{ + return _prefs->fuzzyShowDate(); +} + +bool FuzzyClock::showDayOfWeek() +{ + return _prefs->fuzzyShowDayOfWeek(); +} + + +//************************************************************ + + +ClockApplet::ClockApplet(const QString& configFile, Type t, int actions, + QWidget *parent, const char *name) + : KPanelApplet(configFile, t, actions, parent, name), + _calendar(0), + _disableCalendar(false), + _clock(0), + _timer(new QTimer(this)), + m_layoutTimer(new QTimer(this)), + m_layoutDelay(0), + m_followBackgroundSetting(true), + m_dateFollowBackgroundSetting(true), + TZoffset(0), + _prefs(new Prefs(sharedConfig())), + zone(new Zone(config())), + menu(0), + m_tooltip(this), + m_shadowEngine(0) +{ + DCOPObject::setObjId("ClockApplet"); + _prefs->readConfig(); + configFileName = configFile.latin1(); + setBackgroundOrigin(AncestorOrigin); + + _dayOfWeek = new QLabel(this); + _dayOfWeek->setAlignment(AlignVCenter | AlignHCenter | WordBreak); + _dayOfWeek->setBackgroundOrigin(AncestorOrigin); + _dayOfWeek->installEventFilter(this); // catch mouse clicks + + _date = new QLabel(this); + _date->setAlignment(AlignVCenter | AlignHCenter | WordBreak); + _date->setBackgroundOrigin(AncestorOrigin); + _date->installEventFilter(this); // catch mouse clicks + + connect(m_layoutTimer, SIGNAL(timeout()), this, SLOT(fixupLayout())); + connect(_timer, SIGNAL(timeout()), SLOT(slotUpdate())); + connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(globalPaletteChange())); + + reconfigure(); // initialize clock widget + slotUpdate(); + + if (kapp->authorizeKAction("kicker_rmb")) + { + menu = new KPopupMenu(); + connect(menu, SIGNAL(aboutToShow()), SLOT(aboutToShowContextMenu())); + connect(menu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + setCustomMenu(menu); + } + + installEventFilter(KickerTip::the()); +} + + +ClockApplet::~ClockApplet() +{ + delete m_shadowEngine; + //reverse for the moment + KGlobal::locale()->removeCatalogue("clockapplet"); + KGlobal::locale()->removeCatalogue("timezones"); // For time zone translations + + if (_calendar) + { + // we have to take care of the calendar closing first before deleting + // the prefs + _calendar->close(); + } + + zone->writeSettings(); + + delete _prefs; _prefs = 0; + delete zone; zone = 0; + delete menu; menu = 0; + config()->sync(); +} + + +KTextShadowEngine *ClockApplet::shadowEngine() +{ + if (!m_shadowEngine) + m_shadowEngine = new KTextShadowEngine(); + + return m_shadowEngine; +} + + +int ClockApplet::widthForHeight(int h) const +{ + if (orientation() == Qt::Vertical) + { + return width(); + } + + int shareDateHeight = 0, shareDayOfWeekHeight = 0; + bool dateToSide = (h < 32); + bool mustShowDate = showDate || (zone->zoneIndex() != 0); + if (mustShowDate) + { + _date->setAlignment(AlignVCenter | AlignHCenter); + if (!dateToSide) + { + shareDateHeight = _date->sizeHint().height(); + } + } + if (showDayOfWeek) + { + _dayOfWeek->setAlignment(AlignVCenter | AlignHCenter); + if (!dateToSide) + { + shareDayOfWeekHeight = _dayOfWeek->sizeHint().height(); + } + } + + int clockWidth = _clock->preferedWidthForHeight(KMAX(0, h - shareDateHeight - shareDayOfWeekHeight)); + int w = clockWidth; + if (!mustShowDate && !showDayOfWeek) + { + // resize the date widgets in case the are to the left of the clock + _clock->widget()->setFixedSize(w, h); + _clock->widget()->move(0,0); + _dayOfWeek->move(clockWidth + 4, 0); + _date->move(clockWidth + 4, 0); + } + else + { + int dateWidth = mustShowDate ? _date->sizeHint().width() + 4 : 0; + int dayOfWeekWidth = showDayOfWeek ? _dayOfWeek->sizeHint().width() + 4 : 0; + + if (dateToSide) + { + w += dateWidth + dayOfWeekWidth; + bool dateFirst = false; + + if (mustShowDate) + { + // if the date format STARTS with a year, assume it's in descending + // order and should therefore PRECEED the date. + QString dateFormat = KGlobal::locale()->dateFormatShort(); + dateFirst = dateFormat.at(1) == 'y' || dateFormat.at(1) == 'Y'; + } + + if (dateFirst) + { + _date->setFixedSize(dateWidth, h); + _date->move(0, 0); + + if (showDayOfWeek) + { + _dayOfWeek->setFixedSize(dayOfWeekWidth, h); + _dayOfWeek->move(dateWidth, 0); + } + + _clock->widget()->setFixedSize(clockWidth, h); + _clock->widget()->move(dateWidth + dayOfWeekWidth, 0); + } + else + { + _clock->widget()->setFixedSize(clockWidth, h); + _clock->widget()->move(0,0); + + if (showDayOfWeek) + { + _dayOfWeek->setFixedSize(dayOfWeekWidth, h); + _dayOfWeek->move(clockWidth, 0); + } + + if (mustShowDate) + { + _date->setFixedSize(dateWidth, h); + _date->move(clockWidth + dayOfWeekWidth, 0); + } + } + } + else + { + w = KMAX(KMAX(w, dateWidth), dayOfWeekWidth); + + _clock->widget()->setFixedSize(w, h - shareDateHeight - shareDayOfWeekHeight); + _clock->widget()->setMinimumSize(w, h - shareDateHeight - shareDayOfWeekHeight); + _clock->widget()->move(0, 0); + if (showDayOfWeek) + { + _dayOfWeek->setFixedSize(w, _dayOfWeek->sizeHint().height()); + _dayOfWeek->move(0, _clock->widget()->height()); + } + + if (mustShowDate) + { + _date->setFixedSize(w, _date->sizeHint().height()); + _date->move(0, _clock->widget()->height() + shareDayOfWeekHeight); + } + } + } + + return w; +} + +int ClockApplet::heightForWidth(int w) const +{ + if (orientation() == Qt::Horizontal) + { + return height(); + } + + int clockHeight = _clock->preferedHeightForWidth(w); + bool mustShowDate = showDate || (zone->zoneIndex() != 0); + + _clock->widget()->setFixedSize(w, clockHeight); + + // add 4 pixels in height for each of date+dayOfWeek, if visible + if (showDayOfWeek) + { + if (_dayOfWeek->minimumSizeHint().width() > w) + { + _dayOfWeek->setAlignment(AlignVCenter | WordBreak); + } + else + { + _dayOfWeek->setAlignment(AlignVCenter | AlignHCenter | WordBreak); + } + + _dayOfWeek->setFixedSize(w, _dayOfWeek->minimumSizeHint().height()); + _dayOfWeek->move(0, clockHeight); + + clockHeight += _dayOfWeek->height(); + } + + if (mustShowDate) + { + // yes, the const_cast is ugly, but this is to ensure that we + // get a proper date label in the case that we munged it for + // display on panel that is too narrow and then they made it wider + const_cast<ClockApplet*>(this)->updateDateLabel(false); + + if (_date->minimumSizeHint().width() > w) + { + QString dateStr = _date->text(); + // if we're too wide to fit, replace the first non-digit from the end with a space + int p = dateStr.findRev(QRegExp("[^0-9]")); + if (p > 0) + { + _date->setText(dateStr.insert(p, '\n')); + } + } + + if (_date->minimumSizeHint().width() > w) + { + _date->setAlignment(AlignVCenter | WordBreak); + } + else + { + _date->setAlignment(AlignVCenter | AlignHCenter | WordBreak); + } + _date->setFixedSize(w, _date->heightForWidth(w)); + _date->move(0, clockHeight); + + clockHeight += _date->height(); + } + + return clockHeight; +} + +void ClockApplet::preferences() +{ + preferences(false); +} + +void ClockApplet::preferences(bool timezone) +{ + KConfigDialogSingle *dialog = dynamic_cast<KConfigDialogSingle*>(KConfigDialog::exists(configFileName)); + + if (!dialog) + { + dialog = new KConfigDialogSingle(zone, this, configFileName, _prefs, KDialogBase::Swallow); + connect(dialog, SIGNAL(settingsChanged()), this, SLOT(slotReconfigure())); + } + + if (timezone) + { + dialog->settings->tabs->setCurrentPage(1); + } + + dialog->show(); +} + +void ClockApplet::updateFollowBackground() +{ + QColor globalBgroundColor = KApplication::palette().active().background(); + QColor bgColor; + + switch (_prefs->type()) + { + case Prefs::EnumType::Plain: + bgColor = _prefs->plainBackgroundColor(); + break; + case Prefs::EnumType::Analog: + bgColor = _prefs->analogBackgroundColor(); + break; + case Prefs::EnumType::Fuzzy: + bgColor = _prefs->fuzzyBackgroundColor(); + break; + case Prefs::EnumType::Digital: + default: + bgColor = _prefs->digitalBackgroundColor(); + break; + } + + m_followBackgroundSetting = (bgColor == globalBgroundColor); + + bgColor = _prefs->dateBackgroundColor(); + m_dateFollowBackgroundSetting = (bgColor == globalBgroundColor); +} + +// DCOP interface +void ClockApplet::reconfigure() +{ + _timer->stop(); + + // ugly workaround for FuzzyClock: sometimes FuzzyClock + // hasn't finished drawing when getting deleted, so we + // ask FuzzyClock to delete itself appropriately + if (_clock && _clock->widget()->inherits("FuzzyClock")) + { + FuzzyClock* f = static_cast<FuzzyClock*>(_clock); + f->deleteMyself(); + } + else + { + delete _clock; + } + + int shortInterval = 500; + int updateInterval = 0; + + switch (_prefs->type()) + { + case Prefs::EnumType::Plain: + _clock = new PlainClock(this, _prefs, this); + if (_prefs->plainShowSeconds()) + updateInterval = shortInterval; + break; + case Prefs::EnumType::Analog: + _clock = new AnalogClock(this, _prefs, this); + if (_prefs->analogShowSeconds()) + updateInterval = shortInterval; + break; + case Prefs::EnumType::Fuzzy: + _clock = new FuzzyClock(this, _prefs, this); + break; + case Prefs::EnumType::Digital: + default: + _clock = new DigitalClock(this, _prefs, this); + if (_prefs->digitalShowSeconds() || _prefs->digitalBlink()) + updateInterval = shortInterval; + break; + } + + m_updateOnTheMinute = updateInterval != shortInterval; + if (m_updateOnTheMinute) + { + connect(_timer, SIGNAL(timeout()), this, SLOT(setTimerTo60())); + updateInterval = ((60 - clockGetTime().second()) * 1000) + 500; + } + else + { + // in case we reconfigure to show seconds but setTimerTo60 is going to be called + // we need to make sure to disconnect this so we don't end up updating only once + // a minute ;) + disconnect(_timer, SIGNAL(timeout()), this, SLOT(setTimerTo60())); + } + + _timer->start(updateInterval); + + // See if the clock wants to show the date. + showDate = _clock->showDate(); + if (showDate) + { + TZoffset = zone->calc_TZ_offset(zone->zone(), true); + updateDateLabel(); + } + + updateFollowBackground(); + setBackground(); + + // FIXME: this means you can't have a transparent clock but a non-transparent + // date or day =/ + + _clock->widget()->installEventFilter(this); // catch mouse clicks + _clock->widget()->show(); + + _clock->forceUpdate(); /* force repaint */ + + if (showDayOfWeek) + { + _dayOfWeek->show(); + } + else + { + _dayOfWeek->hide(); + } + + if (showDate || (zone->zoneIndex() != 0)) + { + _date->show(); + } + else + { + _date->hide(); + } + + emit(updateLayout()); + + showZone(zone->zoneIndex()); +} + +void ClockApplet::setTimerTo60() +{ +// kdDebug() << "setTimerTo60" << endl; + disconnect(_timer, SIGNAL(timeout()), this, SLOT(setTimerTo60())); + _timer->changeInterval(60000); +} + +void ClockApplet::setBackground() +{ + QColor globalBgroundColor = KApplication::palette().active().background(); + QColor fgColor, bgColor; + + if (!_clock) + return; + + switch (_prefs->type()) + { + case Prefs::EnumType::Plain: + bgColor = _prefs->plainBackgroundColor(); + fgColor = _prefs->plainForegroundColor(); + break; + case Prefs::EnumType::Analog: + bgColor = _prefs->analogBackgroundColor(); + fgColor = _prefs->analogForegroundColor(); + break; + case Prefs::EnumType::Fuzzy: + bgColor = _prefs->fuzzyBackgroundColor(); + fgColor = _prefs->fuzzyForegroundColor(); + break; + case Prefs::EnumType::Digital: + default: + bgColor = _prefs->digitalBackgroundColor(); + fgColor = _prefs->digitalForegroundColor(); + break; + } + + if (!m_followBackgroundSetting) + _clock->widget()->setPaletteBackgroundColor(bgColor); + else + _clock->widget()->unsetPalette(); + _clock->widget()->setPaletteForegroundColor(fgColor); + + bgColor = _prefs->dateBackgroundColor(); + + // See if the clock wants to show the day of week. + // use same font/color as for date + showDayOfWeek = _clock->showDayOfWeek(); + if (showDayOfWeek) + { + _dayOfWeek->setFont(_prefs->dateFont()); + + if (!m_dateFollowBackgroundSetting) + _dayOfWeek->setBackgroundColor(bgColor); + else + _dayOfWeek->unsetPalette(); + _dayOfWeek->setPaletteForegroundColor(_prefs->dateForegroundColor()); + } + + // See if the clock wants to show the date. + showDate = _clock->showDate(); + _date->setFont(_prefs->dateFont()); + + if (!m_dateFollowBackgroundSetting) + _date->setPaletteBackgroundColor(bgColor); + else + _date->unsetPalette(); + _date->setPaletteForegroundColor(_prefs->dateForegroundColor()); +} + +void ClockApplet::globalPaletteChange() +{ + if (!m_dateFollowBackgroundSetting && !m_followBackgroundSetting) + return; + + QColor globalBgroundColor = KApplication::palette().active().background(); + + if (m_dateFollowBackgroundSetting) + _prefs->setDateBackgroundColor(globalBgroundColor); + + if (m_followBackgroundSetting) + { + // we need to makes sure we have the background color synced! + // otherwise when we switch color schemes again or restart kicker + // it might come back non-transparent + switch (_prefs->type()) + { + case Prefs::EnumType::Plain: + _prefs->setPlainBackgroundColor(globalBgroundColor); + break; + case Prefs::EnumType::Analog: + _prefs->setAnalogBackgroundColor(globalBgroundColor); + break; + case Prefs::EnumType::Fuzzy: + _prefs->setFuzzyBackgroundColor(globalBgroundColor); + break; + case Prefs::EnumType::Digital: + default: + _prefs->setDigitalBackgroundColor(globalBgroundColor); + break; + } + } + + _prefs->writeConfig(); +} + +void ClockApplet::slotUpdate() +{ + if (_lastDate != clockGetDate()) + { + updateDateLabel(); + } + + if (m_updateOnTheMinute) + { + // catch drift so we're never more than a few s out + int seconds = clockGetTime().second(); +// kdDebug() << "checking for drift: " << seconds << endl; + + if (seconds > 2) + { + connect(_timer, SIGNAL(timeout()), this, SLOT(setTimerTo60())); + _timer->changeInterval(((60 - seconds) * 1000) + 500); + } + } + _clock->updateClock(); + KickerTip::Client::updateKickerTip(); +} + +void ClockApplet::slotCalendarDeleted() +{ + _calendar = 0L; + // don't reopen the calendar immediately ... + _disableCalendar = true; + QTimer::singleShot(100, this, SLOT(slotEnableCalendar())); + + // we are free to show a tip know :) + installEventFilter(KickerTip::the()); +} + + +void ClockApplet::slotEnableCalendar() +{ + _disableCalendar = false; +} + +void ClockApplet::toggleCalendar() +{ + if (_calendar && !_disableCalendar) + { + // calls slotCalendarDeleted which does the cleanup for us + _calendar->close(); + return; + } + + if (_calendar || _disableCalendar) + { + return; + } + + KickerTip::the()->untipFor(this); + removeEventFilter(KickerTip::the()); + + _calendar = new DatePicker(this, _lastDate, _prefs); + connect(_calendar, SIGNAL(destroyed()), SLOT(slotCalendarDeleted())); + + QSize size = _prefs->calendarSize(); + + if (size != QSize()) + { + _calendar->resize(size); + } + else + { + _calendar->adjustSize(); + } + + // make calendar fully visible + QPoint popupAt = KickerLib::popupPosition(popupDirection(), + _calendar, + this); + _calendar->move(popupAt); + _calendar->show(); + _calendar->setFocus(); +} + + +void ClockApplet::openContextMenu() +{ + if (!menu || !kapp->authorizeKAction("kicker_rmb")) + return; + + menu->exec( QCursor::pos() ); +} + +void ClockApplet::contextMenuActivated(int result) +{ + if ((result >= 0) && (result < 100)) + { + _prefs->setType(result); + _prefs->writeConfig(); + reconfigure(); + return; + }; + + if ((result >= 500) && (result < 600)) + { + showZone(result-500); + zone->writeSettings(); + return; + }; + + KProcess proc; + switch (result) + { + case 102: + preferences(); + break; + case 103: + proc << locate("exe", "kdesu"); + proc << "--nonewdcop"; + proc << QString("%1 kde-clock.desktop --lang %2") + .arg(locate("exe", "kcmshell")) + .arg(KGlobal::locale()->language()); + proc.start(KProcess::DontCare); + break; + case 104: + proc << locate("exe", "kcmshell"); + proc << "kde-language.desktop"; + proc.start(KProcess::DontCare); + break; + case 110: + preferences(true); + break; + } /* switch() */ +} + +void ClockApplet::aboutToShowContextMenu() +{ + bool bImmutable = config()->isImmutable(); + + menu->clear(); + menu->insertTitle( SmallIcon( "clock" ), i18n( "Clock" ) ); + + KLocale *loc = KGlobal::locale(); + QDateTime dt = QDateTime::currentDateTime(); + dt = dt.addSecs(TZoffset); + + KPopupMenu *copyMenu = new KPopupMenu( menu ); + copyMenu->insertItem(loc->formatDateTime(dt), 201); + copyMenu->insertItem(loc->formatDate(dt.date()), 202); + copyMenu->insertItem(loc->formatDate(dt.date(), true), 203); + copyMenu->insertItem(loc->formatTime(dt.time()), 204); + copyMenu->insertItem(loc->formatTime(dt.time(), true), 205); + copyMenu->insertItem(dt.date().toString(), 206); + copyMenu->insertItem(dt.time().toString(), 207); + copyMenu->insertItem(dt.toString(), 208); + copyMenu->insertItem(dt.toString("yyyy-MM-dd hh:mm:ss"), 209); + connect( copyMenu, SIGNAL( activated(int) ), this, SLOT( slotCopyMenuActivated(int) ) ); + + if (!bImmutable) + { + KPopupMenu *zoneMenu = new KPopupMenu( menu ); + connect(zoneMenu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + for (int i = 0; i <= zone->remoteZoneCount(); i++) + { + if (i == 0) + { + zoneMenu->insertItem(i18n("Local Timezone"), 500 + i); + } + else + { + zoneMenu->insertItem(i18n(zone->zone(i).utf8()).replace("_", " "), 500 + i); + } + } + zoneMenu->setItemChecked(500 + zone->zoneIndex(),true); + zoneMenu->insertSeparator(); + zoneMenu->insertItem(SmallIcon("configure"), i18n("&Configure Timezones..."), 110); + + KPopupMenu *type_menu = new KPopupMenu(menu); + connect(type_menu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + type_menu->insertItem(i18n("&Plain"), Prefs::EnumType::Plain, 1); + type_menu->insertItem(i18n("&Digital"), Prefs::EnumType::Digital, 2); + type_menu->insertItem(i18n("&Analog"), Prefs::EnumType::Analog, 3); + type_menu->insertItem(i18n("&Fuzzy"), Prefs::EnumType::Fuzzy, 4); + type_menu->setItemChecked(_prefs->type(),true); + + menu->insertItem(i18n("&Type"), type_menu, 101, 1); + menu->insertItem(i18n("Show Time&zone"), zoneMenu, 110, 2); + if (kapp->authorize("user/root")) + { + menu->insertItem(SmallIcon("date"), i18n("&Adjust Date && Time..."), 103, 4); + } + menu->insertItem(SmallIcon("kcontrol"), i18n("Date && Time &Format..."), 104, 5); + } + + menu->insertItem(SmallIcon("editcopy"), i18n("C&opy to Clipboard"), copyMenu, 105, 6); + if (!bImmutable) + { + menu->insertSeparator(7); + menu->insertItem(SmallIcon("configure"), i18n("&Configure Clock..."), 102, 8); + } +} + + +void ClockApplet::slotCopyMenuActivated( int id ) +{ + QPopupMenu *m = (QPopupMenu *) sender(); + QString s = m->text(id); + QApplication::clipboard()->setText(s); +} + +QTime ClockApplet::clockGetTime() +{ + return QTime::currentTime().addSecs(TZoffset); +} + +QDate ClockApplet::clockGetDate() +{ + return QDateTime::currentDateTime().addSecs(TZoffset).date(); +} + +void ClockApplet::showZone(int z) +{ + zone->setZone(z); + TZoffset = zone->calc_TZ_offset( zone->zone() ); + updateDateLabel(); + _clock->forceUpdate(); /* force repaint */ +} + +void ClockApplet::nextZone() +{ + zone->nextZone(); + showZone(zone->zoneIndex()); +} + +void ClockApplet::prevZone() +{ + zone->prevZone(); + showZone(zone->zoneIndex()); +} + +void ClockApplet::mousePressEvent(QMouseEvent *ev) +{ + switch (ev->button()) + { + case QMouseEvent::LeftButton: + toggleCalendar(); + break; + case QMouseEvent::RightButton: + openContextMenu(); + break; + case QMouseEvent::MidButton: + nextZone(); + QToolTip::remove(_clock->widget()); + break; + default: + break; + } +} + +void ClockApplet::wheelEvent(QWheelEvent* e) +{ + if (e->delta() < 0) + { + prevZone(); + } + else + { + nextZone(); + } + + QToolTip::remove(_clock->widget()); + KickerTip::Client::updateKickerTip(); +} + +// catch the mouse clicks of our child widgets +bool ClockApplet::eventFilter( QObject *o, QEvent *e ) +{ + if (( o == _clock->widget() || o == _date || o == _dayOfWeek) && + e->type() == QEvent::MouseButtonPress ) + { + mousePressEvent(static_cast<QMouseEvent*>(e) ); + return true; + } + + return KPanelApplet::eventFilter(o, e); +} + +void ClockApplet::positionChange(Position p) +{ + KPanelApplet::positionChange(p); + reconfigure(); +} + +void ClockApplet::updateDateLabel(bool reLayout) +{ + _lastDate = clockGetDate(); + _dayOfWeek->setText(KGlobal::locale()->calendar()->weekDayName(_lastDate)); + + if (zone->zoneIndex() != 0) + { + QString zone_s = i18n(zone->zone().utf8()); + _date->setText(zone_s.mid(zone_s.find('/') + 1).replace("_", " ")); + _date->setShown(true); + } + else + { + QString dateStr = KGlobal::locale()->formatDate(_lastDate, true); + _date->setText(dateStr); + _date->setShown(showDate); + } + + if (reLayout) + { + if (_calendar && _lastDate != _calendar->date()) + { + _calendar->setDate(_lastDate); + } + + m_layoutTimer->stop(); + m_layoutTimer->start(m_layoutDelay, true); + } +} + +void ClockApplet::updateKickerTip(KickerTip::Data& data) +{ + int zoneCount = zone->remoteZoneCount(); + + QString activeZone = zone->zone(); + if (zoneCount == 0) + { + QString _time = KGlobal::locale()->formatTime(clockGetTime(), + _prefs->plainShowSeconds()); + QString _date = KGlobal::locale()->formatDate(clockGetDate(), false); + data.message = _time; + data.subtext = _date; + + if (!activeZone.isEmpty()) + { + activeZone = i18n(activeZone.utf8()); + data.subtext.append("<br>").append(activeZone.mid(activeZone.find('/') + 1).replace("_", " ")); + } + } + else + { + int activeIndex = zone->zoneIndex(); + + for (int i = 0; i <= zone->remoteZoneCount(); i++) + { + QString m_zone = zone->zone(i); + TZoffset = zone->calc_TZ_offset(m_zone); + + if (!m_zone.isEmpty()) + { + m_zone = i18n(m_zone.utf8()); // ensure it gets translated + } + + QString _time = KGlobal::locale()->formatTime(clockGetTime(), + _prefs->plainShowSeconds()); + QString _date = KGlobal::locale()->formatDate(clockGetDate(), false); + + if (activeIndex == i) + { + data.message = m_zone.mid(m_zone.find('/') + 1).replace("_", " "); + data.message += " " + _time + "<br>" + _date; + } + else + { + if (i == 0) + { + data.subtext += "<b>" + i18n("Local Timezone") + "</b>"; + } + else + { + data.subtext += "<b>" + m_zone.mid(m_zone.find('/') + 1).replace("_", " ") + "</b>"; + } + data.subtext += " " + _time + ", " + _date + "<br>"; + } + } + + TZoffset = zone->calc_TZ_offset(activeZone); + } + + data.icon = DesktopIcon("date", KIcon::SizeMedium); + data.direction = popupDirection(); + data.duration = 4000; +} + +void ClockApplet::fixupLayout() +{ + m_layoutDelay = 0; + + // ensure we have the right widget line up in horizontal mode + // when we are showing date beside the clock + // this fixes problems triggered by having the date first + // because of the date format (e.g. YY/MM/DD) and then hiding + // the date + if (orientation() == Qt::Horizontal && height() < 32) + { + bool mustShowDate = showDate || (zone->zoneIndex() != 0); + + if (!mustShowDate && !showDayOfWeek) + { + _clock->widget()->move(0,0); + } + + int dayWidth = 0; + if (!showDayOfWeek) + { + _dayOfWeek->move(_clock->widget()->width() + 4, 0); + } + else + { + dayWidth = _dayOfWeek->width(); + } + + if (!showDate) + { + _date->move(_clock->widget()->width() + dayWidth + 4, 0); + } + } + + emit updateLayout(); +} + +int ClockApplet::type() +{ + return _prefs->type(); +} + +ClockAppletToolTip::ClockAppletToolTip( ClockApplet* clock ) + : QToolTip( clock ), + m_clock( clock ) +{ +} + +void ClockAppletToolTip::maybeTip( const QPoint & /*point*/ ) +{ + QString tipText; + if ( (m_clock->type() == Prefs::EnumType::Fuzzy) || + (m_clock->type() == Prefs::EnumType::Analog) ) + { + // show full time (incl. hour) as tooltip for Fuzzy clock + tipText = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime().addSecs(m_clock->TZoffset)); + } + else + { + tipText = KGlobal::locale()->formatDate(m_clock->clockGetDate()); + } + + if (m_clock->timezones() && m_clock->timezones()->zoneIndex() > 0) + { + tipText += "\n" + i18n("Showing time for %1").arg(i18n(m_clock->timezones()->zone().utf8()), false); + } + + tip(m_clock->geometry(), tipText); +} + +//************************************************************ + +#include "clock.moc" diff --git a/kicker/applets/clock/clock.h b/kicker/applets/clock/clock.h new file mode 100644 index 000000000..efa67be46 --- /dev/null +++ b/kicker/applets/clock/clock.h @@ -0,0 +1,348 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __CLOCK_H +#define __CLOCK_H + +#include <qlcdnumber.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qguardedptr.h> +#include <qdatetime.h> +#include <qvbox.h> +#include <qstringlist.h> +#include <qtooltip.h> +#include <qevent.h> + +#include <dcopobject.h> +#include <kpanelapplet.h> +#include <kdirwatch.h> +#include <kconfigdialog.h> + +#include <kickertip.h> +#include "settings.h" +#include "kshadowengine.h" + +class QTimer; +class QBoxLayout; +class DatePicker; +class QPixmap; +class Zone; +class KPopupMenu; +class Prefs; +class ClockApplet; + +namespace KIO +{ + class Job; +} + +class DigitalWidget; +class AnalogWidget; +class FuzzyWidget; +class ClockApplet; +class KConfigDialogManager; +class SettingsWidgetImp; + +class SettingsWidgetImp : public SettingsWidget +{ + Q_OBJECT + + public: + SettingsWidgetImp(Prefs *p=0, + Zone *z=0, + QWidget* parent=0, + const char* name=0, + WFlags fl=0); + public slots: + void OkApply(); + + private: + Prefs *prefs; + Zone *zone; +}; + +class KConfigDialogSingle : public KConfigDialog +{ + Q_OBJECT + + public: + KConfigDialogSingle(Zone *zone, + QWidget *parent=0, + const char *name=0, + Prefs *prefs=0, + KDialogBase::DialogType dialogType = KDialogBase::IconList, + bool modal=false); + + SettingsWidgetImp* settings; + + void updateSettings(); + void updateWidgets(); + void updateWidgetsDefault(); + + protected slots: + void selectPage(int p); + void dateToggled(); + + private: + DigitalWidget *digitalPage; + AnalogWidget *analogPage; + FuzzyWidget *fuzzyPage; + Prefs *_prefs; +}; + +/** + * Base class for all clock types + */ +class ClockWidget +{ + public: + ClockWidget(ClockApplet *applet, Prefs *prefs); + virtual ~ClockWidget(); + + virtual QWidget* widget()=0; + virtual int preferedWidthForHeight(int h) const =0; + virtual int preferedHeightForWidth(int w) const =0; + virtual void updateClock()=0; + virtual void forceUpdate() { _force = true; updateClock(); } + virtual void loadSettings()=0; + virtual bool showDate()=0; + virtual bool showDayOfWeek()=0; + + protected: + ClockApplet *_applet; + Prefs *_prefs; + QTime _time; + bool _force; +}; + + +class PlainClock : public QLabel, public ClockWidget +{ + Q_OBJECT + + public: + PlainClock(ClockApplet *applet, Prefs *prefs, QWidget *parent=0, const char *name=0); + + QWidget* widget() { return this; } + int preferedWidthForHeight(int h) const; + int preferedHeightForWidth(int w) const; + void updateClock(); + void loadSettings(); + bool showDate(); + bool showDayOfWeek(); + + protected: + void paintEvent(QPaintEvent *e); + void drawContents(QPainter *p); + + QString _timeStr; +}; + + +class DigitalClock : public QLCDNumber, public ClockWidget +{ + Q_OBJECT + + public: + DigitalClock(ClockApplet *applet, Prefs *prefs, QWidget *parent=0, const char *name=0); + ~DigitalClock(); + + QWidget* widget() { return this; } + int preferedWidthForHeight(int h) const; + int preferedHeightForWidth(int w) const; + void updateClock(); + void loadSettings(); + bool showDate(); + bool showDayOfWeek(); + + protected: + void paintEvent( QPaintEvent*); + void drawContents( QPainter * p); + void resizeEvent ( QResizeEvent *ev); + + QPixmap *_buffer; + QString _timeStr; + QPixmap lcdPattern; +}; + + +class AnalogClock : public QFrame, public ClockWidget +{ + Q_OBJECT + + public: + AnalogClock(ClockApplet *applet, Prefs *prefs, QWidget *parent=0, const char *name=0); + ~AnalogClock(); + + QWidget* widget() { return this; } + int preferedWidthForHeight(int h) const { return h; } + int preferedHeightForWidth(int w) const { return w; } + void updateClock(); + void loadSettings(); + bool showDate(); + bool showDayOfWeek(); + + protected: + virtual void paintEvent(QPaintEvent *); + void styleChange(QStyle&); + void initBackgroundPixmap(); + + QPixmap *_spPx; + QPixmap lcdPattern; + int _bgScale; +}; + + +class FuzzyClock : public QFrame, public ClockWidget +{ + Q_OBJECT + + public: + FuzzyClock(ClockApplet *applet, Prefs* prefs, QWidget *parent=0, const char *name=0); + + QWidget* widget() { return this; } + int preferedWidthForHeight(int h) const; + int preferedHeightForWidth(int w) const; + void updateClock(); + void loadSettings(); + bool showDate(); + bool showDayOfWeek(); + + public slots: + void deleteMyself(); + + protected: + virtual void drawContents(QPainter *p); + + QStringList hourNames; + QStringList normalFuzzy; + QStringList normalFuzzyOne; + QStringList dayTime; + + QString _timeStr; + + private: + bool alreadyDrawing; +}; + +class ClockAppletToolTip : public QToolTip +{ + public: + ClockAppletToolTip( ClockApplet* clock ); + + protected: + virtual void maybeTip( const QPoint & ); + + private: + ClockApplet *m_clock; +}; + +class ClockApplet : public KPanelApplet, public KickerTip::Client, public DCOPObject +{ + Q_OBJECT + K_DCOP + + friend class ClockAppletToolTip; + + public: + ClockApplet(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~ClockApplet(); + + int widthForHeight(int h) const; + int heightForWidth(int w) const; + void preferences(); + void preferences(bool timezone); + int type(); + Orientation getOrientation() { return orientation(); } + void resizeRequest() { emit(updateLayout()); } + const Zone* timezones() { return zone; } + + QTime clockGetTime(); + QDate clockGetDate(); + + virtual void updateKickerTip(KickerTip::Data&); + + KTextShadowEngine *shadowEngine(); + + k_dcop: + void reconfigure(); + + protected slots: + void slotReconfigure() { reconfigure(); } + void slotUpdate(); + void slotCalendarDeleted(); + void slotEnableCalendar(); + void slotCopyMenuActivated( int id ); + void contextMenuActivated(int result); + void aboutToShowContextMenu(); + void fixupLayout(); + void globalPaletteChange(); + void setTimerTo60(); + + protected: + void toggleCalendar(); + void openContextMenu(); + void updateDateLabel(bool reLayout = true); + void showZone(int z); + void nextZone(); + void prevZone(); + void updateFollowBackground(); + + void paletteChange(const QPalette &) { setBackground(); } + void setBackground(); + void mousePressEvent(QMouseEvent *ev); + void wheelEvent(QWheelEvent* e); + bool eventFilter(QObject *, QEvent *); + + virtual void positionChange(Position p); + + QCString configFileName; + DatePicker *_calendar; + bool _disableCalendar; + ClockWidget *_clock; + QLabel *_date; + QLabel *_dayOfWeek; + QDate _lastDate; + QTimer *_timer; + QTimer *m_layoutTimer; + int m_layoutDelay; + bool m_followBackgroundSetting; + bool m_dateFollowBackgroundSetting; + int TZoffset; + + // settings + Prefs *_prefs; + Zone *zone; + bool showDate; + bool showDayOfWeek; + bool m_updateOnTheMinute; + QStringList _remotezonelist; + KPopupMenu* menu; + ClockAppletToolTip m_tooltip; + KTextShadowEngine *m_shadowEngine; +}; + + +#endif diff --git a/kicker/applets/clock/clockapplet.desktop b/kicker/applets/clock/clockapplet.desktop new file mode 100644 index 000000000..6dda8818a --- /dev/null +++ b/kicker/applets/clock/clockapplet.desktop @@ -0,0 +1,151 @@ +[Desktop Entry] +Type=Plugin +Icon=clock +Name=Clock +Name[af]=Horlosie +Name[ar]=الساعة +Name[az]=Saat +Name[be]=Гадзіннік +Name[bg]=ЧаÑовник +Name[bn]=ঘড়ি +Name[br]=Eurier +Name[bs]=Sat +Name[ca]=Rellotge +Name[cs]=Hodiny +Name[csb]=Zédżer +Name[cy]=Cloc +Name[da]=Ur +Name[de]=Uhr +Name[el]=Ρολόι +Name[eo]=HorloÄo +Name[es]=Reloj +Name[et]=Kell +Name[eu]=Erlojua +Name[fa]=ساعت +Name[fi]=Kello +Name[fr]=Horloge +Name[fy]=Klok +Name[ga]=Clog +Name[gl]=Reloxo +Name[he]=שעון +Name[hi]=घड़ी +Name[hr]=Sat +Name[hu]=Óra +Name[id]=Jam +Name[is]=Klukka +Name[it]=Orologio +Name[ja]=時計 +Name[ka]=სáƒáƒáƒ—ი +Name[kk]=Сағат +Name[km]=នាឡិកា +Name[ko]=시계 +Name[lo]=ໂມງ +Name[lt]=Laikrodis +Name[lv]=Pulkstenis +Name[mk]=ЧаÑовник +Name[mn]=Цаг +Name[ms]=Jam +Name[mt]=ArloÄ¡Ä¡ +Name[nb]=Klokke +Name[nds]=Klock +Name[ne]=घडी +Name[nl]=Klok +Name[nn]=Klokke +Name[nso]=Sesupanako +Name[oc]=Rellotge +Name[pa]=ਘੜੀ +Name[pl]=Zegar +Name[pt]=Relógio +Name[pt_BR]=Relógio +Name[ro]=Ceas +Name[ru]=ЧаÑÑ‹ +Name[rw]=Isaha +Name[se]=Diibmu +Name[sk]=Hodiny +Name[sl]=Ura +Name[sr]=ЧаÑовник +Name[sr@Latn]=ÄŒasovnik +Name[ss]=Liwashi +Name[sv]=Klocka +Name[ta]=கடிகாரம௠+Name[te]=గడియారం +Name[tg]=Соат +Name[th]=นาฬิà¸à¸² +Name[tr]=Saat +Name[tt]=Säğät +Name[uk]=Годинник +Name[uz]=Soat +Name[uz@cyrillic]=Соат +Name[ven]=Tshifhinga +Name[vi]=Äồng hồ +Name[wa]=Ôrlodje +Name[xh]=Ikloko +Name[zh_CN]=时钟 +Name[zh_TW]=æ™‚é˜ +Name[zu]=Iwashi + +Comment=An analog and digital clock +Comment[af]='n Analoog en digitale horlosie +Comment[ar]= ساعة رقمية Ùˆ عادية +Comment[be]=Ðналагавы Ñ– лічбавы гадзіннік +Comment[bg]=СиÑтемен аплет за показване на датата и чаÑа +Comment[bn]=à¦à¦•à¦Ÿà¦¿ অà§à¦¯à¦¾à¦¨à¦¾à¦²à¦— à¦à¦¬à¦‚ ডিজিটাল ঘড়ি +Comment[bs]=Analogni i digitalni sat +Comment[ca]=Un rellotge digital i analògic +Comment[cs]=Applet s analogovými a digitálnÃmi hodinami +Comment[csb]=Analogòwi ë cyfrowi zédżer +Comment[da]=Et analogt og digitalt ur +Comment[de]=Eine analoge und digitale Uhr +Comment[el]=Ένα αναλογικό και ψηφιακό Ïολόι +Comment[en_GB]=An analogue and digital clock +Comment[eo]=Analoga kaj cifereca horloÄo +Comment[es]=Reloj analógico/digital +Comment[et]=Analoog- ja digitaalkell +Comment[eu]=Erloju analogiko eta digitala +Comment[fa]=ساعت قیاسی Ùˆ رقمی +Comment[fi]=Analoginen ja digitaalinen kello +Comment[fr]=Une horloge numérique et analogique +Comment[fy]=In analoge en digitale klok +Comment[ga]=Clog analógach agus digiteach +Comment[gl]=Unha applet cun reloxo analóxico e dixital. +Comment[he]=שעון ×× ×œ×•×’×™ ודיגיטלי +Comment[hr]=Analogni i digitalni sat +Comment[hu]=Egy analóg/digitális óra kisalkalmazásként +Comment[is]=Forrit sem birtir stafræna klukku eða skÃfuklukku +Comment[it]=Un orologio digitale o analogico +Comment[ja]=アナãƒã‚°æ™‚計ã¨ãƒ‡ã‚¸ã‚¿ãƒ«æ™‚計 +Comment[ka]=áƒáƒœáƒáƒšáƒáƒ’ური დრციფრული სáƒáƒáƒ—ი +Comment[kk]=Тілді немеÑе цифрлық Ñағат +Comment[km]=នាឡិកា​អាណាឡូក និង​ឌីជីážáž› +Comment[lt]=Analoginis ir skaitmeninis laikrodis +Comment[mk]=Ðналоген и дигитален чаÑовник +Comment[nb]=En analog og digital klokke for panelet. +Comment[nds]=En analoog oder digitaal Klock +Comment[ne]=à¤à¤¨à¤¾à¤²à¤— र डिजिटल घडी +Comment[nl]=Een analoge en digitale klok +Comment[nn]=Ei analog og digital klokke +Comment[pa]=ਇੱਕ à¨à¨¨à¨¾à¨²à¨¾à¨— ਤੇ ਡਿਜ਼ੀਟਲ ਘੜੀ ਹੈ। +Comment[pl]=Zegar analogowy i cyfrowy +Comment[pt]=Um relógio analógico e digital +Comment[pt_BR]=Um relógio analógico e digital +Comment[ro]=Un ceas analogic È™i digital +Comment[ru]=Ðплет аналоговых и цифровых чаÑов +Comment[se]=AnalogálaÅ¡ ja digitalálaÅ¡ diibmo +Comment[sk]=Analógové a digitálne hodiny. +Comment[sl]=Analogna in digitalna ura +Comment[sr]=Ðналогни и дигитални чаÑовник +Comment[sr@Latn]=Analogni i digitalni Äasovnik +Comment[sv]=En analog och digital klocka +Comment[te]=ఎనాలాగౠమరయూ డిజిటలౠగడియారం +Comment[th]=นาฬิà¸à¸²à¹à¸šà¸šà¹€à¸‚็มà¹à¸¥à¸°à¹à¸šà¸šà¸•à¸±à¸§à¹€à¸¥à¸‚ +Comment[tr]=Bir sayısal ve analog saat programcığı +Comment[uk]=Ðналоговий або цифровий годинник +Comment[uz]=Analog va raqamli soat +Comment[uz@cyrillic]=Ðналог ва рақамли Ñоат +Comment[vi]=Äồng hồ thÆ°á»ng và đồng hồ Ä‘iện tá» +Comment[wa]=Ene analodjike ou didjitÃ¥le ôrlodje. +Comment[zh_CN]=模拟和数å—时钟é¢æ¿å°ç¨‹åº +Comment[zh_TW]=一個å°çš„類比或數å—æ™‚é˜ + +X-KDE-Library=clock_panelapplet +X-KDE-UniqueApplet=false diff --git a/kicker/applets/clock/clockapplet.kcfg b/kicker/applets/clock/clockapplet.kcfg new file mode 100644 index 000000000..9b1ab3031 --- /dev/null +++ b/kicker/applets/clock/clockapplet.kcfg @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <include>kapplication.h</include> + <kcfgfile arg="true"/> + <group name="General"> + <entry name="Type" type="Enum"> + <label>Clock type</label> + <choices> + <choice name="Plain"/> + <choice name="Digital"/> + <choice name="Analog"/> + <choice name="Fuzzy"/> + </choices> + <default>Digital</default> + </entry> + </group> + <group name="Date"> + <entry name="DateForegroundColor" type="Color" key="Foreground_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().text()</default> + </entry> + <entry name="DateBackgroundColor" type="Color" key="Background_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().background()</default> + </entry> + <entry name="DateFont" type="Font" key="Font"> + <label>Font for the clock.</label> + <code> +QFont defFont=KGlobalSettings::generalFont(); +defFont.setPointSize(8); + </code> + <default code="true">defFont</default> + </entry> + </group> + <group name="Plain"> + <entry name="PlainShowSeconds" type="Bool" key="Show_Seconds"> + <label>Show seconds.</label> + <default>false</default> + </entry> + <entry name="PlainShowDate" type="Bool" key="Show_Date"> + <label>Show date.</label> + <default>true</default> + </entry> + <entry name="PlainShowDayOfWeek" type="Bool" key="Show_DayOfWeek"> + <label>Show day of week.</label> + <default>false</default> + </entry> + <entry name="PlainShowFrame" type="Bool" key="Show_Frame"> + <label>Show frame.</label> + <default>false</default> + </entry> + <entry name="PlainFont" type="Font" key="Font"> + <label>Font for the clock.</label> + <code> +defFont=KGlobalSettings::generalFont(); +defFont.setPointSize(8); +defFont.setBold(true); + </code> + <default code="true">defFont</default> + </entry> + <entry name="PlainForegroundColor" type="Color" key="Foreground_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().text()</default> + </entry> + <entry name="PlainBackgroundColor" type="Color" key="Background_Color"> + <label>Background color.</label> + <default code="true">KApplication::palette().active().background()</default> + </entry> + </group> + <group name="Digital"> + <entry name="DigitalShowSeconds" type="Bool" key="Show_Seconds"> + <label>Show seconds.</label> + <default>false</default> + </entry> + <entry name="DigitalShowDate" type="Bool" key="Show_Date"> + <label>Show date.</label> + <default>false</default> + </entry> + <entry name="DigitalShowDayOfWeek" type="Bool" key="Show_DayOfWeek"> + <label>Show day of week.</label> + <default>false</default> + </entry> + <entry name="DigitalShowFrame" type="Bool" key="Show_Frame"> + <label>Show frame.</label> + <default>false</default> + </entry> + <entry name="DigitalForegroundColor" type="Color" key="Foreground_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().text()</default> + </entry> + <entry name="DigitalBackgroundColor" type="Color" key="Background_Color"> + <label>Background color.</label> + <default code="true">KApplication::palette().active().background()</default> + </entry> + <entry name="DigitalShadowColor" type="Color" key="Shadow_Color"> + <label>Shadow color.</label> + <default code="true">KApplication::palette().active().mid()</default> + </entry> + <entry name="DigitalBlink" type="Bool" key="Blink"> + <label>Blink</label> + <default>false</default> + </entry> + <entry name="DigitalLCDStyle" type="Bool" key="LCD_Style"> + <label>LCD Style</label> + <default>false</default> + </entry> + </group> + <group name="Analog"> + <entry name="AnalogShowSeconds" type="Bool" key="Show_Seconds"> + <label>Show seconds.</label> + <default>true</default> + </entry> + <entry name="AnalogShowDate" type="Bool" key="Show_Date"> + <label>Show date.</label> + <default>false</default> + </entry> + <entry name="AnalogShowDayOfWeek" type="Bool" key="Show_DayOfWeek"> + <label>Show day of week.</label> + <default>false</default> + </entry> + <entry name="AnalogShowFrame" type="Bool" key="Show_Frame"> + <label>Show frame.</label> + <default>false</default> + </entry> + <entry name="AnalogForegroundColor" type="Color" key="Foreground_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().text()</default> + </entry> + <entry name="AnalogBackgroundColor" type="Color" key="Background_Color"> + <label>Background color.</label> + <default code="true">KApplication::palette().active().background()</default> + </entry> + <entry name="AnalogShadowColor" type="Color" key="Shadow_Color"> + <label>Shadow color.</label> + <default code="true">KApplication::palette().active().mid()</default> + </entry> + <entry name="AnalogLCDStyle" type="Bool" key="LCD_Style"> + <label>LCD Style</label> + <default>true</default> + </entry> + <entry name="AnalogAntialias" type="Int" key="Antialias"> + <label>Anti-Alias factor</label> + <default>0</default> + </entry> + </group> + <group name="Fuzzy"> + <entry name="FuzzyShowDate" type="Bool" key="Show_Date"> + <label>Show date.</label> + <default>true</default> + </entry> + <entry name="FuzzyShowDayOfWeek" type="Bool" key="Show_DayOfWeek"> + <label>Show day of week.</label> + <default>false</default> + </entry> + <entry name="FuzzyShowFrame" type="Bool" key="Show_Frame"> + <label>Show frame.</label> + <default>false</default> + </entry> + <entry name="FuzzyFont" type="Font" key="Font"> + <label>Font for the clock.</label> + <code> +defFont=KGlobalSettings::generalFont(); + </code> + <default code="true">defFont</default> + </entry> + <entry name="FuzzyForegroundColor" type="Color" key="Foreground_Color"> + <label>Foreground color.</label> + <default code="true">KApplication::palette().active().text()</default> + </entry> + <entry name="FuzzyBackgroundColor" type="Color" key="Background_Color"> + <label>Background color.</label> + <default code="true">KApplication::palette().active().background()</default> + </entry> + <entry name="Fuzzyness" type="Int"> + <label>Fuzzyness</label> + <default>1</default> + </entry> + </group> + <group name="Calendar"> + <entry name="CalendarFullWindow" type="Bool" key="FullWindow"> + <label>Show window frame</label> + <default>true</default> + </entry> + <entry name="CalendarSize" type="Size" key="Size"> + <label>Default size of the calendar</label> + </entry> + </group> +</kcfg> diff --git a/kicker/applets/clock/datepicker.cpp b/kicker/applets/clock/datepicker.cpp new file mode 100644 index 000000000..0ea677e8a --- /dev/null +++ b/kicker/applets/clock/datepicker.cpp @@ -0,0 +1,87 @@ +/************************************************************ + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "datepicker.h" +#include "prefs.h" + +#include <kdatepicker.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kwin.h> +#include <netwm.h> + +DatePicker::DatePicker(QWidget *parent, const QDate& date, Prefs* _prefs) + : QVBox( parent, 0, + _prefs->calendarFullWindow() + ? (WType_TopLevel | WDestructiveClose | + WStyle_StaysOnTop) + : (WStyle_Customize | WStyle_NoBorder | + WType_TopLevel | WDestructiveClose | + WStyle_StaysOnTop) ), + prefs(_prefs) +{ + if (prefs->calendarFullWindow()) + { + KWin::setType(winId(), NET::Utility); + setFrameStyle(QFrame::NoFrame); + } + else + { + setFrameStyle(QFrame::PopupPanel | QFrame::Raised); + } + + KWin::setOnAllDesktops(handle(), true); + picker = new KDatePicker(this, date); + picker->setCloseButton(!_prefs->calendarFullWindow()); + + /* name and icon for kicker's taskbar */ + setCaption(i18n("Calendar")); + setIcon(SmallIcon("date")); +} + +void DatePicker::closeEvent(QCloseEvent* e) +{ + prefs->setCalendarSize(size()); + QVBox::closeEvent(e); +} + +void DatePicker::keyPressEvent(QKeyEvent *e) +{ + QVBox::keyPressEvent(e); + + if (e->key() == Qt::Key_Escape) + { + close(); + } +} + +bool DatePicker::setDate(const QDate& date) +{ + return picker->setDate(date); +} + +QDate DatePicker::date() +{ + return picker->date(); +} + diff --git a/kicker/applets/clock/datepicker.h b/kicker/applets/clock/datepicker.h new file mode 100644 index 000000000..ee39261e0 --- /dev/null +++ b/kicker/applets/clock/datepicker.h @@ -0,0 +1,49 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __DATEPICKER_H +#define __DATEPICKER_H + +#include <qvbox.h> +#include <qdatetime.h> + +class KDatePicker; +class Prefs; + +class DatePicker : public QVBox +{ + public: + DatePicker(QWidget*, const QDate&, Prefs* _prefs); + bool setDate(const QDate& date); + QDate date(); + + protected: + void closeEvent(QCloseEvent* e); + void keyPressEvent(QKeyEvent *e); + + private: + KDatePicker *picker; + Prefs *prefs; +}; + +#endif diff --git a/kicker/applets/clock/digital.ui b/kicker/applets/clock/digital.ui new file mode 100644 index 000000000..256bca99b --- /dev/null +++ b/kicker/applets/clock/digital.ui @@ -0,0 +1,305 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>DigitalWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>DigitalWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>553</width> + <height>251</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>ButtonGroup2_3</cstring> + </property> + <property name="title"> + <string>Display</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalShowDate</cstring> + </property> + <property name="text"> + <string>Dat&e</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalShowSeconds</cstring> + </property> + <property name="text"> + <string>Seco&nds</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalShowDayOfWeek</cstring> + </property> + <property name="text"> + <string>Da&y of week</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalBlink</cstring> + </property> + <property name="text"> + <string>Blin&king dots</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalShowFrame</cstring> + </property> + <property name="text"> + <string>&Frame</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer21</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> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Time</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DigitalLCDStyle</cstring> + </property> + <property name="text"> + <string>LCD look</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>Foreground_ColorL</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_DigitalForegroundColor</cstring> + </property> + </widget> + <widget class="KColorButton" row="2" column="1"> + <property name="name"> + <cstring>kcfg_DigitalBackgroundColor</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>backgroundDigitalLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Background color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_DigitalBackgroundColor</cstring> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_DigitalForegroundColor</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_DigitalShadowColor</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>Shadow_ColorL</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Shadow color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_DigitalShadowColor</cstring> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer75</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_DigitalBackgroundColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>backgroundDigitalLabel</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_DigitalForegroundColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>Foreground_ColorL</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_DigitalShadowColor</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_DigitalLCDStyle</sender> + <signal>toggled(bool)</signal> + <receiver>Shadow_ColorL</receiver> + <slot>setDisabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>kcfg_DigitalShowDate</tabstop> + <tabstop>kcfg_DigitalShowSeconds</tabstop> + <tabstop>kcfg_DigitalBlink</tabstop> + <tabstop>kcfg_DigitalShowFrame</tabstop> + <tabstop>kcfg_DigitalLCDStyle</tabstop> + <tabstop>kcfg_DigitalForegroundColor</tabstop> + <tabstop>kcfg_DigitalShadowColor</tabstop> + <tabstop>kcfg_DigitalBackgroundColor</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">kfontrequester.h</include> + <include location="local" impldecl="in implementation">digital.ui.h</include> +</includes> +<slots> + <slot>kcfg_DigitalLCDStyle_stateChanged( int )</slot> +</slots> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/clock/fuzzy.ui b/kicker/applets/clock/fuzzy.ui new file mode 100644 index 000000000..04e910340 --- /dev/null +++ b/kicker/applets/clock/fuzzy.ui @@ -0,0 +1,287 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>FuzzyWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>FuzzyWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>306</width> + <height>299</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Display</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_FuzzyShowDate</cstring> + </property> + <property name="text"> + <string>Dat&e</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_FuzzyShowDayOfWeek</cstring> + </property> + <property name="text"> + <string>Da&y of week</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_FuzzyShowFrame</cstring> + </property> + <property name="text"> + <string>&Frame</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer13</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="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Time</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer46</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Font:</string> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel1_2_3_4_3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_FuzzyBackgroundColor</cstring> + </property> + </widget> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>51</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1_4_3_2</cstring> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_FuzzyForegroundColor</cstring> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_FuzzyBackgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_FuzzyForegroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </grid> + </widget> + <widget class="QLayoutWidget" row="0" column="2"> + <property name="name"> + <cstring>Layout7_3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel4_3</cstring> + </property> + <property name="text"> + <string>Low</string> + </property> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>kcfg_Fuzzyness</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>4</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>Both</enum> + </property> + <property name="tickInterval"> + <number>1</number> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel5_3</cstring> + </property> + <property name="text"> + <string>High</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>TextLabel3_3</cstring> + </property> + <property name="text"> + <string>Fuzziness:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_Fuzzyness</cstring> + </property> + </widget> + <widget class="KFontRequester" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_FuzzyFont</cstring> + </property> + <property name="title"> + <string>Date Font</string> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>kcfg_FuzzyShowDate</tabstop> + <tabstop>kcfg_FuzzyShowFrame</tabstop> + <tabstop>kcfg_Fuzzyness</tabstop> + <tabstop>kcfg_FuzzyForegroundColor</tabstop> + <tabstop>kcfg_FuzzyBackgroundColor</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">kfontrequester.h</include> +</includes> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kfontrequester.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/clock/lcd.png b/kicker/applets/clock/lcd.png Binary files differnew file mode 100644 index 000000000..32e5e90d8 --- /dev/null +++ b/kicker/applets/clock/lcd.png diff --git a/kicker/applets/clock/prefs.kcfgc b/kicker/applets/clock/prefs.kcfgc new file mode 100644 index 000000000..890209526 --- /dev/null +++ b/kicker/applets/clock/prefs.kcfgc @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=clockapplet.kcfg +ClassName=Prefs +Singleton=false +Mutators=Type,CalendarSize,CalendarFullWindow,DateBackgroundColor,PlainBackgroundColor,AnalogBackgroundColor,FuzzyBackgroundColor,DigitalBackgroundColor +# MemberVariables=public diff --git a/kicker/applets/clock/settings.ui b/kicker/applets/clock/settings.ui new file mode 100644 index 000000000..215aa5433 --- /dev/null +++ b/kicker/applets/clock/settings.ui @@ -0,0 +1,515 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>605</width> + <height>639</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabs</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Appearance</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="text"> + <string>Clock type:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>clockCombo</cstring> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Plain Clock</string> + </property> + </item> + <item> + <property name="text"> + <string>Digital Clock</string> + </property> + </item> + <item> + <property name="text"> + <string>Analog Clock</string> + </property> + </item> + <item> + <property name="text"> + <string>Fuzzy Clock</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_Type</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer> + <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>20</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>widgetStack</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>ButtonGroup2_3_2_2</cstring> + </property> + <property name="title"> + <string>Display</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_PlainShowDate</cstring> + </property> + <property name="text"> + <string>Dat&e</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_PlainShowSeconds</cstring> + </property> + <property name="text"> + <string>&Seconds</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_PlainShowDayOfWeek</cstring> + </property> + <property name="text"> + <string>Da&y of week</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_PlainShowFrame</cstring> + </property> + <property name="text"> + <string>&Frame</string> + </property> + </widget> + <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> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Time</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>TextLabel1_3_3_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Font:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>TextLabel1_2_3_4_3_2</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Background color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_PlainBackgroundColor</cstring> + </property> + </widget> + <widget class="KColorButton" row="1" column="2"> + <property name="name"> + <cstring>kcfg_PlainBackgroundColor</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton" row="0" column="2"> + <property name="name"> + <cstring>kcfg_PlainForegroundColor</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>TextLabel1_4_3_2_2</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_PlainForegroundColor</cstring> + </property> + </widget> + <spacer row="0" column="3"> + <property name="name"> + <cstring>spacer17</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>230</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KFontRequester" row="2" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_PlainFont</cstring> + </property> + </widget> + <spacer row="3" column="3"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + </vbox> + </widget> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>dateBox</cstring> + </property> + <property name="title"> + <string>Date</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_DateBackgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_DateForegroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + <spacer row="0" column="2"> + <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>343</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Font:</string> + </property> + </widget> + <widget class="KFontRequester"> + <property name="name"> + <cstring>kcfg_DateFont</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>100</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Timezones</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>City</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Comment</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>tzListView</cstring> + </property> + <property name="toolTip" stdset="0"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string>A list of timezones known to your system. Press the middle mouse button on the clock in the taskbar and it shows you the time in the selected cities.</string> + </property> + </widget> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>tabs</tabstop> + <tabstop>kcfg_Type</tabstop> + <tabstop>kcfg_PlainShowDate</tabstop> + <tabstop>kcfg_PlainShowSeconds</tabstop> + <tabstop>kcfg_PlainShowFrame</tabstop> + <tabstop>kcfg_PlainForegroundColor</tabstop> + <tabstop>kcfg_PlainBackgroundColor</tabstop> + <tabstop>kcfg_DateBackgroundColor</tabstop> + <tabstop>kcfg_DateForegroundColor</tabstop> + <tabstop>kcfg_DateFont</tabstop> + <tabstop>tzListView</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">kfontrequester.h</include> +</includes> +<slots> + <slot>configureType()</slot> +</slots> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kfontrequester.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kfontrequester.h</includehint> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/clock/zone.cpp b/kicker/applets/clock/zone.cpp new file mode 100644 index 000000000..1d952a765 --- /dev/null +++ b/kicker/applets/clock/zone.cpp @@ -0,0 +1,180 @@ +/************************************************************ + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "zone.h" + +#include <kcolorbutton.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kstringhandler.h> +#include <klocale.h> + +#include <qfile.h> +#include <qtooltip.h> +#include <klistview.h> + +#include <time.h> +#include <stdlib.h> // for getenv() + +Zone::Zone(KConfig* conf): + config(conf), + _zoneIndex(0) +{ + _defaultTZ = ::getenv("TZ"); + tzset(); + + config->setGroup("General"); + + /* default displayable timezones */ + QString tzList = config->readEntry("RemoteZones"); + _remotezonelist = QStringList::split(",", tzList); + setZone(config->readNumEntry("Initial_TZ", 0)); +} + +Zone::~Zone() +{ + writeSettings(); +} + +void Zone::setZone(int z) +{ + if (_zoneIndex > _remotezonelist.count()) + z = 0; + + _zoneIndex = z; +} + +QString Zone::zone(int z) const +{ + return (z == 0 ? _defaultTZ : _remotezonelist[z-1]); +} + +int Zone::calc_TZ_offset(const QString& zone, bool /* reset */) +{ + const KTimezone *z = zone.isEmpty() ? m_zoneDb.local() : m_zoneDb.zone(zone); + + if (!z) + { + z = m_zoneDb.local(); + } + + if (z) + { + return -z->offset(Qt::LocalTime); + } + + return 0; +} + +void Zone::readZoneList(KListView *listView ) +{ + const KTimezones::ZoneMap zones = m_zoneDb.allZones(); + QMap<QString, QListViewItem*> KontinentMap; + + listView->setRootIsDecorated(true); + for (KTimezones::ZoneMap::ConstIterator it = zones.begin(); it != zones.end(); ++it) + { + const KTimezone *zone = it.data(); + QString tzName = zone->name(); + QString comment = zone->comment(); + if (!comment.isEmpty()) + comment = i18n(comment.utf8()); + + const QStringList KontCity = QStringList::split("/", i18n(tzName.utf8()).replace("_", " ")); + QListViewItem* Kontinent = KontinentMap[KontCity[0]]; + if (!Kontinent) { + KontinentMap[KontCity[0]] = new QListViewItem(listView, KontCity[0]); + Kontinent = KontinentMap[KontCity[0]]; + Kontinent->setExpandable(true); + } + + QCheckListItem *li = new QCheckListItem(Kontinent, KontCity[1], QCheckListItem::CheckBox); + li->setText(1, comment); + li->setText(2, tzName); /* store complete path in ListView */ + + if (_remotezonelist.findIndex(tzName) != -1) + li->setOn(true); + + // locate the flag from /l10n/%1/flag.png + // if not available select default "C" flag + QString flag = locate( "locale", QString("l10n/%1/flag.png").arg(zone->countryCode().lower()) ); + if (!QFile::exists(flag)) + flag = locate( "locale", "l10n/C/flag.png" ); + if (QFile::exists(flag)) + li->setPixmap(0, QPixmap(flag)); + } +} + +void Zone::getSelectedZonelist(KListView *listView) +{ + _remotezonelist.clear(); + + /* loop through all entries */ + QListViewItem *root = listView->firstChild(); + while (root) { + if (root->firstChild()) { + root = root->firstChild(); + continue; + } + + QCheckListItem *cl = (QCheckListItem*) root; + if (cl->isOn()) { + _remotezonelist.append(cl->text(2)); + } + + if (root->nextSibling()) { + root = root->nextSibling(); + continue; + } + root = root->parent(); + if (root) + root = root->nextSibling(); + } +} + +void Zone::nextZone() +{ + if (++_zoneIndex > _remotezonelist.count()) + _zoneIndex = 0; +} + +void Zone::prevZone() +{ + if (_zoneIndex == 0) + _zoneIndex = _remotezonelist.count(); + else + --_zoneIndex; +} + +void Zone::writeSettings() +{ + config->setGroup("General"); + config->writeEntry("RemoteZones", _remotezonelist.join(",")); + config->writeEntry("Initial_TZ",_zoneIndex); + config->sync(); +} diff --git a/kicker/applets/clock/zone.h b/kicker/applets/clock/zone.h new file mode 100644 index 000000000..34371c6ae --- /dev/null +++ b/kicker/applets/clock/zone.h @@ -0,0 +1,62 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __ZONE_H +#define __ZONE_H + +#include <ktimezones.h> +#include <qstringlist.h> + +class KConfig; +class KListView; + +class Zone { + +public: + Zone(KConfig* conf); + ~Zone(); + + void writeSettings(); + + QString zone() const { return zone(_zoneIndex); }; + QString zone(int z) const; + QStringList remoteZoneList() const { return _remotezonelist; }; + int remoteZoneCount() { return _remotezonelist.count(); }; + unsigned int zoneIndex() const { return _zoneIndex; } + void setZone(int z = 0); + + void nextZone(); + void prevZone(); + int calc_TZ_offset(const QString& zone, bool reset=false); + void readZoneList(KListView *listView); + void getSelectedZonelist(KListView *listView); + +protected: + KTimezones m_zoneDb; + QStringList _remotezonelist; + KConfig *config; + QString _defaultTZ; + unsigned int _zoneIndex; +}; + +#endif diff --git a/kicker/applets/launcher/ChangeLog b/kicker/applets/launcher/ChangeLog new file mode 100644 index 000000000..b86dbd7aa --- /dev/null +++ b/kicker/applets/launcher/ChangeLog @@ -0,0 +1,40 @@ +2004-06-15 Dan Bullok <dan.kde@bullok.com> + * Fixed flicker on drop/arrange. + * Can now drop more than one item at a time + * Empty panel now has size>0, so user can still drop icons on it. + * Fixed gcc 3.4 incompatibilities in EasyVector + * Fixed Drag and Drop Bugs : + * Crash when non-url dropped on quicklauncher + * Crash panel button dropped on quicklauncher + * Able to drop objects when quicklauncher is locked + * Add application context menu now inserts new app at current location + +2004-06-14 Dan Bullok <dan.kde@bullok.com> + * Fixed License statements (added email & pointer to COPYING) + * GUI changes made in previous commit. + * continued separating QuickURL and QuickButton. + * Rearranged menu items to make more sense + +2004-06-13 Dan Bullok <dan.kde@bullok.com> + * Fixes Bugs #42278, #55625, #63506, #67891, #76868, #79848, #80530 - also makes bacon & eggs for breakfast (toast & jam available for vegetarians) + * v2.0alpha + * Replaced most of the innards of QuickLauncher class. + * Icons are positions evenly across available space. + * Drag and drop works for all kicker widths. + * Visual Feedback of drop location + * Icon Size is user-definable. Sensible(?) values are used by default (Icons grow slightly as panel size increases. #icons per row for given panel size is Tiny,Small: 1, Normal: 2, Large:3, 110pix: 4). + * User can lock icon drag and drop (prevents accidentally screwing things up). + * Icons can either take up exactly the defined amount of space (ConserveSpace=true - this is the default), or grow slightly to take advantage of unused space. + * Spouts tons of debugging info to kdDebug (for now). + +2004-06-12 Dan Bullok <dan.kde@bullok.com> + * Fixed bug #75351: Tooltips change to filenames after rearranging applications in quicklauncher. + * Moved the URL->(menuID,service,kurl) functionality from the QuickButton constructor to its own class: QuickURL. Very similar code is used elsewhere in kicker, and should eventually be merged. + * Renamed some methods in QuickButton (getId -> menuId, getURL -> url) This matches the predominant KDE naming style. + * Groundwork laid for variable-sized buttons. + +2004-06-12 Dan Bullok <dan.kde@bullok.com> + * Changed member variable names: myVar -> _myVar. + +2004-06-12 Dan Bullok <dan.kde@bullok.com> + * Fixed formatting only - no code changes. There were a few conflicting indenting styles. I picked the one that looked like it was the oldest, and applied it to all the files. diff --git a/kicker/applets/launcher/Makefile.am b/kicker/applets/launcher/Makefile.am new file mode 100644 index 000000000..a101c6ccf --- /dev/null +++ b/kicker/applets/launcher/Makefile.am @@ -0,0 +1,27 @@ + +INCLUDES = -I$(top_srcdir)/kicker/libkicker -I$(top_srcdir)/kicker/kicker/ui $(all_includes) + +kde_module_LTLIBRARIES = launcher_panelapplet.la + +launcher_panelapplet_la_SOURCES = quicklauncher.skel quicklauncher.cpp quickbutton.cpp quickaddappsmenu.cpp flowgridmanager.cpp popularity.cpp configdlgbase.ui prefs.kcfgc configdlg.cpp + +METASOURCES = AUTO +noinst_HEADERS = quicklauncher.h quickbutton.h quickaddappsmenu.h easyvector.h quickbuttongroup.h flowgridmanager.h popularity.h configdlg.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = quicklauncher.desktop + +EXTRA_DIST = $(lnk_DATA) + +launcher_panelapplet_la_LDFLAGS = -module $(KDE_RPATH) $(all_libraries) -avoid-version -no-undefined +launcher_panelapplet_la_LIBADD = ../../kicker/core/libkicker_core.la ../../kicker/buttons/libkicker_buttons.la \ + ../../kicker/ui/libkicker_ui.la ../../libkicker/libkickermain.la $(LIB_KIO) \ + $(LIB_KSYCOCA) $(LIB_KDEUI) $(LIB_KUTILS) + +kde_kcfg_DATA = launcherapplet.kcfg + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/quicklauncher.pot + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/quicklauncher quicklauncher *.h -lqt -lkdecore -lkdeui diff --git a/kicker/applets/launcher/ToDo b/kicker/applets/launcher/ToDo new file mode 100644 index 000000000..c7c852a36 --- /dev/null +++ b/kicker/applets/launcher/ToDo @@ -0,0 +1,8 @@ +TODO: + X * Geometry isn't always updated when panel size changes. + x * Remove debugging code (makes everything slow). + * Tooltip or other popup to alert user that buttons are locked (with a "don't show this again" checkbox). + * Docs. + * Use old quicklauncher config file if found. #77959 + X * "Add application" context menu should add the new application at the index of the button that summoned the context menu. + X * Make sure to always have a little space to drop things on, even when there are no buttons. diff --git a/kicker/applets/launcher/configdlg.cpp b/kicker/applets/launcher/configdlg.cpp new file mode 100644 index 000000000..9950dd2a9 --- /dev/null +++ b/kicker/applets/launcher/configdlg.cpp @@ -0,0 +1,101 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen <kde.sch@ttgen.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + + +#include <qcombobox.h> +#include <klocale.h> +#include <kdebug.h> + +#include "prefs.h" +#include "configdlg.h" +#include "configdlgbase.h" + +ConfigDlg::ConfigDlg(QWidget *parent, const char *name, Prefs *config, + int autoSize, KConfigDialog::DialogType dialogType, + int dialogButtons) : + KConfigDialog(parent, name, config, dialogType, dialogButtons), + m_settings(config), + m_autoSize(autoSize) +{ + m_ui = new ConfigDlgBase(this->plainPage()); + addPage(m_ui, i18n("Configure"), "config"); + + m_ui->iconDim->clear(); + m_ui->iconDim->insertItem(i18n("Automatic")); + for (int n=0; n<int(m_settings->iconDimChoices().size()); ++n) + { + m_ui->iconDim->insertItem(QString::number( + m_settings->iconDimChoices()[n])); + } + connect(m_ui->iconDim, SIGNAL(textChanged(const QString&)), + this, SLOT(updateButtons())); + updateWidgets(); + m_oldIconDimText = m_ui->iconDim->currentText(); + updateButtons(); +} + +void ConfigDlg::updateSettings() +{ + kdDebug() << "updateSettings" << endl; + KConfigDialog::updateSettings(); + if (!hasChanged()) + { + return; + } + m_oldIconDimText = m_ui->iconDim->currentText(); + if (m_ui->iconDim->currentText() == i18n("Automatic")) + { + m_settings->setIconDim(m_autoSize); + } + else + { + m_settings->setIconDim(m_ui->iconDim->currentText().toInt()); + } + settingsChangedSlot(); +} + +void ConfigDlg::updateWidgets() +{ + KConfigDialog::updateWidgets(); + if (m_settings->iconDim() == m_autoSize) + { + m_ui->iconDim->setEditText(i18n("Automatic")); + } + else + { + m_ui->iconDim->setEditText(QString::number(m_settings->iconDim())); + } +} + +void ConfigDlg::updateWidgetsDefault() +{ + KConfigDialog::updateWidgetsDefault(); +} + +bool ConfigDlg::hasChanged() +{ + return m_oldIconDimText != m_ui->iconDim->currentText() || + KConfigDialog::hasChanged(); +} + +#include "configdlg.moc" diff --git a/kicker/applets/launcher/configdlg.h b/kicker/applets/launcher/configdlg.h new file mode 100644 index 000000000..1d03a9381 --- /dev/null +++ b/kicker/applets/launcher/configdlg.h @@ -0,0 +1,55 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen <kde.sch@ttgen.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef CONFIG_DLG_H +#define CONFIG_DLG_H + +#include <kconfigdialog.h> + +class ConfigDlgBase; +class Prefs; + +class ConfigDlg : public KConfigDialog +{ + Q_OBJECT + +public: + ConfigDlg(QWidget *parent, const char *name, Prefs *config, int autoSize, + KConfigDialog::DialogType dialogType, int dialogButtons); + +protected: + virtual bool hasChanged(); + +protected slots: + virtual void updateSettings(); + virtual void updateWidgets(); + virtual void updateWidgetsDefault(); + +private: + ConfigDlgBase *m_ui; + Prefs* m_settings; + int m_autoSize; + QString m_oldIconDimText; +}; + +#endif diff --git a/kicker/applets/launcher/configdlgbase.ui b/kicker/applets/launcher/configdlgbase.ui new file mode 100644 index 000000000..bfb1bc4e6 --- /dev/null +++ b/kicker/applets/launcher/configdlgbase.ui @@ -0,0 +1,273 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ConfigDlgBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ConfigDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>371</width> + <height>338</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_DragEnabled</cstring> + </property> + <property name="text"> + <string>Allow drag and drop</string> + </property> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Layout</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_ConserveSpace</cstring> + </property> + <property name="text"> + <string>Conserve space</string> + </property> + <property name="toolTip" stdset="0"> + <string>Do not expand icons to the size of the panel</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Icon size:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <property name="name"> + <cstring>iconDim</cstring> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer4_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>332</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>autoAdjustGroup</cstring> + </property> + <property name="title"> + <string>Most Popular Applications</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSlider" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_HistoryHorizon</cstring> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="lineStep"> + <number>0</number> + </property> + <property name="value"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <spacer row="1" column="1"> + <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>140</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Short Term</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Long Term</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Maximum number of applications:</string> + </property> + </widget> + <widget class="KIntSpinBox" row="1" column="1"> + <property name="name"> + <cstring>kcfg_AutoAdjustMinItems</cstring> + </property> + </widget> + <spacer row="2" column="2"> + <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>50</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KIntSpinBox" row="2" column="1"> + <property name="name"> + <cstring>kcfg_AutoAdjustMaxItems</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>Minimum number of applications:</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_AutoAdjustEnabled</cstring> + </property> + <property name="text"> + <string>Add/remove applications based on their popularity</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AutoAdjustMinItems</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AutoAdjustMaxItems</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_HistoryHorizon</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel1</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel2</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel3</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoAdjustEnabled</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel3_2</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/launcher/easyvector.h b/kicker/applets/launcher/easyvector.h new file mode 100644 index 000000000..cad9a2c86 --- /dev/null +++ b/kicker/applets/launcher/easyvector.h @@ -0,0 +1,147 @@ +/* Copyright 2004, Daniel Woods Bullok <dan.devel@bullok.com> + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#ifndef __easyvector_h__ +#define __easyvector_h__ +#include <vector> +#include <algorithm> +#include <assert.h> + +template < class VALUE > +class __Valtype { +public: + typedef const VALUE& CVALUE; +}; + + +template < class VALUE > +class __Valtype< VALUE* > { +public: + typedef const VALUE* CVALUE; +}; + + +template <class VALUE, bool CHECKINDEX=true> +class EasyVector: public std::vector< VALUE > { +public: + typedef int Index; + typedef std::vector< Index > Indices; + typedef typename __Valtype< VALUE >::CVALUE CVALUE; + + static const Index NotFound=-2; + static const Index Append=-1; + + template < class PTYPE, class PROP_FUNC > + Index findProperty(const PTYPE &property, + PROP_FUNC prop_func) const; + Index findValue(CVALUE value) const; + + Index lastIndex() const {return this->size()-1;} + + void eraseAt(Index index); + + VALUE takeFrom(Index index); + + void insertAt(Index index,const VALUE &value); + void insertAt(Index index,const EasyVector &values); + + bool isValidIndex(Index index) const; + bool isValidInsertIndex(Index index) const; + virtual ~EasyVector(){}; + + +protected: + void _checkInsertIndex(Index index) const; + void _checkIndex(Index index) const; + Index _convertInsertIndex(Index index) const; +}; + + +template < class VALUE, bool CHECKINDEX > +template < class PTYPE, class PROP_FUNC > +typename EasyVector< VALUE, CHECKINDEX >::Index + EasyVector< VALUE, CHECKINDEX >::findProperty(const PTYPE &property, + PROP_FUNC prop_func) const +{ typename EasyVector< VALUE, CHECKINDEX >::const_iterator i; + for (i=this->begin();i!=this->end();++i) { + if (prop_func(*i)==property) + return i-this->begin(); + } + return NotFound; +} + + +template < class VALUE, bool CHECKINDEX > +typename EasyVector< VALUE, CHECKINDEX >::Index + EasyVector< VALUE, CHECKINDEX >::findValue(CVALUE value) const +{ typename EasyVector< VALUE, CHECKINDEX >::const_iterator i; + i=std::find(this->begin(),this->end(),value); + if (i==this->end()) return NotFound; + return i-this->begin(); +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::eraseAt(Index index) +{ _checkIndex(index); + erase(this->begin()+index); +} + + +template < class VALUE, bool CHECKINDEX > +VALUE EasyVector< VALUE, CHECKINDEX >::takeFrom(Index index) +{ _checkIndex(index); + VALUE result=(*this)[index]; + eraseAt(index); + return result; +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::insertAt(EasyVector< VALUE, CHECKINDEX >::Index index,const VALUE &value) +{ index=_convertInsertIndex(index); + _checkInsertIndex(index); + if (index==int(this->size())) { + this->push_back(value); + return; + } + insert(this->begin()+index,value); +} + + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::insertAt(EasyVector< VALUE, CHECKINDEX >::Index index,const EasyVector< VALUE, CHECKINDEX > &v) +{ index=_convertInsertIndex(index); + _checkInsertIndex(index); + insert(this->begin()+index,v.begin(),v.end()); +} + + +template < class VALUE, bool CHECKINDEX > +bool EasyVector< VALUE, CHECKINDEX >::isValidIndex(EasyVector< VALUE, CHECKINDEX >::Index index) const +{ return(0<=index && index<int(this->size()));} + +template < class VALUE, bool CHECKINDEX > +bool EasyVector< VALUE, CHECKINDEX >::isValidInsertIndex(EasyVector< VALUE, CHECKINDEX >::Index index) const +{ return(index==Append)||(0<=index && index<=int(this->size()));} + +template < class VALUE, bool CHECKINDEX > +inline typename EasyVector< VALUE, CHECKINDEX >::Index EasyVector< VALUE, CHECKINDEX >::_convertInsertIndex(Index index) const +{ if (index==Append) return this->size(); + return index; +} + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::_checkInsertIndex(Index index) const +{ if (CHECKINDEX) assert (isValidInsertIndex(index));} + +template < class VALUE, bool CHECKINDEX > +void EasyVector< VALUE, CHECKINDEX >::_checkIndex(Index index) const +{ if (CHECKINDEX) assert (isValidIndex(index));} + + +#endif + diff --git a/kicker/applets/launcher/flowgridmanager.cpp b/kicker/applets/launcher/flowgridmanager.cpp new file mode 100644 index 000000000..b5715097b --- /dev/null +++ b/kicker/applets/launcher/flowgridmanager.cpp @@ -0,0 +1,316 @@ +/* Copyright 2004, Daniel Woods Bullok <dan.devel@bullok.com> + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#include "flowgridmanager.h" +#include <kdebug.h> +#ifdef DEBUG + #define DEBUGSTR kdDebug() +#else + #define DEBUGSTR kndDebug() +#endif + + +FlowGridManager::FlowGridManager(QSize p_item_size, + QSize p_space_size, + QSize p_border_size, + QSize p_frame_size, + Qt::Orientation orient, + int num_items, + Slack slack_x,Slack slack_y) +{ + _pItemSize=p_item_size; + _pSpaceSize=p_space_size; + _pBorderSize=p_border_size; + _pFrameSize=p_frame_size; + _orientation=orient; + _numItems=num_items; + _slackX=slack_x; + _slackY=slack_y; + _conserveSpace=false; + + _dirty=true; + _valid=false; +} + +// set members. +// These all set the _dirty flag if the new value is different. +void FlowGridManager::setNumItems(int num_items) +{ if (_numItems==num_items) + return; + _numItems=num_items; _dirty=true; +} +void FlowGridManager::setItemSize(QSize p_item_size) +{ if (_pItemSize==p_item_size) + return; + _pItemSize=p_item_size; _dirty=true; +} + +void FlowGridManager::setSpaceSize(QSize p_space_size) +{ if (_pSpaceSize==p_space_size) + return; + _pSpaceSize=p_space_size; _dirty=true; +} + +void FlowGridManager::setBorderSize(QSize p_border_size) +{ if (_pBorderSize==p_border_size) + return; + _pBorderSize=p_border_size; _dirty=true; +} + +void FlowGridManager::setFrameSize(QSize p_frame_size) +{ if (_pFrameSize==p_frame_size) + return; + _pFrameSize=p_frame_size; + if (_pFrameSize.width()<=0) { + _orientation=Qt::Vertical; + } + if (_pFrameSize.height()<=0) { + _orientation=Qt::Horizontal; + } + _dirty=true; +} + +void FlowGridManager::setOrientation(Qt::Orientation orient) +{ if (orient==_orientation) + return; + _orientation=orient; _dirty=true; +} + +void FlowGridManager::setSlack(Slack slack_x, Slack slack_y) +{ if (slack_x==_slackX && slack_y==_slackY) return; + _slackX=slack_x; _slackY=slack_y; _dirty=true;} + + +void FlowGridManager::setConserveSpace(bool conserve) +{ if (_conserveSpace==conserve) + return; + _conserveSpace=conserve; _dirty=true; +} + + + +// get members +QSize FlowGridManager::itemSize() const +{ _checkReconfigure(); return _itemSize;} + +QSize FlowGridManager::spaceSize() const +{ _checkReconfigure(); return _spaceSize;} + +QSize FlowGridManager::borderSize() const +{ _checkReconfigure(); return _borderSize;} + +QSize FlowGridManager::gridDim() const +{ _checkReconfigure(); return _gridDim;} + +QSize FlowGridManager::gridSpacing() const +{ _checkReconfigure(); return _gridSpacing;} + +QSize FlowGridManager::frameSize() const +{ _checkReconfigure(); return _frameSize;} + +QPoint FlowGridManager::origin() const +{ _checkReconfigure(); return _origin;} + +Qt::Orientation FlowGridManager::orientation() const +{ _checkReconfigure(); return _orientation;} + +/*Slack FlowGridManager::slackX() const +{ return _slackY;} + +Slack FlowGridManager::slackY() const +{ return _slackY;} +*/ + +bool FlowGridManager::conserveSpace() const +{ return _conserveSpace; } + + +bool FlowGridManager::isValid() const +{ _checkReconfigure(); return _valid;} + +QPoint FlowGridManager::posAtCell(int x,int y) const +{ _checkReconfigure(); + return _origin+QPoint(_gridSpacing.width()*x,_gridSpacing.height()*y); +} + +QPoint FlowGridManager::pos(int i) const +{ return posAtCell(cell(i).x(),cell(i).y()); +} + +QPoint FlowGridManager::cell(int index) const +{ _checkReconfigure(); + //assert((index>=0) && (index<_gridDim.width()*_gridDim.height())); + int x=index % _gridDim.width(), + y=index / _gridDim.width(); + return QPoint(x,y); +} + + + + +// return height if orientation is Horizontal +// return width if orientation is Vertical +int FlowGridManager::_getHH(QSize size) const +{ if (_orientation==Qt::Horizontal) + return size.height(); + return size.width(); +} + +// return height if orientation is Vertical +// return width if orientation is Horizontal +int FlowGridManager::_getWH(QSize size) const +{ if (_orientation==Qt::Horizontal) + return size.width(); + return size.height(); +} + +// swap horizontal and vertical if orientation is Vertical, otherwise return arg +QSize FlowGridManager::_swapHV(QSize hv) const +{ if (_orientation==Qt::Horizontal) + return hv; + QSize temp=hv; + temp.transpose(); + return temp; +} + + +// return the amount of slack when: +// nitems = # of items +// length = total length of space where items will be placed +// item, space, border = length of respective entities +int FlowGridManager::_slack(int nitems,int length,int item,int space,int border) const +{ return length-(2*border)-(nitems-1)*space-nitems*item;} + + +void FlowGridManager::_clear() const +{ + _borderSize=QSize(0,0); + _spaceSize=QSize(0,0); + _itemSize=QSize(0,0); + _gridDim=QSize(0,0); + _gridSpacing=QSize(0,0); + _origin=QPoint(0,0); + _frameSize=QSize(0,0); + + _dirty=false; + _valid=false; +} + + +int FlowGridManager::indexNearest(QPoint p) const +{ if (!isValid()) return -1; + QPoint c=(p-_origin)-QPoint(_spaceSize.width(),_spaceSize.height())/2; + int x=c.x()/_gridSpacing.width(), + y=c.y()/_gridSpacing.height(); + int i= x+y*_gridDim.width(); + if (i>_numItems) return -1; + return i; +} + + + +// Redistribute the boxes +void FlowGridManager::_reconfigure() const +{ if ((!_pFrameSize.isValid()) || + (!_pItemSize.isValid()) || + _numItems==0 ) { + _clear(); + return; + } + int height=_getHH(_pFrameSize), + pItemHeight=_getHH(_pItemSize), + pSpaceHeight=_getHH(_pSpaceSize), + pBorderHeight=_getHH(_pBorderSize), + spanlen=(height-2*pBorderHeight+pSpaceHeight)/(pItemHeight+pSpaceHeight); + int slack,iSlack; + + if (spanlen==0) { + _dirty=false; + _valid=false; + return; + } + // figure out the number of spans required for all items + int numspans=_numItems/spanlen; + if (numspans*spanlen<_numItems) { + numspans++; + } + + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); // total slack + iSlack=slack/spanlen; // slack per item + // Items pick up extra slack + if (_slackX==ItemSlack) pItemHeight+=iSlack; + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); + + // space picks up extra slack + if (spanlen>1) { + iSlack=slack/(spanlen+1); + pSpaceHeight+=iSlack; + } + + slack=_slack(spanlen,height,pItemHeight,pSpaceHeight,pBorderHeight); + iSlack=slack/2; + pBorderHeight+=iSlack; + if (_conserveSpace) { + _itemSize=_swapHV(QSize(_getWH(_pItemSize),pItemHeight)); + _spaceSize=_swapHV(QSize(_getWH(_pSpaceSize),pSpaceHeight)); + _borderSize=_swapHV(QSize(_getWH(_pBorderSize),pBorderHeight)); + } + else { + _itemSize=_swapHV(QSize(pItemHeight,pItemHeight)); + _spaceSize=_swapHV(QSize(pSpaceHeight,pSpaceHeight)); + _borderSize=_swapHV(QSize(pBorderHeight,pBorderHeight)); + } + _gridDim=_swapHV(QSize(numspans,spanlen)); + + _gridSpacing=_itemSize+_spaceSize; + _origin=QPoint(_borderSize.width(),_borderSize.height()); + _frameSize=2*_borderSize+QSize(_gridDim.width()*_gridSpacing.width()-_spaceSize.width(), + _gridDim.height()*_gridSpacing.height()-_spaceSize.height()); + + _dirty=false; + _valid=true; +} + + +void FlowGridManager::dump() +{ + DEBUGSTR<<endl<<flush; + + DEBUGSTR<<"_pItemSize=("<<_pItemSize.width()<<","<<_pItemSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_pSpaceSize=("<<_pSpaceSize.width()<<","<<_pSpaceSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_pBorderSize=("<<_pBorderSize.width()<<","<<_pBorderSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_pFrameSize=("<<_pFrameSize.width()<<","<<_pFrameSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_borderSize=("<<_borderSize.width()<<","<<_borderSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_spaceSize=("<<_spaceSize.width()<<","<<_spaceSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_itemSize=("<<_itemSize.width()<<","<<_itemSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_gridDim=("<<_gridDim.width()<<","<<_gridDim.height()<<")"<<endl<<flush; + DEBUGSTR<<"_gridSpacing=("<<_gridSpacing.width()<<","<<_gridSpacing.height()<<")"<<endl<<flush; + DEBUGSTR<<"_origin=("<<_origin.x()<<","<<_origin.y()<<")"<<endl<<flush; + DEBUGSTR<<"_frameSize=("<<_frameSize.width()<<","<<_frameSize.height()<<")"<<endl<<flush; + DEBUGSTR<<"_conserveSpace="<<_conserveSpace<<endl<<flush; + + DEBUGSTR<<"_orientation="<<_orientation<<endl<<flush; + DEBUGSTR<<"_numItems="<<_numItems<<endl<<flush; + DEBUGSTR<<"_slackX="<<_slackX<<endl<<flush; + DEBUGSTR<<"_slackY="<<_slackY<<endl<<flush; + DEBUGSTR<<"_dirty="<<_dirty<<endl<<flush; + DEBUGSTR<<"_valid="<<_valid<<endl<<flush; + DEBUGSTR<<endl<<flush; +} + + + +bool operator== ( const FlowGridManager & csg1, const FlowGridManager & csg2 ) +{ + return csg1.gridDim()==csg2.gridDim() && + csg1.origin()==csg2.origin() && + csg1.gridSpacing()==csg2.gridSpacing() && + csg1.frameSize()==csg2.frameSize(); +} + + + + diff --git a/kicker/applets/launcher/flowgridmanager.h b/kicker/applets/launcher/flowgridmanager.h new file mode 100644 index 000000000..9d100c74f --- /dev/null +++ b/kicker/applets/launcher/flowgridmanager.h @@ -0,0 +1,99 @@ +/* Copyright 2004, Daniel Woods Bullok <dan.devel@bullok.com> + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#ifndef __const_space_grid_h__ +#define __const_space_grid_h__ + +#include <qnamespace.h> +#include <qpoint.h> +#include <qsize.h> + + +class FlowGridManager { +// Determine if two FlowGridManager objs have the same layout. They may or +// may not have the same input parameters, but the resulting layout is identical. + friend bool operator== ( const FlowGridManager & gp1, const FlowGridManager & gp2 ); + +public: + typedef enum { + ItemSlack,SpaceSlack,BorderSlack,NoSlack + } Slack; + + FlowGridManager(QSize p_item_size=QSize(0,0), + QSize p_space_size=QSize(0,0), + QSize p_border_size=QSize(0,0), + QSize frame_size=QSize(0,0), + Qt::Orientation orient=Qt::Horizontal, + int num_items=0, + Slack slack_x=ItemSlack, + Slack slack_y=ItemSlack); + + + void setNumItems(int num_items); + void setItemSize(QSize item_size); + void setSpaceSize(QSize space_size); + void setBorderSize(QSize border_size); + void setOrientation(Qt::Orientation orient); + void setFrameSize(QSize frame_size); + void setSlack(Slack slack_x, Slack slack_y); + void setConserveSpace(bool conserve); + + + QSize itemSize() const; + QSize spaceSize() const; + QSize borderSize() const; + QSize gridDim() const; + QSize gridSpacing() const; + QSize frameSize() const; + QPoint origin() const; + Qt::Orientation orientation() const; + bool conserveSpace() const; + +// Slack slackX() const; +// Slack slackY() const; + + QPoint posAtCell(int x,int y) const; + QPoint pos(int i) const; + QPoint cell(int index) const; + bool isValid() const; + int indexNearest(QPoint p) const; + + void dump(); +protected: + int _getHH(QSize size) const; + int _getWH(QSize size) const; + QSize _swapHV(QSize hv) const; + inline void _checkReconfigure() const; + int _slack(int nitems,int length,int item,int space,int border) const; + void _reconfigure() const; + void _clear() const; + +protected: + // user-definable data + QSize _pItemSize,_pSpaceSize,_pBorderSize,_pFrameSize; + Slack _slackX, _slackY; + bool _conserveSpace; + Qt::Orientation _orientation; + int _numItems; + + // results + mutable QSize _itemSize, _spaceSize, _borderSize, _gridDim, _gridSpacing, _frameSize; + mutable QPoint _origin; + + // status + mutable bool _dirty, _valid; + +}; + + +// reconfigure the grid if necessary. +inline void FlowGridManager::_checkReconfigure() const +{ if (!_dirty) return; + _reconfigure(); +} + +#endif + diff --git a/kicker/applets/launcher/launcherapplet.kcfg b/kicker/applets/launcher/launcherapplet.kcfg new file mode 100644 index 000000000..3433bf437 --- /dev/null +++ b/kicker/applets/launcher/launcherapplet.kcfg @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile arg="true"/> + <group name="General"> + <entry name="ConserveSpace" type="Bool"> + <label>Conserve Space</label> + <default>true</default> + </entry> + <entry name="DragEnabled" type="Bool"> + <label>Drag Enabled</label> + <default>true</default> + </entry> + <entry name="IconDim" type="Int"> + <label>Icon Size</label> + <default>0</default> + </entry> + <entry name="IconDimChoices" type="IntList"> + <label>Offered Icon Sizes</label> + <default>16,20,24,28,32,48,64</default> + </entry> + <entry name="Buttons" type="StringList"> + <label>Buttons</label> + <default>kde-Home.desktop,kde-konsole.desktop,kde-KControl.desktop,kde-Help.desktop,kde-kwrite.desktop</default> + </entry> + <entry name="VolatileButtons" type="StringList"> + <label>Volatile Buttons</label> + <whatsthis>Buttons that can be removed dynamically if they become unpopular</whatsthis> + <default></default> + </entry> + <entry name="ShowVolatileButtonIndicator" type="Bool"> + <label>Show frame for volatile buttons</label> + <default>true</default> + </entry> + <entry name="AutoAdjustEnabled" type="Bool"> + <label>Auto Adjust Enabled</label> + <default>false</default> + </entry> + <entry name="AutoAdjustMinItems" type="Int"> + <label>Minimum Number of Items</label> + <min>0</min> + <default>3</default> + </entry> + <entry name="AutoAdjustMaxItems" type="Int"> + <label>Maximum Number of Items</label> + <min>0</min> + <default>6</default> + </entry> + <entry name="HistoryHorizon" type="Int"> + <label>History Weight</label> + <min>0</min> + <max>100</max> + <default>70</default> + </entry> + </group> + <group name="PopularityData"> + <entry name="ServiceCacheSize" key="ServiceCacheSize" type="Int"> + <label>Service Cache Size</label> + <whatsthis>Number of services to remember</whatsthis> + <default>500</default> + </entry> + <entry name="ServiceNames" key="ServiceNames" type="StringList"> + <label>Service Names</label> + <whatsthis>Name of known services</whatsthis> + </entry> + <entry name="ServiceInspos" key="ServiceInspos" type="IntList"> + <label>Service Insertion Positions</label> + <whatsthis>Position where services are inserted when they regain popularity</whatsthis> + </entry> + <entry name="ServiceHistories" key="ServiceHistories" type="StringList"> + <label>Service History Data</label> + <whatsthis>History Data used to determine the popularity of a service</whatsthis> + </entry> + </group> +</kcfg> diff --git a/kicker/applets/launcher/popularity.cpp b/kicker/applets/launcher/popularity.cpp new file mode 100644 index 000000000..3bfcdd872 --- /dev/null +++ b/kicker/applets/launcher/popularity.cpp @@ -0,0 +1,424 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen <kde.sch@ttgen.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "popularity.h" +#include "prefs.h" +#include <assert.h> +#include <algorithm> +#include <iterator> +#include <kconfig.h> +#include <kdebug.h> +#include <list> +#include <set> +#include <map> +#include <cmath> +#include <vector> + +using namespace std; + +class PopularityStatisticsImpl +{ +public: + struct SingleFalloffHistory + { + public: + // fallof is a number between 0 and 1. The popularity of + // each service is multiplied with the falloff value + // every time a service is used. Only the used service + // gets also 1-falloff added to its popularity. + double falloff; + // popularity values for each service + map<QString, double> vals; + // accumulated popularity of the unknown programs + // started before the statistic started + double iniVal; + }; + + struct Popularity + { + QString service; + double popularity; + bool operator<(const Popularity& p) const + { + return popularity > p.popularity; + } + }; + + PopularityStatisticsImpl(); + void normalizeHistory(SingleFalloffHistory& h); + void updateServiceRanks(); + + vector<SingleFalloffHistory> m_stats; + vector<Popularity> m_servicesByPopularity; + map<QString, int> m_serviceRanks; + double m_historyHorizon; +}; + +// ---- Public methods ---- + +PopularityStatistics::PopularityStatistics() : + d(new PopularityStatisticsImpl()) +{ +} + +PopularityStatistics::~PopularityStatistics() +{ + delete d; +} + +void PopularityStatistics::useService(const QString& service) +{ + vector<PopularityStatisticsImpl::SingleFalloffHistory>::iterator + it(d->m_stats.begin()), end(d->m_stats.end()); + for (; it != end; ++it) + { + map<QString, double>::iterator valIt; + bool found(false); + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + valIt->second = valIt->second * it->falloff; + if (valIt->first == service) + { + found = true; + valIt->second += 1-it->falloff; + } + } + it->iniVal = it->iniVal * it->falloff; + if (found == false) + { + it->vals[service] = 1-it->falloff; + } + d->normalizeHistory(*it); + } + d->updateServiceRanks(); +} + +void PopularityStatistics::moveToTop(const QStringList& newTopServiceList) +{ + vector<PopularityStatisticsImpl::SingleFalloffHistory>::iterator + histIt(d->m_stats.begin()), histEnd(d->m_stats.end()); + for (; histIt != histEnd; ++histIt) + { + set<QString> newTopServices; + for (uint n=0; n<newTopServiceList.size(); ++n) + newTopServices.insert(newTopServiceList[n]); + + // Sort by popularity + vector<PopularityStatisticsImpl::Popularity> ranking; + map<QString, double>::iterator valIt; + for (valIt = histIt->vals.begin(); valIt != histIt->vals.end(); ++valIt) + { + PopularityStatisticsImpl::Popularity pop; + pop.service = valIt->first; + pop.popularity = valIt->second; + ranking.push_back(pop); + } + stable_sort(ranking.begin(), ranking.end()); + + // Get the new positions of each service in the ranking. + // We don't touch the popularity values in the ranking. + list<QString> topServiceList, bottomServiceList; + vector<PopularityStatisticsImpl::Popularity>:: iterator rankIt; + for (rankIt = ranking.begin(); rankIt != ranking.end(); ++rankIt) + { + if (newTopServices.find(rankIt->service) != newTopServices.end()) + { + topServiceList.push_back(rankIt->service); + //kdDebug() << "top service: " << valIt->first << endl; + newTopServices.erase(rankIt->service); + } + else + { + //kdDebug() << "bottom service: " << valIt->first << endl; + bottomServiceList.push_back(rankIt->service); + } + } + // Append remaining new services to the topServices list + while (newTopServices.size() > 0) + { + topServiceList.push_back(*newTopServices.begin()); + newTopServices.erase(newTopServices.begin()); + } + + list<QString> newServiceList; + copy(topServiceList.begin(), topServiceList.end(), + back_insert_iterator<list<QString> >(newServiceList)); + copy(bottomServiceList.begin(), bottomServiceList.end(), + back_insert_iterator<list<QString> >(newServiceList)); + + // Merge the old list of service popularities + // with the new ordering of the services + histIt->vals.clear(); + list<QString>::iterator servIt; + uint serviceIndex = 0; + //kdDebug() << endl; + + for (servIt = newServiceList.begin(); servIt != newServiceList.end(); + ++servIt) + { + if (serviceIndex < ranking.size()) + { + histIt->vals[*servIt] = ranking[serviceIndex].popularity; + //kdDebug() << "->Re-Added service " << + //ranking[serviceIndex].popularity + // << " " << *servIt << endl; + //kdDebug() << "...was replaced by " << *servIt << endl; + } + else + { + //kdDebug() << "Service " << *servIt << endl; + //kdDebug() << "...was set to popularity=0" << endl; + histIt->vals[*servIt] = 0.00001; + } + // Make sure that the topServices are actually bigger than + // the bottomServices and not just bigger or equal + // and also that no services have popularity==0 + if (serviceIndex >= topServiceList.size()) + { + histIt->vals[*servIt] *= histIt->falloff; + } + ++serviceIndex; + } + d->normalizeHistory(*histIt); + } + d->updateServiceRanks(); +} + +/*v +Old version - moves everything else one position up +and 'service' to the bottom +void PopularityStatistics::moveToBottom(const QString& service) +{ + // Moves a service to the bottom of the ranking + // by moving everything else to the top + d->updateServiceRanks(); + QStringList allButOneServices; + vector<PopularityStatisticsImpl::Popularity>::iterator + it(d->m_servicesByPopularity.begin()), + end(d->m_servicesByPopularity.end()); + for (; it != end; ++it) + { + if (it->service != service) + allButOneServices << it->service; + } + moveToTop(allButOneServices); +}*/ + +void PopularityStatistics::moveToBottom(const QString& service) +{ + vector<PopularityStatisticsImpl::SingleFalloffHistory>::iterator + it(d->m_stats.begin()), end(d->m_stats.end()); + for (; it != end; ++it) + { + it->iniVal += it->vals[service]; + it->vals[service] = 0; + d->normalizeHistory(*it); + } + d->updateServiceRanks(); +} + +QString PopularityStatistics::serviceByRank(int n) const +{ + if (n >= 0 && n < int(d->m_servicesByPopularity.size())) + return d->m_servicesByPopularity[n].service; + else + return QString(); +} + +double PopularityStatistics::popularityByRank(int n) const +{ + if (n >= 0 && n < int(d->m_servicesByPopularity.size())) + return d->m_servicesByPopularity[n].popularity; + else + return 0.0; +} + +int PopularityStatistics::rankByService(const QString service) +{ + if (d->m_serviceRanks.find(service) != d->m_serviceRanks.end()) + { + return d->m_serviceRanks[service]; + } + return -1; +} + +void PopularityStatistics::writeConfig(Prefs* prefs) const +{ + QStringList serviceNames, serviceHistories; + int limit = prefs->serviceCacheSize(); + //kdDebug() << "popularityData: writeConfig" << endl; + for (int n=0; n<int(d->m_servicesByPopularity.size()) && n<limit; ++n) + { + PopularityStatisticsImpl::Popularity pop = d->m_servicesByPopularity[n]; + QStringList historyData; + for (int i=0; i<int(d->m_stats.size()); ++i) + { + historyData << QString::number(d->m_stats[i].vals[pop.service]); + } + serviceNames << pop.service; + serviceHistories << historyData.join("/"); + //kdDebug() << "popularityData: writeConfig -- " << pop.service << endl; + } + prefs->setServiceNames(serviceNames); + prefs->setServiceHistories(serviceHistories); +} + +void PopularityStatistics::readConfig(Prefs* prefs) +{ + int n = 0; + QStringList serviceNames = prefs->serviceNames(); + QStringList histories = prefs->serviceHistories(); + for (n = std::min(serviceNames.size(), histories.size())-1; n>=0; --n) + { + QString serviceName = serviceNames[n]; + QStringList serviceHistory = + QStringList::split("/", histories[n]); + for (int i=min(serviceHistory.size(), d->m_stats.size())-1; i>=0; --i) + { + d->m_stats[i].vals[serviceName] = serviceHistory[i].toDouble(); + } + } + + for (int i=0; i<int(d->m_stats.size()); ++i) + { + map<QString, double>::iterator valIt; + double valSum = 0; + for (valIt = d->m_stats[i].vals.begin(); + valIt != d->m_stats[i].vals.end(); ++valIt) + { + if (valIt->second < 0) valIt->second = 0; + valSum += valIt->second; + } + // Scale down values if their sum is bigger than 1 + // because of rounding errors or a corrupted config file + if (valSum > 1) + { + for (valIt = d->m_stats[i].vals.begin(); + valIt != d->m_stats[i].vals.end(); ++valIt) + { + valIt->second = valIt->second / valSum; + } + } + d->m_stats[i].iniVal = 1-valSum; + } + d->updateServiceRanks(); +} + +void PopularityStatistics::setHistoryHorizon(double h) +{ + d->m_historyHorizon = std::max(std::min(h, 1.0), 0.0); + d->updateServiceRanks(); +} + +double PopularityStatistics::historyHorizon() +{ + return d->m_historyHorizon; +} + + +// ---- Implementation methods ---- + +PopularityStatisticsImpl::PopularityStatisticsImpl() +{ + const int rateBaseCount(8); + + m_historyHorizon = 0.0; + + for (int n=0; n<rateBaseCount; ++n) + { + SingleFalloffHistory h; + h.falloff = 1.0 - (0.5 / std::exp(double(n)*1.5)); + m_stats.push_back(h); + } +} + +void PopularityStatisticsImpl::normalizeHistory(SingleFalloffHistory& h) +{ + //kdDebug() << "Normalize history" << endl; + double sum = h.iniVal; + map<QString, double>::iterator it; + for (it = h.vals.begin(); it != h.vals.end(); ++it) + { + sum += it->second; + } + for (it = h.vals.begin(); it != h.vals.end(); ++it) + { + it->second = it->second / sum; + } + h.iniVal = h.iniVal / sum; +} + +void PopularityStatisticsImpl::updateServiceRanks() +{ + // For each service calculate the average over the popularity + // for all falloff values and then sort by these averaged values + + vector<SingleFalloffHistory>::iterator + it(m_stats.begin()), end(m_stats.end()); + map<QString, double> serviceValSum, serviceValWeightSum; + int numStats = m_stats.size(); + for (int statIndex = 0; it != end; ++it, ++statIndex) + { + // Put more weight on the short term history if m_historyHorizon==0 + // and more on the the long term history for m_historyHorizon==1 + double a = 2*(numStats-1)*m_historyHorizon - numStats + 0.5; + if (statIndex < a || statIndex > a + numStats) + { + continue; + } + + map<QString, double>::iterator valIt; + /*double valSum = 0; + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + valSum += valIt->second; + } + if (valSum == 0) valSum = 1;*/ + for (valIt = it->vals.begin(); valIt != it->vals.end(); ++valIt) + { + serviceValWeightSum[valIt->first] += 1; + serviceValSum[valIt->first] += valIt->second; + } + } + + m_servicesByPopularity.clear(); + map<QString, double>::iterator sIt; + for (sIt = serviceValWeightSum.begin(); + sIt != serviceValWeightSum.end(); ++sIt) + { + Popularity p; + p.service = sIt->first; + assert(sIt->second > 0); + p.popularity = serviceValSum[sIt->first] / sIt->second; + m_servicesByPopularity.push_back(p); + } + stable_sort(m_servicesByPopularity.begin(), m_servicesByPopularity.end()); + m_serviceRanks.clear(); + for (uint n = 0; n < m_servicesByPopularity.size(); ++n) + { + m_serviceRanks[m_servicesByPopularity[n].service] = n; + /*kdDebug() << QString("Rank %1: %2 %3").arg(n) + .arg(m_servicesByPopularity[n].popularity) + .arg(m_servicesByPopularity[n].service) << endl;*/ + } +} diff --git a/kicker/applets/launcher/popularity.h b/kicker/applets/launcher/popularity.h new file mode 100644 index 000000000..b1dcb32d6 --- /dev/null +++ b/kicker/applets/launcher/popularity.h @@ -0,0 +1,127 @@ +/***************************************************************** + +Copyright (c) 2005 Fred Schaettgen <kde.sch@ttgen.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __popularity_h__ +#define __popularity_h__ + +#include <qstring.h> +#include <qstringlist.h> + +class PopularityStatisticsImpl; +class Prefs; + +/** + * Tracks the usage of any kind of service to offer recommendations. + * A service is identified by a string. After calling @useService + * a few times, you can get a popularity ranking for the used + * services. + * The algorithm tries to take both short- and long-term usage + * into account at the same time. + * The popularity value can be interpreted as the probability + * that the given service will be the next one to be used. + * If some new services are suddenly used a few times, their ranking + * may grow higher than the ranking of services, which were used very + * frequently a while ago. But after this short term usage has + * stopped, its influence gets weaker more quickly then for the old, + * more frequently used services. + * During first time usage, the algorithm needs some time to stabilize, + * since there is simply no dependable long term usage data available, + * so the ranking is more likely to change at first. + * But in the long run, the behaviour of the algorithm is + * completely stable, unlike simple usage counting for instance. + */ +class PopularityStatistics +{ +public: + PopularityStatistics(); + virtual ~PopularityStatistics(); + + /** + * Touch a service. This will increase the usage + * counters for the given service and decrease the + * counters for all the others. + */ + void useService(const QString& service); + + /** + * Exchange all state variables of the most + * popular service with those from services, + * moving the given services to the top of the + * list. Apart from that the order stays the same + * as before. Order of items in the string list + * does *not* matter/ + */ + void moveToTop(const QStringList& services); + + /** + * Sets all counters to zero for the given service + */ + void moveToBottom(const QString& service); + + /** + * Retrieve the name of a service by its position + * in the current popularity ranking + */ + QString serviceByRank(int n) const; + + /** + * Retrieve the popularity (0-1) of a service by + * its position in the current popularity ranking + */ + double popularityByRank(int n) const; + + /** + * Gets the rank of a given service. + * Returns -1 if the service is not in the ranking + */ + int rankByService(const QString service); + + /** + * Writes the configuration. + * A section must be set already for config. + */ + void writeConfig(Prefs* prefs) const; + + /** + * Reads the configuration. + * A section must be set already for config. + */ + void readConfig(Prefs* prefs); + + /** + * Modify the weighting of the history logs. + * 0 <= h <= 1. 1 means long term history + * 0 means short term history - in fact the popularity ranking + * becomes a recently-used list in that case. + */ + void setHistoryHorizon(double h); + double historyHorizon(); + +protected: + PopularityStatisticsImpl *d; + +private: + PopularityStatistics(const PopularityStatistics&) {} +}; + +#endif diff --git a/kicker/applets/launcher/prefs.kcfgc b/kicker/applets/launcher/prefs.kcfgc new file mode 100644 index 000000000..26a3f3d07 --- /dev/null +++ b/kicker/applets/launcher/prefs.kcfgc @@ -0,0 +1,6 @@ +# Code generation options for kconfig_compiler +File=launcherapplet.kcfg +ClassName=Prefs +Singleton=false +Mutators=AutoAdjustMaxItems,Buttons,VolatileButtons,AutoAdjustMaxItems,AutoAdjustMinItems,AutoAdjustEnabled,IconDim,DragEnabled,ConserveSpace,ServiceInspos,ServiceNames,ServiceHistories +# MemberVariables=public diff --git a/kicker/applets/launcher/quickaddappsmenu.cpp b/kicker/applets/launcher/quickaddappsmenu.cpp new file mode 100644 index 000000000..74d00a6e4 --- /dev/null +++ b/kicker/applets/launcher/quickaddappsmenu.cpp @@ -0,0 +1,67 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + based on paneladdappsmenu.cpp which is + Copyright (c) 1999-2000 the kicker authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <kstandarddirs.h> +#include <kdesktopfile.h> +#include <kglobalsettings.h> +#include <ksycocaentry.h> +#include <kservice.h> +#include <kservicegroup.h> + +#include <kdebug.h> +#include "quickaddappsmenu.h" + +QuickAddAppsMenu::QuickAddAppsMenu(const QString &label, const QString &relPath, QWidget *target, QWidget *parent, const char *name, const QString &sender) + : PanelServiceMenu(label, relPath, parent, name) +{ + _targetObject = target; + _sender = sender; + connect(this, SIGNAL(addAppBefore(QString,QString)), + target, SLOT(addAppBeforeManually(QString,QString))); +} + +QuickAddAppsMenu::QuickAddAppsMenu(QWidget *target, QWidget *parent, const QString &sender, const char *name) + : PanelServiceMenu(QString::null, QString::null, parent, name) +{ + _targetObject = target; + _sender = sender; + connect(this, SIGNAL(addAppBefore(QString,QString)), + target, SLOT(addAppBeforeManually(QString,QString))); +} + +void QuickAddAppsMenu::slotExec(int id) +{ + if (!entryMap_.contains(id)) return; + KSycocaEntry * e = entryMap_[id]; + KService::Ptr service = static_cast<KService *>(e); + emit addAppBefore(locate("apps", service->desktopEntryPath()),_sender); +} + + +PanelServiceMenu *QuickAddAppsMenu::newSubMenu(const QString &label, const QString &relPath, QWidget *parent, const char *name, const QString &insertInlineHeader) +{ + return new QuickAddAppsMenu(label, relPath, _targetObject, parent, name, _sender); +} +#include "quickaddappsmenu.moc" diff --git a/kicker/applets/launcher/quickaddappsmenu.h b/kicker/applets/launcher/quickaddappsmenu.h new file mode 100644 index 000000000..88465049c --- /dev/null +++ b/kicker/applets/launcher/quickaddappsmenu.h @@ -0,0 +1,51 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + based on paneladdappsmenu.h which is + Copyright (c) 1999-2000 the kicker authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +s +******************************************************************/ + +#ifndef __quickaddappsmenu_h__ +#define __quickaddappsmenu_h__ + +#include "service_mnu.h" + +class QuickAddAppsMenu: public PanelServiceMenu { + Q_OBJECT +public: + QuickAddAppsMenu(const QString &label, const QString &relPath, QWidget *target, QWidget *parent=0, const char *name=0, const QString &sender=QString("")); + QuickAddAppsMenu(QWidget *target, QWidget *parent=0, const QString &sender=QString(""), const char *name=0); +signals: + void addAppBefore(QString,QString); +protected slots: + virtual void slotExec(int id); +protected: + virtual PanelServiceMenu *newSubMenu(const QString &label, + const QString &relPath, + QWidget *parent, + const char *name, + const QString & _inlineHeader=QString::null); +private: + QWidget *_targetObject; + QString _sender; +}; + +#endif diff --git a/kicker/applets/launcher/quickbutton.cpp b/kicker/applets/launcher/quickbutton.cpp new file mode 100644 index 000000000..933088b04 --- /dev/null +++ b/kicker/applets/launcher/quickbutton.cpp @@ -0,0 +1,322 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "quickbutton.h" +#include "quickaddappsmenu.h" + +#include <qpainter.h> +#include <qdrawutil.h> +#include <qpopupmenu.h> +#include <qtooltip.h> + +#include <kactionclasses.h> +#include <kickertip.h> +#include <klocale.h> +#include <kdesktopfile.h> +#include <krun.h> +#include <kiconeffect.h> +#include <kglobalsettings.h> +#include <kcursor.h> +#include <kapplication.h> +#include <kipc.h> +#include <kiconloader.h> +#include <kurldrag.h> +#include <kstandarddirs.h> + +#include <math.h> +#include <algorithm> + +#ifdef DEBUG + #define DEBUGSTR kdDebug() +#else + #define DEBUGSTR kndDebug() +#endif + +QuickURL::QuickURL(const QString &u) +{ DEBUGSTR<<"QuickURL::QuickURL("<<u<<")"<<endl<<flush; + KService::Ptr _service=0; + _menuId = u; + if (_menuId.startsWith("file:") && _menuId.endsWith(".desktop")) { + // this ensures that desktop entries are referenced by desktop name instead of by file name + _menuId=KURL(_menuId).path(); + } + if (_menuId.startsWith("/")) { + // Absolute path + _kurl.setPath(_menuId); + + if (_menuId.endsWith(".desktop")) { + // Strip path + QString s = _menuId; + s = s.mid(s.findRev('/')+1); + s = s.left(s.length()-8); + _service = KService::serviceByStorageId(s); + if (!_service) { + _service = new KService(_menuId); + } else { + } + } + } else if (!KURL::isRelativeURL(_menuId)) { + // Full URL + _kurl = _menuId; + } else { + // menu-id + _service = KService::serviceByMenuId(_menuId); + } + DEBUGSTR << "QuickURL: _service='"<<_service<<" _kurl="<<_kurl<<" _menuId="<<_menuId<<endl<<flush; + + if (_service) { + if (!_service->isValid()) { + DEBUGSTR << "QuickURL: _service is not valid"<<endl<<flush; + // _service is a KShared pointer, don't try to delete it! + _service = 0; + } else { + DEBUGSTR << "QuickURL: _service='"<<_service<<"' _service->desktopEntryPath()="<<_service->desktopEntryPath()<<endl<<flush; + if (_kurl.path().length() == 0) + { + _kurl.setPath(locate("apps", _service->desktopEntryPath())); + } + if (!_service->menuId().isEmpty()) + _menuId = _service->menuId(); + + m_genericName = _service->genericName(); + m_name = _service->name(); + } + } else { + m_name = _kurl.prettyURL(); + } + DEBUGSTR<<"QuickURL::QuickURL("<<u<<") END"<<endl<<flush; +} + +void QuickURL::run() const +{ kapp->propagateSessionManager(); // is this needed? + if (_service) + KRun::run(*(_service), KURL::List()); + else + new KRun(_kurl, 0, _kurl.isLocalFile()); +} + +//similar to MimeType::pixmapForURL +QPixmap QuickURL::pixmap( mode_t _mode, KIcon::Group _group, + int _force_size, int _state, QString *) const +{ // Load icon + QPixmap pxmap = KMimeType::pixmapForURL(_kurl, _mode, _group, _force_size, _state); + // Resize to fit button + pxmap.convertFromImage(pxmap.convertToImage().smoothScale(_force_size,_force_size, QImage::ScaleMin)); + return pxmap; +} + + +QuickButton::QuickButton(const QString &u, KAction* configAction, + QWidget *parent, const char *name) : + SimpleButton(parent, name), + m_flashCounter(0), + m_sticky(false) +{ + installEventFilter(KickerTip::the()); + setMouseTracking(true); + _highlight = false; + _oldCursor = cursor(); + _qurl=new QuickURL(u); + + QToolTip::add(this, _qurl->name()); + resize(int(DEFAULT_ICON_DIM),int(DEFAULT_ICON_DIM)); + QBrush bgbrush(colorGroup().brush(QColorGroup::Background)); + + QuickAddAppsMenu *addAppsMenu = new QuickAddAppsMenu( + parent, this, _qurl->url()); + _popup = new QPopupMenu(this); + _popup->insertItem(i18n("Add Application"), addAppsMenu); + configAction->plug(_popup); + _popup->insertSeparator(); + _popup->insertItem(SmallIcon("remove"), i18n("Remove"), + this, SLOT(removeApp())); + + m_stickyAction = new KToggleAction(i18n("Never Remove Automatically"), + KShortcut(), this); + connect(m_stickyAction, SIGNAL(toggled(bool)), + this, SLOT(slotStickyToggled(bool))); + m_stickyAction->plug(_popup, 2); + m_stickyId = _popup->idAt(2); + + connect(this, SIGNAL(clicked()), SLOT(launch())); + connect(this, SIGNAL(removeApp(QuickButton *)), parent, + SLOT(removeAppManually(QuickButton *))); +} + +QuickButton::~QuickButton() +{ + delete _qurl; +} + + +QString QuickButton::url() const +{ + return _qurl->url(); +} + + +QString QuickButton::menuId() const +{ return _qurl->menuId();} + + +void QuickButton::loadIcon() +{ + // Set Icon Dimension from size + _iconDim=std::min(size().width(),size().height())-2*ICON_MARGIN; + // Load icons + _icon = _qurl->pixmap(0, KIcon::Panel, _iconDim, KIcon::DefaultState); + _iconh = _qurl->pixmap(0, KIcon::Panel, _iconDim, KIcon::ActiveState); + setPixmap(_icon); +} + +void QuickButton::resizeEvent(QResizeEvent *e) +{ + loadIcon(); + SimpleButton::resizeEvent(e); +} + +void QuickButton::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == RightButton) + _popup->popup(e->globalPos()); + else if (e->button() == LeftButton) { + _dragPos = e->pos(); + QButton::mousePressEvent(e); + } +} + +void QuickButton::mouseMoveEvent(QMouseEvent *e) +{ + if ((e->state() & LeftButton) == 0) return; + QPoint p(e->pos() - _dragPos); + if (p.manhattanLength() <= KGlobalSettings::dndEventDelay()) + return; + DEBUGSTR<<"dragstart"<<endl<<flush; + setDown(false); + if (_dragEnabled) { + KURL::List uris; + uris.append(_qurl->kurl()); + DEBUGSTR<<"creating KURLDrag"<<endl<<flush; + KURLDrag *dd = new KURLDrag(uris,this); + dd->setPixmap(_icon); //PIX + DEBUGSTR<<"ready to drag"<<endl<<flush; + grabKeyboard(); + dd->drag(); + releaseKeyboard(); + } else { + setCursor(Qt::ForbiddenCursor); + } +} + +void QuickButton::slotIconChanged(int group) +{ + loadIcon(); + SimpleButton::slotIconChanged(group); + update(); +} + +void QuickButton::launch() +{ + setDown(false); + update(); + KIconEffect::visualActivate(this, rect()); + _qurl->run(); + emit executed(_qurl->menuId()); +} + +void QuickButton::setDragging(bool enable) +{ + setDown(enable); + _highlight=enable; + update(); +} + +void QuickButton::setEnableDrag(bool enable) +{ + _dragEnabled=enable; +} + +void QuickButton::removeApp() +{ + emit removeApp(this); +} + +void QuickButton::flash() +{ + m_flashCounter = 2000; + QTimer::singleShot(0, this, SLOT(slotFlash())); +} + +void QuickButton::slotFlash() +{ + static const int timeout = 500/4; + if (m_flashCounter > 0) + { + m_flashCounter -= timeout; + if (m_flashCounter < 0) m_flashCounter = 0; + update(); + QTimer::singleShot(timeout, this, SLOT(slotFlash())); + } +} + +void QuickButton::slotStickyToggled(bool isSticky) +{ + m_sticky = isSticky; + emit stickyToggled(isSticky); +} + +void QuickButton::setSticky(bool sticky) +{ + m_stickyAction->setChecked(sticky); + slotStickyToggled(sticky); +} + +void QuickButton::updateKickerTip(KickerTip::Data &data) +{ + if (!_qurl) + { + return; + } + data.message = _qurl->name(); + data.direction = m_popupDirection; + data.subtext = _qurl->genericName(); + if (data.subtext == QString()) + { + data.subtext = data.message; + } + data.icon = KMimeType::pixmapForURL(_qurl->kurl(), 0, + KIcon::Panel, KIcon::SizeHuge, KIcon::DefaultState); +} + +void QuickButton::setPopupDirection(KPanelApplet::Direction d) +{ + m_popupDirection = d; +} + +void QuickButton::setDynamicModeEnabled(bool enabled) +{ + _popup->setItemVisible(m_stickyId, enabled); +} + + +#include "quickbutton.moc" diff --git a/kicker/applets/launcher/quickbutton.h b/kicker/applets/launcher/quickbutton.h new file mode 100644 index 000000000..98eabec6e --- /dev/null +++ b/kicker/applets/launcher/quickbutton.h @@ -0,0 +1,124 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __quickbutton_h__ +#define __quickbutton_h__ + +#include <qbutton.h> +#include <qpoint.h> +#include <qstring.h> +#include <qpixmap.h> +#include <qcursor.h> + +#include <kickertip.h> +#include <kicontheme.h> +#include <kmimetype.h> +#include <kpanelapplet.h> +#include <kservice.h> +#include <kurl.h> + +#include "simplebutton.h" + +class QPopupMenu; +class KAction; +class KToggleAction; + +class QuickURL { +public: + QuickURL(const QString &u); + KURL kurl() const {return _kurl;}; + QString url() const {return _kurl.url();}; + QString menuId() const {return _menuId;}; + QString genericName() const { return m_genericName; } + QString name() const { return m_name; } + KService::Ptr service() const {return _service;}; + void run() const; + QPixmap pixmap(mode_t _mode = 0, KIcon::Group _group = KIcon::Desktop, + int _force_size = 0, int _state = 0, QString * _path = 0L) const; + +private: + KURL _kurl; + QString _menuId; + QString m_genericName; + QString m_name; + KService::Ptr _service; +}; + + +class QuickButton: public SimpleButton, public KickerTip::Client { + Q_OBJECT + +public: + enum { DEFAULT_ICON_DIM = 16 }; + enum { ICON_MARGIN = 1 }; + QuickButton(const QString &u, KAction* configAction, + QWidget *parent=0, const char *name=0); + ~QuickButton(); + QString url() const; + QString menuId() const; + QPixmap icon() const{ return _icon;} + bool sticky() { return m_sticky; } + void setSticky(bool bSticky); + void setPopupDirection(KPanelApplet::Direction d); + + void setDragging(bool drag); + void setEnableDrag(bool enable); + void setDynamicModeEnabled(bool enabled); + void flash(); + +signals: + void removeApp(QuickButton *); + void executed(QString serviceStorageID); + void stickyToggled(bool isSticky); + +protected: + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *rsevent); + void loadIcon(); + void updateKickerTip(KickerTip::Data &data); + +protected slots: + void slotIconChanged(int); + void launch(); + void removeApp(); + void slotFlash(); + void slotStickyToggled(bool isSticky); + +private: + int m_flashCounter; + QuickURL *_qurl; + QPoint _dragPos; + QPopupMenu *_popup; + QPixmap _icon, _iconh; + QCursor _oldCursor; + bool _highlight, _changeCursorOverItem, _dragEnabled; + int _iconDim; + bool m_sticky; + KToggleAction *m_stickyAction; + int m_stickyId; + KPanelApplet::Direction m_popupDirection; +}; + +#endif + diff --git a/kicker/applets/launcher/quickbuttongroup.h b/kicker/applets/launcher/quickbuttongroup.h new file mode 100644 index 000000000..1d373ae92 --- /dev/null +++ b/kicker/applets/launcher/quickbuttongroup.h @@ -0,0 +1,60 @@ +/* Copyright 2004, Daniel Woods Bullok <dan.devel@bullok.com> + distributed under the terms of the + GNU GENERAL PUBLIC LICENSE Version 2 - + See the file kdebase/COPYING for details +*/ + +#ifndef __quickbuttongroup_h__ +#define __quickbuttongroup_h__ + +#include <qstring.h> +#include <functional> +#include "easyvector.h" +#include "quickbutton.h" + + +class QuickButtonGroup: virtual public EasyVector< QuickButton* > { +public: + QuickButtonGroup(const EasyVector< QuickButton* > &kv):EasyVector< QuickButton* >(kv){}; + QuickButtonGroup():EasyVector< QuickButton* >(){}; + Index findDescriptor(const QString &desc); + + void show(); + void hide(); + void setDragging(bool drag); + void setEnableDrag(bool enable); + void deleteContents(); + void setUpdatesEnabled(bool enable); +}; + +QuickButtonGroup::Index QuickButtonGroup::findDescriptor(const QString &desc) +{ return findProperty(desc, std::mem_fun(&QuickButton::url));} + +inline void QuickButtonGroup::setUpdatesEnabled(bool enable) +{ for (QuickButtonGroup::iterator i=begin();i!=end();++i) { + (*i)->setUpdatesEnabled(enable); + if (enable) { (*i)->update();} + } +} + +inline void QuickButtonGroup::show() +{ std::for_each(begin(),end(),std::mem_fun(&QWidget::show));} + +inline void QuickButtonGroup::hide() +{ std::for_each(begin(),end(),std::mem_fun(&QWidget::hide));} + +inline void QuickButtonGroup::setDragging(bool drag) +{ std::for_each(begin(),end(),std::bind2nd(std::mem_fun(&QuickButton::setDragging),drag));} + +inline void QuickButtonGroup::setEnableDrag(bool enable) +{ std::for_each(begin(),end(),std::bind2nd(std::mem_fun(&QuickButton::setEnableDrag),enable));} + +inline void QuickButtonGroup::deleteContents() +{ for (QuickButtonGroup::iterator i=begin();i!=end();++i) { + delete (*i); + (*i)=0; + } +} + +#endif + diff --git a/kicker/applets/launcher/quicklauncher.cpp b/kicker/applets/launcher/quicklauncher.cpp new file mode 100644 index 000000000..abae9efe1 --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.cpp @@ -0,0 +1,1093 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel +Copyright (c) 2004 Dan Bullok <dan.devel@bullok.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qslider.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <dcopclient.h> +#include <kaction.h> +#include <kapplication.h> +#include <kaboutapplication.h> +#include <kaboutdata.h> +#include <kdialogbase.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <knuminput.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kurldrag.h> +#include <kdebug.h> + + +#include <algorithm> +#include <list> +#include <math.h> +#include <set> +#include <assert.h> + +#include "configdlg.h" +#include "popularity.h" +#include "quicklauncher.h" +#include "quickbutton.h" +#include "quickaddappsmenu.h" +#include "quickbuttongroup.h" + +typedef ButtonGroup::iterator ButtonIter; +const ButtonGroup::Index NotFound=ButtonGroup::NotFound; +const ButtonGroup::Index Append=ButtonGroup::Append; + +#ifdef DEBUG + #define DEBUGSTR kdDebug() +#else + #define DEBUGSTR kndDebug() +#endif + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("quicklauncher"); + return new QuickLauncher(configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, + parent, "quicklauncher"); + } +} + +QuickLauncher::QuickLauncher(const QString& configFile, Type type, int actions, + QWidget *parent, const char *name) : + KPanelApplet(configFile, type, actions, parent, name) +{ + DCOPObject::setObjId("QuickLauncherApplet"); + DEBUGSTR << endl << endl << endl << "------------" << flush; + DEBUGSTR << "QuickLauncher::QuickLauncher(" << configFile << ",...)" << + endl << flush; + + m_settings = new Prefs(sharedConfig()); + m_settings->readConfig(); + + m_needsSave = false; + m_needsRefresh = false; + m_refreshEnabled = false; + + m_configDialog = 0; + m_popup = 0; + m_appletPopup = 0; + m_removeAppsMenu = 0; + + m_dragAccepted = false; + + m_buttons = new ButtonGroup; + m_manager = new FlowGridManager; + m_newButtons = 0; + m_oldButtons = 0; + m_dragButtons = 0; + + m_configAction = new KAction(i18n("Configure Quicklauncher..."), "configure", KShortcut(), + this, SLOT(slotConfigure()), this); + + m_saveTimer = new QTimer(this); + connect(m_saveTimer, SIGNAL(timeout()), this, SLOT(saveConfig())); + + m_popularity = new PopularityStatistics(); + + setBackgroundOrigin(AncestorOrigin); + + loadConfig(); + + buildPopupMenu(); + m_minPanelDim = std::max(16, m_settings->iconDimChoices()[1]); + refreshContents(); + setRefreshEnabled(true); + + setAcceptDrops(true); + //QToolTip::add(this, i18n("Drop applications here")); + DEBUGSTR << " QuickLauncher::QuickLauncher(" << configFile << + ",...) END" << endl << flush; + + DCOPClient *dcopClient = KApplication::dcopClient(); + dcopClient->connectDCOPSignal(0, "appLauncher", + "serviceStartedByStorageId(QString,QString)", + "QuickLauncherApplet", + "serviceStartedByStorageId(QString,QString)", + false); + kdDebug() << "Quicklauncher registered DCOP signal" << endl; +} + + +//TODO:? Drag/drop more than one item at a time + +QuickLauncher::~QuickLauncher() +{ + KGlobal::locale()->removeCatalogue("quicklauncher"); + setCustomMenu(0); + delete m_popup; + delete m_appletPopup; + delete m_removeAppsMenu; + delete m_popularity; + clearTempButtons(); + if (m_buttons) + { + m_buttons->deleteContents(); + delete m_buttons; + } +} + +// Builds, connects _popup menu +void QuickLauncher::buildPopupMenu() +{ + QuickAddAppsMenu *addAppsMenu = new QuickAddAppsMenu(this, this); + m_popup = new QPopupMenu(this); + m_popup->insertItem(i18n("Add Application"), addAppsMenu); + m_configAction->plug(m_popup); + + m_appletPopup = new QPopupMenu(this); + m_appletPopup->insertItem(i18n("Add Application"), addAppsMenu); + m_removeAppsMenu = new QPopupMenu(this); + connect(m_removeAppsMenu, SIGNAL(aboutToShow()), + SLOT(fillRemoveAppsMenu())); + connect(m_removeAppsMenu, SIGNAL(activated(int)), + SLOT(removeAppManually(int))); + m_appletPopup->insertItem(i18n("Remove Application"), m_removeAppsMenu); + + m_appletPopup->insertSeparator(); + m_appletPopup->setCheckable( true ); + m_appletPopup->insertItem(i18n("About"), this, SLOT(about())); + setCustomMenu(m_appletPopup); +} + + +// Fill the remove apps menu +void QuickLauncher::fillRemoveAppsMenu() +{ + m_removeAppsMenu->clear(); + ButtonIter iter(m_buttons->begin()); + int i = 0; + while (iter != m_buttons->end()) + { + QString text = QToolTip::textFor(*iter); + if (text.isEmpty()) + { + text = (*iter)->url(); + if (text.isEmpty()) + { + text = i18n("Unknown"); + } + } + m_removeAppsMenu->insertItem((*iter)->icon(), text, i); + ++iter; + ++i; + } +} + +void QuickLauncher::slotSettingsDialogChanged() +{ + // Update conserve space setting + setConserveSpace(m_settings->conserveSpace()); + m_popularity->setHistoryHorizon(m_settings->historyHorizon()/100.0); + slotAdjustToCurrentPopularity(); + kdDebug() << "Icon size: " << m_settings->iconDim() << endl; + refreshContents(); + + saveConfig(); +} + +void QuickLauncher::action(Action a) +{ + if (a == KPanelApplet::Preferences) + { + slotConfigure(); + } + else + { + KPanelApplet::action(a); + } +} + +void QuickLauncher::slotConfigure() +{ + if (!m_configDialog) + { + m_configDialog = new ConfigDlg(this, "configdialog", + m_settings, SIZE_AUTO, KDialogBase::Plain, KDialogBase::Ok | + KDialogBase::Cancel | KDialogBase::Apply | KDialogBase::Default); + connect(m_configDialog, SIGNAL(settingsChanged()), + this, SLOT(slotSettingsDialogChanged())); + } + + m_configDialog->show(); +} + + +int QuickLauncher::findApp(QuickButton *button) +{ + if (m_buttons->empty()) + { + return NotFound; + } + int pos = m_buttons->findValue(button); + return pos; +} + + +int QuickLauncher::findApp(QString url) +{ + if (m_buttons->empty()) + { + return NotFound; + } + int pos=m_buttons->findDescriptor(url); + return pos; +} + +void QuickLauncher::removeAppManually(int index) +{ + removeApp(index, true); +} + +void QuickLauncher::removeApp(int index, bool manuallyRemoved) +{ + if (m_buttons->empty()) + { + return; + } + if (!m_buttons->isValidIndex(index)) + { + kdWarning() << " removeApp (" << index << + ") *******WARNING****** index=" << index << "is out of bounds." << + endl << flush; + return; + } + DEBUGSTR << "Removing button. index=" << index << " url='" << + (*m_buttons)[index]->url() << "'" << endl << flush; + + QString removeAppUrl = (*m_buttons)[index]->url(); + QString removeAppMenuId = (*m_buttons)[index]->menuId(); + + delete (*m_buttons)[index]; + m_buttons->eraseAt(index); + refreshContents(); + + if (int(m_buttons->size()) < m_settings->autoAdjustMinItems() && manuallyRemoved) + { + m_settings->setAutoAdjustMinItems(m_buttons->size()); + } + + if (manuallyRemoved) + { + m_popularity->moveToBottom(removeAppMenuId); + slotAdjustToCurrentPopularity(); + } + + saveConfig(); +} + + +void QuickLauncher::removeApp(QString url, bool manuallyRemoved) +{ + int index = findApp(url); + if (index == NotFound) + { + kdDebug() << "removeApp: Not found: " << url << endl; + return; + } + removeApp(index, manuallyRemoved); +} + + +void QuickLauncher::removeAppManually(QuickButton *button) +{ + int index = findApp(button); + if (index == NotFound) + { + return; + } + removeApp(index, true); +} + + +int QuickLauncher::widthForHeight(int h) const +{ + FlowGridManager temp_manager = *m_manager; + temp_manager.setFrameSize(QSize(h,h)); + temp_manager.setOrientation(Qt::Horizontal); // ??? probably not necessary + if (temp_manager.isValid()) + { + return temp_manager.frameSize().width(); + } + return m_minPanelDim; +} + + +int QuickLauncher::heightForWidth(int w) const +{ + FlowGridManager temp_manager=*m_manager; + temp_manager.setFrameSize(QSize(w,w)); + temp_manager.setOrientation(Qt::Vertical); // ??? probably not necessary + if (temp_manager.isValid()) + { + return temp_manager.frameSize().height(); + } + return m_minPanelDim; +} + + +int QuickLauncher::dimension() const +{ + if (orientation()==Qt::Vertical) + { + return size().width(); + } + return size().height(); +} + +void QuickLauncher::addApp(QString url, bool manuallyAdded) +{ + assert(m_buttons); + QString newButtonId = QuickURL(url).menuId(); + if (m_appOrdering.find(newButtonId) == m_appOrdering.end()) + { + m_appOrdering[newButtonId] = m_appOrdering.size(); + } + uint appPos; + for (appPos = 0; appPos < m_buttons->size(); ++appPos) + { + QString buttonId = (*m_buttons)[appPos]->menuId(); + if (m_appOrdering[buttonId] >= m_appOrdering[newButtonId]) + { + break; + } + } + addApp(url, appPos, manuallyAdded); +} + +QuickButton* QuickLauncher::createButton(QString url) +{ + QuickButton* newButton=new QuickButton(url, m_configAction, this); + connect(newButton, SIGNAL(executed(QString)), + this, SLOT(slotOwnServiceExecuted(QString))); + connect(newButton, SIGNAL(stickyToggled(bool)), + this, SLOT(slotStickyToggled())); + newButton->setPopupDirection(popupDirection()); + return newButton; +} + +void QuickLauncher::addApp(QString url, int index, bool manuallyAdded) +{ + DEBUGSTR << endl <<"About to add: url='" << url << + "' index=" << index << endl << flush; + QuickButton *newButton; + if (!m_buttons->isValidInsertIndex(index)) + { + kdWarning() << " *******WARNING****** index=" << index << + "is out of bounds." << endl << flush; + index = m_buttons->lastIndex(); + } + int old = findApp(QuickURL(url).url()); + if (old != NotFound) + { + if (index == old) + { + return; + } + if (index > old) + { + index--; + } + newButton = (*m_buttons)[old]; + m_buttons->eraseAt(old); + } + else + { + newButton = createButton(url); + } + m_buttons->insertAt(index, newButton); + DEBUGSTR << "Added: url='"<<url<<"' index="<<index<<endl<<endl<<flush; + refreshContents(); + + if (manuallyAdded) + { + newButton->setSticky(true); + if (int(m_buttons->size()) > m_settings->autoAdjustMaxItems()) + { + m_settings->setAutoAdjustMaxItems(m_buttons->size()); + } + } + + updateInsertionPosToStatusQuo(); + saveConfig(); +} + +void QuickLauncher::updateInsertionPosToStatusQuo() +{ + // Update the app ordering map, so that next time, + // addApp(url,manAdded) (without index) will insert the + // item at the same position again. + std::list<QString> appList; + std::set<int> posList; + //kdDebug() << "Rearranging application order. Before:" << endl; + for (uint n = 0; n < m_buttons->size(); ++n) + { + QString buttonId = (*m_buttons)[n]->menuId(); + appList.push_back(buttonId); + if (m_appOrdering.find(buttonId) == m_appOrdering.end()) + { + m_appOrdering[buttonId] = m_appOrdering.size(); + } + posList.insert(m_appOrdering[buttonId]); + //kdDebug() << m_appOrdering[buttonId] << " = " << buttonId << endl; + } + //kdDebug() << "After:" << endl; + while (posList.size() > 0) + { + assert(appList.size() > 0); + m_appOrdering[*appList.begin()] = *posList.begin(); + kdDebug() << *posList.begin() << " = " << *appList.begin() << endl; + posList.erase(posList.begin()); + appList.pop_front(); + } + //kdDebug() << "Done." << endl; +} + +void QuickLauncher::addAppBeforeManually(QString url, QString sender) +{ + if (sender.isNull()) + { + addApp(url, Append, true); + } + int pos = findApp(sender); + if (pos < 0) + { + pos = Append; + } + DEBUGSTR << "QuickLauncher::addAppBefore(" << url << + "," << sender << "): pos=" << pos << endl << flush; + addApp(url, pos, true); +} + + +void QuickLauncher::about() +{ + KAboutData about("quicklauncher", I18N_NOOP("Quick Launcher"), "2.0", + I18N_NOOP("A simple application launcher"), + KAboutData::License_GPL_V2, + "(C) 2000 Bill Nagel\n(C) 2004 Dan Bullok\n(C) 2005 Fred Schaettgen"); + KAboutApplication a(&about, this); + a.exec(); +} + + +void QuickLauncher::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == RightButton) + { + m_popup->popup(e->globalPos()); + } +} + +void QuickLauncher::resizeEvent(QResizeEvent*) +{ + refreshContents(); +} + +void QuickLauncher::dragEnterEvent(QDragEnterEvent *e) +{ + DEBUGSTR << "QuickLauncher::dragEnterEvent(pos=" << e->pos() << + " type=" << e->type() << ")" << endl << flush; + m_dragAccepted=false; + KURL::List kurlList; + if (!isDragEnabled() || !KURLDrag::decode(e, kurlList)) + { + e->accept(false); + return; + } + + if (kurlList.size()<=0) + { + e->accept(false); + return; + } + m_dragButtons=new ButtonGroup; + m_oldButtons=new ButtonGroup(*m_buttons); + + QString url; + KURL::List::ConstIterator it = kurlList.begin(); + for ( ; it != kurlList.end(); ++it ) + { + url = QuickURL((*it).url()).url(); + kdDebug() << " Drag Object='"<<url<<"' " << (*it).url() << endl; + int pos = m_buttons->findDescriptor(url); + if (pos != NotFound) + { + // if it's already in m_buttons, take it out + m_dragButtons->push_back(m_buttons->takeFrom(pos)); + } + else + { + // otherwise, create a new one + QuickButton* button = createButton(url); + button->setSticky(true); + m_dragButtons->push_back(button); + } + } + if (m_dragButtons->size() > 0) + { + //make sure we can drag at least one button. + m_dragAccepted=true; + m_newButtons=new ButtonGroup(*m_buttons); + m_dropPos=NotFound; + e->accept(true); + return; + } + e->accept(false); + clearTempButtons(); +} + + +void QuickLauncher::dragMoveEvent(QDragMoveEvent *e) +{ + if (!m_dragAccepted) + { + kdWarning() << "QuickLauncher::dragMoveEvent: Drag is not accepted." << + m_dragAccepted << endl << flush; + e->accept(false); + return; + } + + e->accept(true); + int pos=m_manager->indexNearest(e->pos()); + if (pos == m_dropPos) + { + return;// Already been inserted here, no need to update + } + + if (m_newButtons->isValidInsertIndex(pos)) + { + mergeButtons(pos); + m_dropPos=pos; + } + refreshContents(); +} + + +void QuickLauncher::dragLeaveEvent(QDragLeaveEvent *e) +{ + DEBUGSTR << "QuickLauncher::dragLeaveEvent(type=" << + e->type() << ")" << endl << flush; + if (!m_dragAccepted) + { + return; + } + + // No drop. Return to starting state. + std::swap(m_buttons,m_oldButtons); + clearTempButtons(); + + refreshContents(); + saveConfig(); +} + + +void QuickLauncher::dropEvent(QDropEvent *e) +{ + DEBUGSTR << "QuickLauncher::dropEvent(pos=" << e->pos() << + " type=" << e->type() << ")" << endl << flush; + if (!m_dragAccepted) + { + e->accept(false); + return; + } + + if (e->source() == 0) + { + for (uint n=0; n<m_dragButtons->size(); ++n) + { + (*m_dragButtons)[n]->setSticky(true); + } + } + + clearTempButtons(); + refreshContents(); + saveConfig(); + updateInsertionPosToStatusQuo(); +} + +// insert dragbuttons at index in m_newButtons. Put result in m_buttons +void QuickLauncher::mergeButtons(int index) +{ + if (!m_newButtons->isValidInsertIndex(index)) + { + index=m_newButtons->size(); + } + + m_buttons->clear(); + (*m_buttons) = (*m_newButtons); + m_buttons->insertAt(index, *m_dragButtons); + refreshContents(); +} + +void QuickLauncher::clearTempButtons() +{ + std::set<QuickButton*> allButtons; + //put all the m_buttons in a set (removes duplicates automatically + if (m_newButtons) + { + allButtons.insert(m_newButtons->begin(),m_newButtons->end()); + } + if (m_oldButtons) + { + allButtons.insert(m_oldButtons->begin(),m_oldButtons->end()); + } + if (m_dragButtons) + { + allButtons.insert(m_dragButtons->begin(),m_dragButtons->end()); + } + + //delete temp ButtonGroups + delete m_newButtons; m_newButtons=0; + delete m_oldButtons; m_oldButtons=0; + delete m_dragButtons; m_dragButtons=0; + + //if an element allButtons is NOT in m_buttons (the ones we keep), delete it + std::set<QuickButton *>::iterator iter = allButtons.begin(); + while (iter != allButtons.end()) + { + if (findApp(*iter) == NotFound) + { + delete *iter; + } + ++iter; + } + m_dragAccepted = false; + m_dropPos = NotFound; +} + +void QuickLauncher::refreshContents() +{ + int idim, d(dimension()); + // determine button size + if (m_settings->iconDim() == SIZE_AUTO) + { + if (d < 18) + { + idim = std::min(16,d); + } + else if (d < 64) + { + idim = 16; + } + else if (d < 80) + { + idim = 20; + } + else if (d < 122) + { + idim = 24; + } + else + { + idim = 28; + } + } + else + { + idim = std::min(m_settings->iconDim(), d - std::max((d/8)-1, 0) * 2); + } + m_space = std::max((idim/8)-1, 0); + m_border = m_space; + m_buttonSize = QSize(idim, idim); + m_manager->setOrientation(orientation()); + m_manager->setNumItems(m_buttons->size()); + m_manager->setFrameSize(size()); + m_manager->setItemSize(m_buttonSize); + m_manager->setSpaceSize(QSize(m_space, m_space)); + m_manager->setBorderSize(QSize(m_border, m_border)); + if (!m_refreshEnabled) + { + m_needsRefresh=true; + return; + } + if (!m_manager->isValid()) + { + kdDebug()<<endl<<"******WARNING****** Layout is invalid."<< + endl << flush; + m_manager->dump(); + return; + } + + unsigned index; + QPoint pos; + setUpdatesEnabled(false); + m_buttons->setUpdatesEnabled(false); + for (index = 0; index < m_buttons->size(); index++) + { + pos = m_manager->pos(index); + QuickButton *button = (*m_buttons)[index]; + button->resize(m_manager->itemSize()); + button->move(pos.x(), pos.y()); + button->setDragging(false); + button->setEnableDrag(isDragEnabled()); + button->setDynamicModeEnabled(m_settings->autoAdjustEnabled()); + } + if (m_newButtons) + { + m_newButtons->setDragging(false); + } + if (m_dragButtons) + { + m_dragButtons->setDragging(true); + } + m_buttons->show(); + setUpdatesEnabled(true); + update(); + m_buttons->setUpdatesEnabled(true); + updateGeometry(); + emit updateLayout(); + updateStickyHighlightLayer(); +} + + +void QuickLauncher::setDragEnabled(bool enable) +{ + m_settings->setDragEnabled(enable); +} + +void QuickLauncher::setConserveSpace(bool conserve_space) +{ + m_manager->setConserveSpace(conserve_space); + if (conserve_space) + { + m_manager->setSlack(FlowGridManager::SpaceSlack, + FlowGridManager::SpaceSlack); + } + else + { + m_manager->setSlack(FlowGridManager::ItemSlack, + FlowGridManager::ItemSlack); + } + refreshContents(); +} + +class SortByPopularity { +public: + bool operator()(const QuickLauncher::PopularityInfo& a, + const QuickLauncher::PopularityInfo& b) + { + return a.popularity < b.popularity; + } +}; + +void QuickLauncher::loadConfig() +{ + DEBUGSTR << "QuickLauncher::loadConfig()" << endl << flush; + //KConfig *c = config(); + //c->setGroup("General"); + setConserveSpace(m_settings->conserveSpace()); + setDragEnabled(m_settings->dragEnabled()); + /*DEBUGSTR << " IconDim="<<m_iconDim << endl << flush; + DEBUGSTR << " ConserveSpace=" << (m_manager->conserveSpace()) << + endl << flush; + DEBUGSTR << " DragEnabled=" << isDragEnabled() << endl << flush;*/ + QStringList volatileButtons = m_settings->volatileButtons(); + QStringList urls = m_settings->buttons(); + kdDebug() << "GetButtons " << urls.join("/") << endl; + QStringList::Iterator iter(urls.begin()); + int n = 0; + while (iter != urls.end()) { + QString url = *iter; + addApp(url, n, false); + ++iter; + ++n; + } + + // Restore sticky state + for (n=0; n<int(m_buttons->size()); ++n) + { + QuickButton* button = (*m_buttons)[n]; + if (volatileButtons.contains(button->menuId()) == false) + { + button->setSticky(true); + } + button->setDynamicModeEnabled(m_settings->autoAdjustEnabled()); + } + + m_popularity->readConfig(m_settings); + m_popularity->setHistoryHorizon(m_settings->historyHorizon()/100.0); + + QStringList serviceNames = m_settings->serviceNames(); + QValueList<int> insPos = m_settings->serviceInspos(); + for (int n=std::min(serviceNames.size(),insPos.size())-1; n>=0; --n) + { + m_appOrdering[serviceNames[n]] = insPos[n]; + } +} + +void QuickLauncher::saveConfig() +{ + if (!m_refreshEnabled) + { + m_needsSave=true; + return; + } + QStringList urls, volatileUrls; + ButtonIter iter = m_buttons->begin(); + while (iter != m_buttons->end()) { + if ((*iter)->sticky() == false) + { + volatileUrls.append((*iter)->menuId()); + } + urls.append((*iter)->menuId()); + ++iter; + } + m_settings->setButtons(urls); + kdDebug() << "SetButtons " << urls.join("/") << endl; + m_settings->setVolatileButtons(volatileUrls); + m_settings->setConserveSpace(m_manager->conserveSpace()); + m_settings->setDragEnabled(isDragEnabled()); + + m_popularity->writeConfig(m_settings); + + // m_popularity must have written the current service list by now + QStringList serviceNames = m_settings->serviceNames(); + QValueList<int> insertionPositions; + for (int n=0; n<int(serviceNames.size()); ++n) + { + if (m_appOrdering.find(serviceNames[n]) != m_appOrdering.end()) + { + insertionPositions.push_back(m_appOrdering[serviceNames[n]]); + } + } + m_settings->setServiceInspos(insertionPositions); + + m_settings->writeConfig(); +} + + +void QuickLauncher::setRefreshEnabled(bool enable) +{ + m_refreshEnabled=enable; + if (m_refreshEnabled) + { + if (m_needsSave) { + saveConfig(); + } + if (m_needsRefresh) { + refreshContents(); + } + } +} + +void QuickLauncher::serviceStartedByStorageId(QString /*starter*/, QString storageId) +{ + KService::Ptr service = KService::serviceByStorageId(storageId); + if (service->icon() == QString::null) + { + kdDebug() << storageId << " has no icon. Makes no sense to add it."; + return; + } + QuickURL url = QuickURL(locate("apps", service->desktopEntryPath())); + QString desktopMenuId(url.menuId()); + kdDebug() << "storageId=" << storageId << " desktopURL=" << desktopMenuId << endl; + // A service was started somwhere else. If the quicklauncher contains + // this service too, we flash the icon + QuickButton *startedButton = 0; + std::set<QString> buttonIdSet; + for (uint n = 0; n < m_buttons->size(); ++n) + { + QuickButton *button = (*m_buttons)[n]; + QString buttonMenuId = button->menuId(); + buttonIdSet.insert(buttonMenuId); + if (desktopMenuId == buttonMenuId) + { + kdDebug() << "QuickLauncher: I know that one: " << storageId << endl; + button->flash(); + startedButton = button; + } + } + + // Update popularity info. + // We do this even if autoadjust is disabled + // so there are sane values to start with if it's turned on. + m_popularity->useService(desktopMenuId); + + if (m_settings->autoAdjustEnabled()) + { + QTimer::singleShot(0, this, SLOT(slotAdjustToCurrentPopularity())); + } +} + +void QuickLauncher::slotAdjustToCurrentPopularity() +{ + // TODO: Shrink immediately if buttons->size() > maxItems + kdDebug() << "Starting popularity update" << endl; + PopularityStatistics* stats = m_popularity; + int minItems = m_settings->autoAdjustMinItems(); + int maxItems = m_settings->autoAdjustMaxItems(); + + static const double hysteresisFactor = 0.90; + double minAddPopularity = 0; + for (int n = 0; n < maxItems; ++n) + { + // All items with a popularity not less than 0.75 of the average + // of the first maxItems apps are included in the list + double belowAvgAllowed = 0.75; + minAddPopularity += (belowAvgAllowed * stats->popularityByRank(n)) / maxItems; + } + double minDelPopularity = minAddPopularity * hysteresisFactor; + std::map<QString, QuickButton*> removeableApps; + std::set<QString> existingApps; + int numApps = m_buttons->size(); + for (int n = 0; n < int(m_buttons->size()); ++n) + { + QuickButton *button = (*m_buttons)[n]; + if (((stats->popularityByRank(stats->rankByService(button->menuId())) < + minDelPopularity) || m_settings->autoAdjustEnabled()==false) && + (button->sticky() == false)) + { + removeableApps[button->menuId()] = button; + --numApps; + } + existingApps.insert(button->menuId()); + } + for (int n = 0; + (numApps < minItems && stats->popularityByRank(n) > 0) || + (numApps < maxItems && stats->popularityByRank(n) > minAddPopularity); + ++n) + { + QString app = m_popularity->serviceByRank(n); + if (existingApps.find(app) == existingApps.end()) + { + addApp(QuickURL(m_popularity->serviceByRank(n)).url(), false); + kdDebug() << "Adding app " << app << endl; + ++numApps; + } + else if (removeableApps.find(app) != removeableApps.end()) + { + removeableApps.erase(app); + ++numApps; + } + } + while (removeableApps.size() > 0) + { + removeApp(findApp(removeableApps.begin()->second), false); + kdDebug() << "Removing app " << removeableApps.begin()->first << endl; + removeableApps.erase(removeableApps.begin()->first); + } + kdDebug() << "done popularity update" << endl; + m_settings->setAutoAdjustMinItems(minItems); + m_settings->setAutoAdjustMaxItems(maxItems); + + // TODO: Think of something better than that: + m_saveTimer->start(10000,true); +} + +void QuickLauncher::slotOwnServiceExecuted(QString serviceMenuId) +{ + m_popularity->useService(serviceMenuId); + if (m_settings->autoAdjustEnabled()) + { + QTimer::singleShot(0, this, SLOT(slotAdjustToCurrentPopularity())); + } +} + +void QuickLauncher::updateStickyHighlightLayer() +{ + // Creates a transparent image which is used + // to highlight those buttons which will never + // be removed automatically from the launcher + QPixmap areaPix(width(), height()); + QPainter areaPixPainter(&areaPix); + areaPixPainter.fillRect(0, 0, width(), height(), QColor(255, 255, 255)); + QSize itemSize = m_manager->itemSize(); + QSize spaceSize = m_manager->spaceSize(); + for (uint n=0; n<m_buttons->size(); ++n) + { + QPoint pos = m_manager->pos(n); + if ((*m_buttons)[n]->sticky() == false) + { + areaPixPainter.fillRect(pos.x()-(spaceSize.width()+1)/2, + pos.y()-(spaceSize.height()+1)/2, + itemSize.width()+spaceSize.width()+1, + itemSize.height()+spaceSize.height()+1, + QColor(0, 0, 0)); + } + } + QImage areaLayer = areaPix.convertToImage(); + m_stickyHighlightLayer = QImage(width(), height(), 32); + m_stickyHighlightLayer.setAlphaBuffer(true); + int pix, tlPix, brPix, w(width()), h(height()); + QRgb transparent(qRgba(0, 0, 0, 0)); + for (int y = h-1; y >= 0; --y) + { + for (int x = w-1; x >= 0; --x) + { + pix = qRed(areaLayer.pixel(x, y)); + if (pix == 0) + { + tlPix = (y>0 && x>0) ? qRed(areaLayer.pixel(x-1,y-1)) : 255; + brPix = (y<h-1 && x<w-1) ? qRed(areaLayer.pixel(x+1,y+1)) : 255; + int c = tlPix-brPix < 0 ? 255 : 0; + int alpha = abs(tlPix-brPix)/2; + m_stickyHighlightLayer.setPixel(x, y, qRgba(c, c, c, alpha)); + } + else + { + m_stickyHighlightLayer.setPixel(x, y, transparent); + } + } + } + repaint(); +} + +void QuickLauncher::paintEvent(QPaintEvent* e) +{ + KPanelApplet::paintEvent(e); + + if (m_settings->autoAdjustEnabled() && + m_settings->showVolatileButtonIndicator()) + { + QPainter p(this); + p.drawImage(0, 0, m_stickyHighlightLayer); + } +} + +void QuickLauncher::slotStickyToggled() +{ + updateStickyHighlightLayer(); + saveConfig(); +} + +void QuickLauncher::positionChange(Position) +{ + for (int n=0; n<int(m_buttons->size()); ++n) + { + (*m_buttons)[n]->setPopupDirection(popupDirection()); + } +} + + +#include "quicklauncher.moc" diff --git a/kicker/applets/launcher/quicklauncher.desktop b/kicker/applets/launcher/quicklauncher.desktop new file mode 100644 index 000000000..0e80149aa --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.desktop @@ -0,0 +1,140 @@ +[Desktop Entry] +Type=Plugin +Name=Quick Launcher +Name[af]=Vinnige Lanseerder +Name[ar]=الإنطلاق السريع +Name[az]=Sür'É™tli BaÅŸladıcı +Name[be]=Хуткі запуÑкальнік +Name[bg]=Бързо Ñтартиране +Name[bn]=কà§à¦‡à¦• লঞà§à¦šà¦¾à¦° +Name[br]=Loc'her prim +Name[bs]=Brzo pokretanje +Name[ca]=Engegador rà pid +Name[cs]=Rychlé spouÅ¡tÄ›nà aplikacà +Name[csb]=Chùtczé zrëszenié +Name[cy]=Cychwynydd Cyflym +Name[da]=Hurtigstarter +Name[de]=Schnellstarter +Name[el]=ΓÏήγοÏη φόÏτωση +Name[eo]=Rapidlanĉilo +Name[es]=Lanzador rápido +Name[et]=Kiirkäivitaja +Name[eu]=Abiarazle bizkorra +Name[fa]=راه‌انداز سریع +Name[fi]=Sovellusten pikakäynnistin +Name[fr]=Lanceur d'applications +Name[fy]=Snel útfierder +Name[ga]=Tosaitheoir Tapa +Name[gl]=Lanzador Rápido +Name[he]=הפעלה מהירה +Name[hi]=दà¥à¤°à¥à¤¤ लांचर +Name[hr]=Brzo pokretanje +Name[hu]=GyorsindÃtó +Name[id]=Launcher Cepat +Name[is]=Flýtiræsir +Name[it]=Esecuzione rapida +Name[ja]=クイックランãƒãƒ£ãƒ¼ +Name[ka]=სწრáƒáƒ¤áƒ˜ დáƒáƒ¬áƒ§áƒ”ბრ+Name[kk]=Жедел жегуші +Name[km]=អ្នក​ចាប់ផ្ដើម​រហáŸážŸ +Name[lo]=ຮງàºàº—ຳງານດ່ວນ +Name[lt]=Greitasis paleidimas +Name[lv]=Ä€trais PalaidÄ“js +Name[mk]=Брз Ñтартувач +Name[mn]=ТүргÑн ажилуулагч +Name[ms]=Pelancar Pantas +Name[mt]=Ħaddem Malajr +Name[nb]=Hurtigstarter +Name[nds]=Fixstarter +Name[ne]=दà¥à¤°à¥à¤¤ सà¥à¤°à¥à¤†à¤¤ +Name[nl]=Snelstarter +Name[nn]=Snøggstartar +Name[nso]=Ngwadisoleswa ya Kapela +Name[oc]=Engegador rapid +Name[pa]=ਚà©à¨¸à¨¤ ਸ਼à©à¨°à©‚ਆਤੀ +Name[pl]=Szybkie uruchamianie +Name[pt]=Execução de Aplicações +Name[pt_BR]=Lançador rápido +Name[ro]=Executor rapid +Name[ru]=БыÑтрый запуÑк +Name[rw]=Mutangiza Yihuta +Name[se]=Jođánisálggaheaddji +Name[sk]=Rýchly spúšťaÄ +Name[sl]=Hitri zaganjalnik +Name[sr]=Брзи покретач +Name[sr@Latn]=Brzi pokretaÄ +Name[sv]=Snabbstartare +Name[ta]=உடனடியாக திரையில௠தெரிதல௠+Name[te]=à°¤à±à°µà°°à°—à°¾ మొదలà±à°ªà±†à°Ÿà±à°Ÿà±†à°¦à°¿ +Name[tg]=Сар додани тез +Name[th]=เรียà¸à¸—ำงานด่วน +Name[tr]=Hızlı BaÅŸlatıcı +Name[tt]=Tiz Cibärgeç +Name[uk]=Швидкий запуÑк +Name[uz]=Tez ishga tushirgich +Name[uz@cyrillic]=Тез ишга туширгич +Name[ven]=Tavhanya +Name[vi]=Khởi Ä‘á»™ng nhanh +Name[wa]=Enondeu al vole di programes +Name[zh_CN]=快速å¯åŠ¨ +Name[zh_TW]=快速起動 +Name[zu]=Umqalisi osheshayo +Comment=Directly access your frequently used applications +Comment[af]=Kry direkte toegang tot die programme wat jy gereeld gebruik +Comment[ar]=للوصول المباشر إلى تطبيقاتك الأكثر إستعمالاً +Comment[be]=ÐаўпроÑÑ‚ запуÑкае праграму +Comment[bg]=Бърз доÑтъп до чеÑто използваните програми +Comment[bn]=আপনার সবচেয়ে ঘনঘন বà§à¦¯à¦¬à¦¹à§ƒà¦¤ অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨à¦—à§à¦²à¦¿ সরাসরি চালৠকরà§à¦¨ +Comment[bs]=Direktno pristupite vaÅ¡im Äesto koriÅ¡tenim programima +Comment[ca]=Accedeix directament a les aplicacions més usades +Comment[cs]=PÅ™Ãmý pÅ™Ãstup k nejÄastÄ›ji použÃvaným aplikacÃm +Comment[csb]=Prosti przistãp do nôczãstczi brëkòwónëch programów +Comment[da]=Direkte adgang til programmer du ofte bruger +Comment[de]=Schneller Zugriff auf häufig verwendete Programme +Comment[el]=Απευθείας Ï€Ïόσβαση στις συχνά χÏησιμοποιοÏμενες εφαÏμογÎÏ‚ σας +Comment[eo]=Rekte atingi viajn preferatajn aplikaĵojn +Comment[es]=Acceso directo a las aplicaciones usadas más frecuentemente +Comment[et]=Ligipääs sagedamini kasutatud rakendustele +Comment[eu]=Sarbide zuzena zure ohiko aplikazioei +Comment[fa]=دستیابی مستقیم به کاربردهای مکرر استÙاده‌شدۀ شما +Comment[fi]=Siirry suoraan useimmin käyttämiisi sovelluksiin +Comment[fr]=Accès direct aux applications les plus utilisées +Comment[fy]=Direkte tagong ta jo faak brûkte programma's +Comment[gl]=Aceda directamenta ás aplicacións que use mais amiudo +Comment[he]=גישה מהירה ×œ×™×™×©×•×ž×™× ×©×תה משתמש ×‘×”× ×”×›×™ הרבה +Comment[hr]=Izravni pristup najÄešće upotrebljavanim aplikacijama +Comment[hu]=A gyakran használt alkalmazások közvetlen elérése +Comment[is]=Beinn aðgangur að mest notuðu forritunum þÃnum +Comment[it]=Accesso diretto alle applicazioni usate più frequentemente +Comment[ja]=よã用ã„るアプリケーションã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹ +Comment[kk]=Жиі пайдаланатын қолданбаларды тез жегу +Comment[km]=ដំណើរការ​កម្មវិធី​ដែល​បាន​ប្រើ​ជា​រឿយៗ​របស់អ្នក​ដោយ​ផ្ទាល់ +Comment[lt]=Tiesiogiai pasiekite dažniausiai naudojamas programas +Comment[mk]=ПриÑтапете директно на вашите чеÑто кориÑтени апликации +Comment[nb]=FÃ¥ direkte tilgang til ofte brukte programmer +Comment[nds]=Direktemang Dien meist bruukte Programmen opropen +Comment[ne]=बारमà¥à¤¬à¤¾à¤° पà¥à¤°à¤¯à¥‹à¤— à¤à¤à¤•à¤¾ अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—मा तपाईà¤à¤•à¥‹ पà¥à¤°à¤¤à¥à¤¯à¤•à¥à¤· पहà¥à¤à¤š +Comment[nl]=Directe toegang tot uw veelgebruikte programma's +Comment[nn]=Direkte tilgang til program du brukar ofte +Comment[pa]=ਅਕਸਰ ਵਰਤੇ ਜਾਂਦੇ ਕਾਰਜਾਂ ਲਈ ਸਿੱਧੀ ਪਹà©à©°à¨š +Comment[pl]=BezpoÅ›redni dostÄ™p do najczęściej używanych programów +Comment[pt]=Aceder directamente à s aplicações usadas com mais frequência por si +Comment[pt_BR]=Acesso direito à seus aplicativos mais freqüentemente usados +Comment[ro]=Accesează direct aplicaÈ›iile folosite frecvent +Comment[ru]=БыÑтрый вызов чаÑто иÑпользуемых приложений +Comment[sk]=Priamo zprÃstupnà najÄastejÅ¡ie použÃvané programy. +Comment[sl]=Neposreden dostop do vaÅ¡ih najbolj uporabljanih programov +Comment[sr]=Директно приÑтупите Ñвојим чеÑто коришћеним програмима +Comment[sr@Latn]=Direktno pristupite svojim Äesto korišćenim programima +Comment[sv]=Direkt Ã¥tkomst av program du ofta använder +Comment[th]=เรียà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸à¸žà¸žà¸¥à¸´à¹€à¸„ชั่นที่คุณใช้บ่à¸à¸¢à¹† ได้โดยตรง +Comment[tr]=Sıkça kullanılan programlara eriÅŸim saÄŸlar +Comment[uk]=БезпоÑередній доÑтуп до програм, Ñкі чаÑто вживаютьÑÑ +Comment[uz]=Eng koÊ»p ishlatilgan dasturlarga qisqa yoÊ»l +Comment[uz@cyrillic]=Ðнг кўп ишлатилган даÑтурларга қиÑқа йўл +Comment[vi]=Chạy ngay các trình bạn thÆ°á»ng xuyên dùng +Comment[wa]=Accès direk Ã¥s programes sovint eployîs +Comment[zh_CN]=直接访问您最ç»å¸¸ä½¿ç”¨çš„åº”ç”¨ç¨‹åº +Comment[zh_TW]=直接å˜å–æ‚¨æœ€å¸¸ä½¿ç”¨çš„æ‡‰ç”¨ç¨‹å¼ +Icon=launch +X-KDE-Library=launcher_panelapplet diff --git a/kicker/applets/launcher/quicklauncher.h b/kicker/applets/launcher/quicklauncher.h new file mode 100644 index 000000000..c82d39661 --- /dev/null +++ b/kicker/applets/launcher/quicklauncher.h @@ -0,0 +1,138 @@ +/***************************************************************** + +Copyright (c) 2000 Bill Nagel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __quicklauncher_h__ +#define __quicklauncher_h__ + +#include <dcopobject.h> +#include <qimage.h> +#include <qstring.h> +#include <qvaluevector.h> +#include <kpanelapplet.h> +#include <map> + +#include "flowgridmanager.h" +#include "prefs.h" +#include "quickbutton.h" + +class ConfigDlg; +class QPopupMenu; +class QuickButtonGroup; +class PopularityStatistics; +class KAction; + +typedef QuickButtonGroup ButtonGroup; + +class QuickLauncher: public KPanelApplet, public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + void serviceStartedByStorageId(QString starter, QString storageId); + +public: + enum {DEFAULT_ICON_DIM=QuickButton::DEFAULT_ICON_DIM}; + enum {SIZE_AUTO=0}; + + struct PopularityInfo { + float popularity; + }; + + QuickLauncher(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~QuickLauncher(); + int widthForHeight(int height) const; + int heightForWidth(int width) const; + void addApp(QString url, int index, bool manuallyAdded); + virtual void action(Action a); + +public slots: + void addApp(QString url, bool manuallyAdded); + void addAppBeforeManually(QString url, QString sender); + void removeAppManually(QuickButton *button); + void removeApp(QString url, bool manuallyRemoved); + void removeApp(int index, bool manuallyRemoved); + void removeAppManually(int index); + void saveConfig(); + void about(); + +protected: + int findApp(QString url); + int findApp(QuickButton *button); + + void mousePressEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent*); + void dragEnterEvent(QDragEnterEvent *e); + void dragLeaveEvent(QDragLeaveEvent *e); + void dragMoveEvent(QDragMoveEvent *e); + void dropEvent(QDropEvent *e); + void refreshContents(); + void setRefreshEnabled(bool enable); + void setConserveSpace(bool conserve_space); + void setDragEnabled(bool conserve_space); + + bool conserveSpace() const { return m_manager->conserveSpace(); } + bool isDragEnabled() const { return m_settings->dragEnabled(); } + + void buildPopupMenu(); + void loadConfig(); + + void mergeButtons(int index); + void clearTempButtons(); + int dimension() const; + +protected slots: + void slotConfigure(); + void slotSettingsDialogChanged(); + void fillRemoveAppsMenu(); + void slotOwnServiceExecuted(QString serviceMenuId); + void slotAdjustToCurrentPopularity(); + void slotStickyToggled(); + +protected: + void updateInsertionPosToStatusQuo(); + void updateStickyHighlightLayer(); + QuickButton* createButton(QString url); + virtual void paintEvent(QPaintEvent* e); + virtual void positionChange(Position); + + QPopupMenu *m_popup; + QPopupMenu *m_appletPopup; + QPopupMenu *m_removeAppsMenu; + QuickButtonGroup *m_buttons, *m_newButtons, *m_oldButtons, *m_dragButtons; + int m_space, m_border; + QSize m_buttonSize; + FlowGridManager *m_manager; + int m_dropLen, m_dropPos, m_minPanelDim; + bool m_dragAccepted, m_refreshEnabled, m_needsSave, m_needsRefresh; + std::map<QString, int> m_appOrdering; + Prefs* m_settings; + KAction *m_configAction; + ConfigDlg *m_configDialog; + PopularityStatistics* m_popularity; + QImage m_stickyHighlightLayer; + QTimer *m_saveTimer; +}; + +#endif diff --git a/kicker/applets/lockout/Makefile.am b/kicker/applets/lockout/Makefile.am new file mode 100644 index 000000000..f9772adf5 --- /dev/null +++ b/kicker/applets/lockout/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes) +METASOURCES = AUTO + +kde_module_LTLIBRARIES = lockout_panelapplet.la + +lockout_panelapplet_la_SOURCES = lockout.cpp +lockout_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +lockout_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KSYCOCA) + +noinst_HEADERS = lockout.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = lockout.desktop + +EXTRA_DIST = $(lnk_DATA) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/lockout.pot diff --git a/kicker/applets/lockout/README b/kicker/applets/lockout/README new file mode 100644 index 000000000..e25954c3d --- /dev/null +++ b/kicker/applets/lockout/README @@ -0,0 +1,4 @@ +A very simple applet that shows two buttons, one for locking the desktop, +the other to invoke the logout process. + +Carsten Pfeiffer <pfeiffer@kde.org> diff --git a/kicker/applets/lockout/lockout.cpp b/kicker/applets/lockout/lockout.cpp new file mode 100644 index 000000000..d22e4a8ed --- /dev/null +++ b/kicker/applets/lockout/lockout.cpp @@ -0,0 +1,278 @@ +/***************************************************************** + +Copyright (c) 2001 Carsten Pfeiffer <pfeiffer@kde.org> + 2001 Matthias Elter <elter@kde.org> + 2001 Martijn Klingens <mklingens@yahoo.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + + +#include <qlayout.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qpopupmenu.h> +#include <qtoolbutton.h> +#include <qstyle.h> +#include <qtooltip.h> + +#include <dcopclient.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klocale.h> +#include <kiconloader.h> +#include <krun.h> +#include <kdebug.h> + +#include <stdlib.h> +#include "lockout.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("lockout"); + return new Lockout(configFile, parent, "lockout"); + } +} + +Lockout::Lockout( const QString& configFile, QWidget *parent, const char *name) + : KPanelApplet( configFile, KPanelApplet::Normal, 0, parent, name ), bTransparent( false ) +{ + KConfig *conf = config(); + conf->setGroup("lockout"); + + //setFrameStyle(Panel | Sunken); + setBackgroundOrigin( AncestorOrigin ); + + if ( orientation() == Horizontal ) + layout = new QBoxLayout( this, QBoxLayout::TopToBottom ); + else + layout = new QBoxLayout( this, QBoxLayout::LeftToRight ); + + layout->setAutoAdd( true ); + layout->setMargin( 0 ); + layout->setSpacing( 0 ); + + lockButton = new SimpleButton( this, "lock"); + logoutButton = new SimpleButton( this, "logout"); + + QToolTip::add( lockButton, i18n("Lock the session") ); + QToolTip::add( logoutButton, i18n("Log out") ); + + lockButton->setPixmap( SmallIcon( "lock" )); + logoutButton->setPixmap( SmallIcon( "exit" )); + + bTransparent = conf->readBoolEntry( "Transparent", bTransparent ); + + connect( lockButton, SIGNAL( clicked() ), SLOT( lock() )); + connect( logoutButton, SIGNAL( clicked() ), SLOT( logout() )); + + lockButton->installEventFilter( this ); + logoutButton->installEventFilter( this ); + + if (!kapp->authorize("lock_screen")) + lockButton->hide(); + + if (!kapp->authorize("logout")) + logoutButton->hide(); + + lockButton->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); + logoutButton->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); + + if ( !kapp->dcopClient()->isAttached() ) + kapp->dcopClient()->attach(); + + connect( kapp, SIGNAL( iconChanged(int) ), SLOT( slotIconChanged() )); +} + +Lockout::~Lockout() +{ + KGlobal::locale()->removeCatalogue("lockout"); +} + +// the -2 is due to kicker allowing us a width/height of 42 and the buttons +// having a size of 44. So we rather cut those 2 pixels instead of changing +// direction and wasting a lot of space. +void Lockout::checkLayout( int height ) const +{ + QSize s = minimumSizeHint(); + QBoxLayout::Direction direction = layout->direction(); + + if ( direction == QBoxLayout::LeftToRight && + ( ( orientation() == Vertical && s.width() - 2 >= height ) || + ( orientation() == Horizontal && s.width() - 2 < height ) ) ) { + layout->setDirection( QBoxLayout::TopToBottom ); + } + else if ( direction == QBoxLayout::TopToBottom && + ( ( orientation() == Vertical && s.height() - 2 < height ) || + ( orientation() == Horizontal && s.height() - 2 >= height ) ) ) { + layout->setDirection( QBoxLayout::LeftToRight ); + } +} + +int Lockout::widthForHeight( int height ) const +{ + checkLayout( height ); + return sizeHint().width(); +} + +int Lockout::heightForWidth( int width ) const +{ + checkLayout( width ); + return sizeHint().height(); +} + +void Lockout::lock() +{ + QCString appname( "kdesktop" ); + int kicker_screen_number = qt_xscreen(); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", ""); +} + +void Lockout::logout() +{ + kapp->requestShutDown(); +} + +void Lockout::mousePressEvent(QMouseEvent* e) +{ + propagateMouseEvent(e); +} + +void Lockout::mouseReleaseEvent(QMouseEvent* e) +{ + propagateMouseEvent(e); +} + +void Lockout::mouseDoubleClickEvent(QMouseEvent* e) +{ + propagateMouseEvent(e); +} + +void Lockout::mouseMoveEvent(QMouseEvent* e) +{ + propagateMouseEvent(e); +} + +void Lockout::propagateMouseEvent(QMouseEvent* e) +{ + if ( !isTopLevel() ) { + QMouseEvent me(e->type(), mapTo( topLevelWidget(), e->pos() ), + e->globalPos(), e->button(), e->state() ); + QApplication::sendEvent( topLevelWidget(), &me ); + } +} + +bool Lockout::eventFilter( QObject *o, QEvent *e ) +{ + if (!kapp->authorizeKAction("kicker_rmb")) + return false; // Process event normally: + + if( e->type() == QEvent::MouseButtonPress ) + { + KConfig *conf = config(); + conf->setGroup("lockout"); + + QMouseEvent *me = static_cast<QMouseEvent *>( e ); + if( me->button() == QMouseEvent::RightButton ) + { + if( o == lockButton ) + { + QPopupMenu *popup = new QPopupMenu(); + + popup->insertItem( SmallIcon( "lock" ), i18n("Lock Session"), + this, SLOT( lock() ) ); + popup->insertSeparator(); + + i18n("&Transparent"); + //popup->insertItem( i18n( "&Transparent" ), 100 ); + popup->insertItem( SmallIcon( "configure" ), + i18n( "&Configure Screen Saver..." ), + this, SLOT( slotLockPrefs() ) ); + + //popup->setItemChecked( 100, bTransparent ); + //popup->connectItem(100, this, SLOT( slotTransparent() ) ); + //if (conf->entryIsImmutable( "Transparent" )) + // popup->setItemEnabled( 100, false ); + popup->exec( me->globalPos() ); + delete popup; + + return true; + } + else if ( o == logoutButton ) + { + QPopupMenu *popup = new QPopupMenu(); + + popup->insertItem( SmallIcon( "exit" ), i18n("&Log Out..."), + this, SLOT( logout() ) ); + popup->insertSeparator(); + //popup->insertItem( i18n( "&Transparent" ), 100 ); + popup->insertItem( SmallIcon( "configure" ), + i18n( "&Configure Session Manager..." ), + this, SLOT( slotLogoutPrefs() ) ); + + //popup->setItemChecked( 100, bTransparent ); + //popup->connectItem(100, this, SLOT( slotTransparent() ) ); + //if (conf->entryIsImmutable( "Transparent" )) + // popup->setItemEnabled( 100, false ); + popup->exec( me->globalPos() ); + delete popup; + + return true; + } // if o + } // if me->button + } // if e->type + + // Process event normally: + return false; +} + +void Lockout::slotLockPrefs() +{ + // Run the screensaver settings + KRun::run( "kcmshell screensaver", KURL::List() ); +} + +void Lockout::slotTransparent() +{ + bTransparent = !bTransparent; + + KConfig* conf = config(); + conf->setGroup("lockout"); + conf->writeEntry( "Transparent", bTransparent ); + conf->sync(); +} + +void Lockout::slotLogoutPrefs() +{ + // Run the logout settings. + KRun::run( "kcmshell kcmsmserver", KURL::List() ); +} + +void Lockout::slotIconChanged() +{ + lockButton->setPixmap( SmallIcon( "lock" )); + logoutButton->setPixmap( SmallIcon( "exit" )); +} + +#include "lockout.moc" diff --git a/kicker/applets/lockout/lockout.desktop b/kicker/applets/lockout/lockout.desktop new file mode 100644 index 000000000..e8681cc88 --- /dev/null +++ b/kicker/applets/lockout/lockout.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Type=Plugin +Name=Lock/Logout Buttons +Name[af]=Sluit/Teken af Knoppies +Name[ar]=أزرار الإقÙال/الخروج +Name[be]=Кнопкі блакаваннÑ/выхаду +Name[bg]=Заключване и изход +Name[bn]=লক/লগ-আউট বাটন +Name[bs]=Dugmad za zakljuÄavanje/odjavu +Name[ca]=Botons bloqueja/surt +Name[cs]=TlaÄÃtka odhlášenÃ/uzamÄenà +Name[csb]=KnÄ…pë blokòwaniô ekranu/wëlogòwaniô +Name[da]=LÃ¥s/Logaf-knapper +Name[de]=Bildschirmsperre und Abmeldung aus KDE +Name[el]=Κουμπιά κλειδώματος/αποσÏνδεσης +Name[eo]=Åœloso- kaj adiaÅo-butonoj +Name[es]=Botones de bloqueo/salida +Name[et]=Lukustamise/väljalogimise nupud +Name[eu]=Blokeatu/Irteteko botoiak +Name[fa]=دکمه‌های Ù‚ÙÙ„/خروج +Name[fi]=Lukitus/Uloskirjautumispainikkeet +Name[fr]=Boutons de verrouillage et déconnexion +Name[fy]=Beskoattelje/ôfmeldknoppen +Name[ga]=Cnaipà Glasála/Logála Amach +Name[gl]=Botóns de Bloqueo/SaÃda +Name[he]=כפתורי × ×¢×™×œ×”\יצי××” +Name[hr]=Gumb za zakljuÄavanje/odjavljivanje +Name[hu]=Zároló/kijelentkezÅ‘ gombok +Name[is]=Læsa/stimpla út hnappar +Name[it]=Pulsanti di uscita e bloccaggio schermo +Name[ja]=ãƒãƒƒã‚¯/ãƒã‚°ã‚¢ã‚¦ãƒˆãƒœã‚¿ãƒ³ +Name[ka]=დáƒáƒ‘ლáƒáƒ™áƒ•áƒ˜áƒ¡/გáƒáƒ›áƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ ღილáƒáƒ™áƒ”ბი +Name[kk]=Шығу не Ñкранды бұғаттау батырмалары +Name[km]=ប៊ូážáž»áž„ ចាក់សោ/áž…áŸáž‰ +Name[ko]=ìž ê¸ˆ/로그아웃 +Name[lt]=Užrakinimo/iÅ¡siregistravimo mygtukai +Name[mk]=Копчиња „Заклучи/Одјави Ñе“ +Name[nb]=Panelprogram for skjermlÃ¥s/utlogging +Name[nds]=Knööp för dat Afsluten oder Afmellen +Name[ne]=तालà¥à¤šà¤¾ लगाउने/लगआउट गरà¥à¤¨à¥‡ बटन +Name[nl]=Vergrendel/afmeldknoppen +Name[nn]=Knappar for skjermlÃ¥s/utlogging +Name[pa]=ਤਾਲਾ/ਬਾਹਰੀ ਦਰ ਬਟਨ +Name[pl]=Przyciski blokowania ekranu/wylogowania +Name[pt]=Botões de Bloqueio/SaÃda +Name[pt_BR]=Botões de Travar/Sair +Name[ro]=Butoane de blocare/ieÈ™ire +Name[ru]=Кнопки выхода и Ð·Ð°Ð¿Ð¸Ñ€Ð°Ð½Ð¸Ñ Ñкрана +Name[se]=Lohkadan/olggosÄálihan boalut +Name[sk]=TlaÄidlá na ohlásenie/zamknutie +Name[sl]=Gumba za zaklep in odjavo +Name[sr]=Дугмад за закључавање/одјављивање +Name[sr@Latn]=Dugmad za zakljuÄavanje/odjavljivanje +Name[sv]=LÃ¥s/Logga ut-knappar +Name[te]=తాళం వెయి/లాగౌటౠబటనà±à°²à± +Name[tg]=Тугмаҳои Қулф/Баромадан +Name[th]=ปุ่มล็à¸à¸„/ล็à¸à¸à¹€à¸à¸²à¸—์ +Name[tr]=Kilitle/Çık Düğmeleri +Name[uk]=Кнопки ЗамиканнÑ/Виходу з ÑиÑтеми +Name[uz]=Qulflash/chiqish tugmalari +Name[uz@cyrillic]=Қулфлаш/чиқиш тугмалари +Name[vi]=Tiểu ứng dụng Khoá/Äăng xuất +Name[wa]=Boton po serer a clé ou dislodjî +Name[zh_CN]=é”定/注销按钮 +Name[zh_TW]=「螢幕鎖定/登出ã€æŒ‰éˆ• +Comment=Adds buttons for locking screen and session logout +Comment[af]=Voeg skerm sluit en afteken knoppies by +Comment[ar]=يضي٠أزرار لإقÙال الشاشة Ùˆ الخروج من الجلسة +Comment[be]=Дадае кнопкі Ð´Ð»Ñ Ð±Ð»Ð°ÐºÑ–Ñ€Ð¾ÑžÐºÑ– Ñкрана Ñ– заканчÑÐ½Ð½Ñ ÑеÑÑ–Ñ– +Comment[bg]=ДобавÑне на бутоните за заключване на екрана и изход +Comment[bn]=সà§à¦•à§à¦°à§€à¦£ লক à¦à¦¬à¦‚ লগ-আউট করার জনà§à¦¯ বাটন যোগ করে +Comment[bs]=Dodaje na panel dugmad za zakljuÄavanje ekrana i odjavu sa sistema +Comment[ca]=Afegeix botons per bloquejar la pantalla i sortir de la sessió +Comment[cs]=PÅ™idá tlaÄÃtka pro uzamÄenà obrazovky a odhlášenà z relace +Comment[csb]=Dodôwô knapë blokòwaniô ekranu ë wëlogòwaniô +Comment[da]=Tilføjer knapper for at lÃ¥se skærmen og logge ud fra sessionen +Comment[de]=Fügt Knöpfe zur Bildschirmsperre und Abmeldung aus KDE hinzu +Comment[el]=Î ÏοσθÎτει κουμπιά για το κλείδωμα της οθόνης και την αποσÏνδεση συνεδÏίας +Comment[eo]=Aldonu butonojn por Ålosi ekranon kaj seanco-eliron +Comment[es]=Añade botones para bloquear la sesión y para salirse de esta +Comment[et]=Lisab nupud ekraani lukustamiseks ning seansi lõpetamiseks +Comment[eu]=Pantaila blokeatu eta saiotik irteteko botoiak gehitzen ditu +Comment[fa]=دکمه‌ها را برای Ù‚ÙÙ„ پرده Ùˆ خروج نشست اضاÙÙ‡ می‌کند +Comment[fi]=Lisää painikkeet ruudun lukitsemiseen ja uloskirjautumiseen +Comment[fr]=Ajoute des boutons permettant de verrouiller l'écran et de déconnecter la session en cours +Comment[fy]=Heakket knoppen ta foar it beskoattelje fan it skerm en it sluten fan de sesje +Comment[gl]=Engade botóns para bloquear a pantalla e sair da sesión +Comment[he]=מוסיף ×›×¤×ª×•×¨×™× ×œ× ×¢×™×œ×ª המסך ויצי××” מהמערכת +Comment[hr]=Dodavanje gumba za zakljuÄavanje zaslona i odjavljivanja sesije +Comment[hu]=Nyomógombok a képernyÅ‘ zárolásához és kijelentkezéshez +Comment[is]=Bætir við hnöppum til að læsa skjánum og stimpla sig út +Comment[it]=Aggiunge i pulsanti per bloccare lo schermo o uscire dalla sessione +Comment[ja]=スクリーンãƒãƒƒã‚¯ã¨ã‚»ãƒƒã‚·ãƒ§ãƒ³ãƒã‚°ã‚¢ã‚¦ãƒˆç”¨ãƒœã‚¿ãƒ³ã‚’è¿½åŠ +Comment[kk]=Ðкранды бұғаттау және ÑеанÑтан шығу батырмаларды қоÑу +Comment[km]=បន្ážáŸ‚ម​ប៊ូážáž»áž„​សម្រាប់​ចាក់សោ​អáŸáž€áŸ’រង់ និង​ចáŸáž‰â€‹áž–ី​សមáŸáž™ +Comment[ko]=ì„¸ì…˜ì„ ìž ê·¸ê±°ë‚˜ ë내기 +Comment[lt]=Prideda mygtukus ekrano užrakinimui ir sesijos užbaigimui +Comment[mk]=Додава копчиња за заклучување на екранот и одјавување од ÑеÑијата +Comment[nb]=Legger til knapper for Ã¥ lÃ¥se skjermen og logge ut av økta. +Comment[nds]=Föögt Knööp för dat Afsluten vun den Schirm oder dat Afmellen ut KDE to +Comment[ne]=परà¥à¤¦à¤¾ तालà¥à¤šà¤¾ लगाउन र सतà¥à¤° लग आउट गरà¥à¤¨à¤•à¤¾ लागि बटनहरू थपà¥à¤› +Comment[nl]=Voegt knoppen toe voor het vergrendelen van het scherm en het afsluiten van de sessie +Comment[nn]=Legg til knappar for Ã¥ lÃ¥sa skjermen og logga ut av økta. +Comment[pa]=ਪਰਦੇ ਨੂੰ ਤਾਲਾਬੰਦ ਕਰਨ ਅਤੇ ਅਜਲਾਸ ਬੰਦ ਕਰਨ ਲਈ ਬਟਨ ਜੋੜਦਾ ਹੈ +Comment[pl]=Dodaje przyciski zablokowania ekranu i wylogowania +Comment[pt]=Adiciona botões para bloquear o ecrã e encerrar a sessão +Comment[pt_BR]=Adiciona os botões para bloquear a tela e finalizar a sessão +Comment[ro]=Adaugă butoane pentru blocarea ecranului È™i sesiunea de ieÈ™ire +Comment[ru]=Добавление кнопок выхода из KDE и Ð·Ð°Ð¿Ð¸Ñ€Ð°Ð½Ð¸Ñ Ñкрана +Comment[se]=Lasit boaluid mat sáhttet lohkadit Å¡earpma ja heaittihit bargovuoru +Comment[sk]=Pridá tlaÄidlá na zamknutie obrazovky a ukonÄenie relácie +Comment[sl]=Doda gumba za zaklep zaslona in odjavo iz seje +Comment[sr]=Додаје дугмад за закључавање екрана и одјављивање из ÑеÑије +Comment[sr@Latn]=Dodaje dugmad za zakljuÄavanje ekrana i odjavljivanje iz sesije +Comment[sv]=Lägger till knappar för att lÃ¥sa skärmen och logga ut frÃ¥n sessionen +Comment[th]=เพิ่มปุ่มสำหรับล็à¸à¸„หน้าจà¸à¹à¸¥à¸°à¸¥à¹‡à¸à¸à¹€à¸à¸²à¸—์à¸à¸à¸à¸ˆà¸²à¸à¸§à¸²à¸£à¸°à¸—ี่à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸à¸¢à¸¹à¹ˆ +Comment[uk]=Додає кнопки Ð´Ð»Ñ Ð·Ð°Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ ÐµÐºÑ€Ð°Ð½Ð° та виходу з ÑеанÑу +Comment[uz]=Ekranni qulflash va seansdan chiqish uchun tugmalar +Comment[uz@cyrillic]=Ðкранни қулфлаш ва ÑеанÑдан чиқиш учун тугмалар +Comment[vi]=Thêm nút khoá mà n hình và đăng xuất khá»i phiên là m việc +Comment[wa]=Radjout des botons po serer l' waitroûle a clé et dislodjî del session +Comment[zh_CN]=æ·»åŠ é”定å±å¹•å’Œæ³¨é”€ä¼šè¯çš„按钮 +Comment[zh_TW]=åŠ å…¥ç”¨ä¾†éŽ–å®šèž¢å¹•èˆ‡ç™»å‡ºä½œæ¥éšŽæ®µçš„按鈕 +Icon=exit +X-KDE-Library=lockout_panelapplet diff --git a/kicker/applets/lockout/lockout.h b/kicker/applets/lockout/lockout.h new file mode 100644 index 000000000..606870a99 --- /dev/null +++ b/kicker/applets/lockout/lockout.h @@ -0,0 +1,52 @@ +#ifndef LOCKOUT_H +#define LOCKOUT_H + +#include <qevent.h> +#include <qstring.h> +#include <kpanelapplet.h> + +#include "simplebutton.h" + +class QBoxLayout; +class QToolButton; + +class Lockout : public KPanelApplet +{ + Q_OBJECT + +public: + Lockout( const QString& configFile, + QWidget *parent = 0, const char *name = 0 ); + ~Lockout(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + +protected: + virtual void mousePressEvent( QMouseEvent * ); + virtual void mouseMoveEvent( QMouseEvent * ); + virtual void mouseReleaseEvent( QMouseEvent * ); + virtual void mouseDoubleClickEvent( QMouseEvent * ); + + virtual bool eventFilter( QObject *, QEvent * ); + +private slots: + void lock(); + void logout(); + + void slotLockPrefs(); + void slotLogoutPrefs(); + void slotTransparent(); + void slotIconChanged(); + +private: + void propagateMouseEvent( QMouseEvent * ); + void checkLayout( int height ) const; + + SimpleButton *lockButton, *logoutButton; + QBoxLayout *layout; + + bool bTransparent; +}; + +#endif // LOCKOUT_H diff --git a/kicker/applets/media/Makefile.am b/kicker/applets/media/Makefile.am new file mode 100644 index 000000000..0b971aef2 --- /dev/null +++ b/kicker/applets/media/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(top_srcdir)/libkonq -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = media_panelapplet.la +media_panelapplet_la_SOURCES = preferencesdialog.cpp mediumbutton.cpp mediaapplet.cpp + +METASOURCES = AUTO + +noinst_HEADERS = mediaapplet.h mediumbutton.h preferencesdialog.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = mediaapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +media_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +media_panelapplet_la_LIBADD = ../../../libkonq/libkonq.la ../../libkicker/libkickermain.la $(LIB_KDEUI) $(LIB_KIO) $(LIB_KUTILS) + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/mediaapplet.pot + diff --git a/kicker/applets/media/mediaapplet.cpp b/kicker/applets/media/mediaapplet.cpp new file mode 100644 index 000000000..4ccd0eeef --- /dev/null +++ b/kicker/applets/media/mediaapplet.cpp @@ -0,0 +1,444 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kglobal.h> +#include <klocale.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <kaboutapplication.h> +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kiconloader.h> + +#include "mediaapplet.h" + +#include "preferencesdialog.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString configFile) + { + KGlobal::locale()->insertCatalogue("mediaapplet"); + return new MediaApplet(configFile, KPanelApplet::Normal, + KPanelApplet::About | KPanelApplet::Preferences, + parent, "mediaapplet"); + } +} + +MediaApplet::MediaApplet(const QString& configFile, Type type, int actions, QWidget *parent, const char *name) + : KPanelApplet(configFile, type, actions, parent, name), + mButtonSizeSum(0) +{ + if (!parent) + setBackgroundMode(X11ParentRelative); + + setBackgroundOrigin(AncestorOrigin); + + setAcceptDrops(true); + + loadConfig(); + + mpDirLister = new KDirLister(); + + connect( mpDirLister, SIGNAL( clear() ), + this, SLOT( slotClear() ) ); + connect( mpDirLister, SIGNAL( started(const KURL&) ), + this, SLOT( slotStarted(const KURL&) ) ); + connect( mpDirLister, SIGNAL( completed() ), + this, SLOT( slotCompleted() ) ); + connect( mpDirLister, SIGNAL( newItems( const KFileItemList & ) ), + this, SLOT( slotNewItems( const KFileItemList & ) ) ); + connect( mpDirLister, SIGNAL( deleteItem( KFileItem * ) ), + this, SLOT( slotDeleteItem( KFileItem * ) ) ); + connect( mpDirLister, SIGNAL( refreshItems( const KFileItemList & ) ), + this, SLOT( slotRefreshItems( const KFileItemList & ) ) ); + + reloadList(); +} + +MediaApplet::~MediaApplet() +{ + delete mpDirLister; + + while (!mButtonList.isEmpty()) + { + MediumButton *b = mButtonList.first(); + mButtonList.remove(b); + delete b; + } + + KGlobal::locale()->removeCatalogue("mediaapplet"); +} + +void MediaApplet::about() +{ + KAboutData data("mediaapplet", + I18N_NOOP("Media Applet"), + "1.0", + I18N_NOOP("\"media:/\" ioslave frontend applet"), + KAboutData::License_GPL_V2, + "(c) 2004, Kevin Ottens"); + + data.addAuthor("Kevin \'ervin\' Ottens", + I18N_NOOP("Maintainer"), + "ervin ipsquad net", + "http://ervin.ipsquad.net"); + + data.addCredit("Joseph Wenninger", + I18N_NOOP("Good mentor, patient and helpful. Thanks for all!"), + "jowenn@kde.org"); + + KAboutApplication dialog(&data); + dialog.exec(); +} + +void MediaApplet::preferences() +{ + PreferencesDialog dialog(mMedia); + + dialog.setExcludedMediumTypes(mExcludedTypesList); + dialog.setExcludedMedia(mExcludedList); + + if(dialog.exec()) + { + mExcludedTypesList = dialog.excludedMediumTypes(); + mExcludedList = dialog.excludedMedia(); + saveConfig(); + reloadList(); + } +} + +int MediaApplet::widthForHeight( int /*height*/ ) const +{ + return mButtonSizeSum; +} + +int MediaApplet::heightForWidth( int /*width*/ ) const +{ + return mButtonSizeSum; +} + +void MediaApplet::resizeEvent( QResizeEvent *) +{ + arrangeButtons(); +} + +void MediaApplet::arrangeButtons() +{ + int button_size = 1; + int x_offset = 0; + int y_offset = 0; + + // Determine upper bound for the button size + MediumButtonList::iterator it; + MediumButtonList::iterator end = mButtonList.end(); + for ( it = mButtonList.begin(); it != end; ++it ) + { + MediumButton *button = *it; + + button_size = std::max(button_size, + orientation() == Vertical ? + button->heightForWidth(width()) : + button->widthForHeight(height()) ); + // button->widthForHeight(height()) : + // button->heightForWidth(width()) ); + } + + int kicker_size; + if (orientation() == Vertical) + { + kicker_size = width(); + } + else + { + kicker_size = height(); + } + + unsigned int max_packed_buttons = kicker_size / button_size; + // Center icons if we only have one column/row + if (mButtonList.count() < max_packed_buttons) + { + max_packed_buttons = QMAX(uint(1), mButtonList.count()); + } + max_packed_buttons = QMAX(uint(1), max_packed_buttons); + + int padded_button_size = kicker_size / max_packed_buttons; + mButtonSizeSum = 0; + unsigned int pack_count = 0; + + // Arrange the buttons. If kicker is more than twice as high/wide + // as the maximum preferred size of an icon, we put several icons + // in one column/row + for ( it = mButtonList.begin(); it != end; ++it ) + { + MediumButton *button = *it; + + button->move(x_offset, y_offset); + button->setPanelPosition(position()); + + if(pack_count == 0) + { + mButtonSizeSum += button_size; + } + + ++pack_count; + + if(orientation() == Vertical) + { + if (pack_count < max_packed_buttons) + { + x_offset += padded_button_size; + } + else + { + x_offset = 0; + y_offset += button_size; + pack_count = 0; + } + + button->resize(padded_button_size, button_size); + } + else + { + if (pack_count < max_packed_buttons) + { + y_offset += padded_button_size; + } + else + { + y_offset = 0; + x_offset += button_size; + pack_count = 0; + } + + button->resize(button_size, padded_button_size); + } + + button->unsetPalette(); + button->setBackgroundOrigin(AncestorOrigin); + } + + updateGeometry(); + emit updateLayout(); +} + +void MediaApplet::slotClear() +{ + kdDebug()<<"MediaApplet::slotClear"<<endl; + + while (!mButtonList.isEmpty()) + { + MediumButton *b = mButtonList.first(); + mButtonList.remove(b); + delete b; + } + + arrangeButtons(); +} + +void MediaApplet::slotStarted(const KURL &/*url*/) +{ +} + +void MediaApplet::slotCompleted() +{ + mMedia = mpDirLister->items(KDirLister::AllItems); +} + +void MediaApplet::slotNewItems(const KFileItemList &entries) +{ + kdDebug()<<"MediaApplet::slotNewItems"<<endl; + + for(KFileItemListIterator it(entries); it.current(); ++it) + { + kdDebug() << "item: " << it.current()->url() << endl; + + bool found = false; + MediumButtonList::iterator it2; + MediumButtonList::iterator end = mButtonList.end(); + for ( it2 = mButtonList.begin(); it2 != end; ++it2 ) + { + MediumButton *button = *it2; + + if(button->fileItem().url()==it.current()->url()) + { + found = true; + button->setFileItem(*it.current()); + break; + } + } + + if(!found && !mExcludedList.contains(it.current()->url().url()) ) + { + MediumButton *button = new MediumButton(this, *it.current()); + button->show(); + mButtonList.append(button); + } + } + + arrangeButtons(); +} + +void MediaApplet::slotDeleteItem(KFileItem *fileItem) +{ + kdDebug()<<"MediumApplet::slotDeleteItem:"<< fileItem->url() << endl; + + MediumButtonList::iterator it; + MediumButtonList::iterator end = mButtonList.end(); + for ( it = mButtonList.begin(); it != end; ++it ) + { + MediumButton *button = *it; + + if(button->fileItem().url()==fileItem->url()) + { + mButtonList.remove(button); + delete button; + break; + } + } + slotCompleted(); + arrangeButtons(); +} + +void MediaApplet::slotRefreshItems(const KFileItemList &entries) +{ + for(KFileItemListIterator it(entries); it.current(); ++it) + { + kdDebug()<<"MediaApplet::slotRefreshItems:"<<(*it.current()).url().url()<<endl; + + QString mimetype = (*it.current()).mimetype(); + bool found = false; + + kdDebug()<<"mimetype="<<mimetype<<endl; + + MediumButtonList::iterator it2; + MediumButtonList::iterator end = mButtonList.end(); + for ( it2 = mButtonList.begin(); it2 != end; ++it2 ) + { + MediumButton *button = *it2; + + if(button->fileItem().url()==(*it.current()).url()) + { + if(mExcludedTypesList.contains(mimetype)) + { + mButtonList.remove(button); + delete button; + } + else + { + button->setFileItem(*it.current()); + } + found = true; + break; + } + } + + if(!found && !mExcludedTypesList.contains(mimetype) && !mExcludedList.contains(it.current()->url().url()) ) + { + MediumButton *button = new MediumButton(this, *it.current()); + button->show(); + mButtonList.append(button); + } + } + + arrangeButtons(); +} + +void MediaApplet::positionChange(Position) +{ + arrangeButtons(); +} + +void MediaApplet::loadConfig() +{ + KConfig *c = config(); + c->setGroup("General"); + + if(c->hasKey("ExcludedTypes")) + { + mExcludedTypesList = c->readListEntry("ExcludedTypes",';'); + } + else + { + mExcludedTypesList.clear(); + mExcludedTypesList << "media/hdd_mounted"; + mExcludedTypesList << "media/hdd_unmounted"; + mExcludedTypesList << "media/nfs_mounted"; + mExcludedTypesList << "media/nfs_unmounted"; + mExcludedTypesList << "media/smb_mounted"; + mExcludedTypesList << "media/smb_unmounted"; + } + + if(c->hasKey("ExcludedMedia")) + { + mExcludedList = c->readListEntry("ExcludedMedia",';'); + } + else + { + mExcludedList.clear(); + } +} + +void MediaApplet::saveConfig() +{ + KConfig *c = config(); + c->setGroup("General"); + + c->writeEntry("ExcludedTypes", mExcludedTypesList, ';'); + c->writeEntry("ExcludedMedia", mExcludedList, ';'); + + c->sync(); +} + +void MediaApplet::reloadList() +{ + mpDirLister->stop(); + + while (!mButtonList.isEmpty()) + { + MediumButton *b = mButtonList.first(); + mButtonList.remove(b); + delete b; + } + + mpDirLister->clearMimeFilter(); + mpDirLister->setMimeExcludeFilter(mExcludedTypesList); + mpDirLister->openURL(KURL("media:/")); +} + +void MediaApplet::mousePressEvent(QMouseEvent *e) +{ + if(e->button()==RightButton) + { + KPopupMenu menu(this); + + menu.insertTitle(i18n("Media")); + menu.insertItem(SmallIcon("configure"), i18n("&Configure..."), 1); + + int choice = menu.exec(this->mapToGlobal(e->pos())); + + if(choice==1) + { + preferences(); + } + } +} + +#include "mediaapplet.moc" diff --git a/kicker/applets/media/mediaapplet.desktop b/kicker/applets/media/mediaapplet.desktop new file mode 100644 index 000000000..958ebb753 --- /dev/null +++ b/kicker/applets/media/mediaapplet.desktop @@ -0,0 +1,130 @@ +[Desktop Entry] +Type=Plugin +Comment=Directly access your storage media +Comment[af]=Kry direkte toegang tot jou stoor media +Comment[ar]=الوصول مباشرة إلى وسائطك للتخزين +Comment[be]=ÐаўпроÑÑ‚ дае доÑтуп да ноÑьбітаў інфармацыі +Comment[bg]=Директен доÑтъп до ÑъхранÑващите уÑтройÑтва +Comment[bn]=আপনার সà§à¦Ÿà§‹à¦°à§‡à¦œ মিডিয়া সরাসরি খà§à¦²à§à¦¨ +Comment[bs]=Direktno pristupite vaÅ¡im ureÄ‘ajima +Comment[ca]=Accedeix directament als suports d'emmagatzematge +Comment[cs]=PÅ™Ãmý pÅ™Ãstup k úložným zaÅ™ÃzenÃm +Comment[csb]=Prosti przistãp do Twòjëch zôpisownëch mediów +Comment[da]=Direkte adgang til opbevaringsmedie +Comment[de]=Direkter Zugriff auf Ihre Speichermedien +Comment[el]=Απευθείας Ï€Ïόσβαση στις συσκευÎÏ‚ αποθήκευσής σας +Comment[eo]=Rekte atingi vian konservejon +Comment[es]= Acceso directo a sus dispositivos de almacenamiento +Comment[et]=Ligipääs andmekandjatele +Comment[eu]=Atzitu zure biltegiratze-euskarriak +Comment[fa]=دستیابی مستقیم رسانۀ ذخیره‌گاه شما +Comment[fi]=Tallennuslaitteet näyttävä paneelisovelma +Comment[fr]=Accès direct aux périphériques de stockage +Comment[fy]=Direkte tagong ta jo opslachmedia +Comment[gl]=Unha applet que mostra os seus dispositivos +Comment[he]=גישה ישירה ×ל ×”×”×ª×§× ×™× ×©×œ×š +Comment[hr]=Izravni pristup medijima za pohranjivanje +Comment[hu]=A tárolóeszközök közvetlen elérése +Comment[is]=Beinn aðgangur að geymslumiðlum +Comment[it]=Accesso diretto ai dispositivi di archiviazione +Comment[ja]=記憶メディアã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹ +Comment[ka]=თქვენი შენáƒáƒ®áƒ•áƒ˜áƒ¡ მედიის პირდáƒáƒžáƒ˜áƒ ი წვდáƒáƒ›áƒ +Comment[kk]=Жинақтаушыларыңызды тез ашу +Comment[km]=ចូលដំណើរការ​ឧបករណáŸâ€‹áž•áŸ’ទុក​របស់​អ្នក​ដោយ​ផ្ទាល់ +Comment[lt]=Tiesiogiai pasiekite savo saugojimo įrenginius +Comment[mk]=ПриÑтапете директно на вашите медиуми за податоци +Comment[nb]=Direkte tilgang til lagringsenheter +Comment[nds]=Direktemang op Dien Spiekermedien togriepen +Comment[ne]=à¤à¤£à¥à¤¡à¤¾à¤°à¤£ मिडियामा तपाईà¤à¤•à¥‹ पà¥à¤°à¤¤à¥à¤¯à¤•à¥à¤· पहà¥à¤à¤š +Comment[nl]=Directe toegang tot uw opslagmedia +Comment[nn]=Direkte tilgang til lagringseiningar +Comment[pa]=ਜੋ ਕਿ ਤà©à¨¹à¨¾à¨¡à¨¾ ਸਟੋਰੇਜ਼ ਮਾਧਿਅਮ ਵੇਖਾਉਦਾ ਹੈ। +Comment[pl]=BezpoÅ›redni dostÄ™p do Twoich urzÄ…dzeÅ„ przechowywania danych +Comment[pt]=Aceder directamente aos seus suportes de armazenamento +Comment[pt_BR]=Acesso direto à s suas mÃdias de armazenamento +Comment[ro]=Accesează direct dispozitivele de stocare +Comment[ru]=Ðплет панели, показывающий уÑтройÑтва Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ +Comment[se]=Njuolggoluotta vurkenmediaide +Comment[sk]=Priamy prÃstup na zálohovacie médiá +Comment[sl]=Neposreden dostop do nosilcev za shranjevanje +Comment[sr]=Директно приÑтупите Ñкладишним медијима +Comment[sr@Latn]=Direktno pristupite skladiÅ¡nim medijima +Comment[sv]=Direkt Ã¥tkomst av lagringsmedia +Comment[th]=เข้าใช้งานสื่à¸à¸—ี่เà¸à¹‡à¸šà¸‚้à¸à¸¡à¸¹à¸¥à¸‚à¸à¸‡à¸„ุณโดยตรง +Comment[tr]=Depolama aygıtlarına doÄŸrudan eriÅŸim +Comment[uk]=БезпоÑередній доÑтуп до приÑтроїв Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— +Comment[uz]=Saqlash usunalariga qisqa yoÊ»l +Comment[uz@cyrillic]=Сақлаш уÑуналарига қиÑқа йўл +Comment[vi]=Truy cáºp ngay và o các ổ chứa dữ liệu của bạn +Comment[wa]=Accès direk a vos sopoirts di wÃ¥rdaedje +Comment[zh_CN]=直接访问您的å˜å‚¨ä»‹è´¨ +Comment[zh_TW]=直接å˜å–您的儲å˜åª’é«” +Name=Storage Media +Name[af]=Stoor Media +Name[ar]=وسائط التخزين +Name[be]=ÐоÑьбіты +Name[bg]=СъхранÑващи уÑтройÑтва +Name[bn]=সà§à¦Ÿà§‹à¦°à§‡à¦œ মিডিয়া +Name[bs]=UreÄ‘aji za smjeÅ¡taj podataka +Name[ca]=Suports d'emmagatzematge +Name[cs]=Úložná zaÅ™Ãzenà +Name[csb]=Zôpisowné media +Name[da]=Opbevaringsmedie +Name[de]=Speichermedien +Name[el]=ΣυσκευÎÏ‚ αποθήκευσης +Name[eo]=Enmemoriga Medio +Name[es]=Dispositivos de almacenamiento +Name[et]=Andmekandjad +Name[eu]=Biltegiratze-euskarria +Name[fa]=رسانۀ ذخیره‌گاه +Name[fi]=Tallennusmedia +Name[fr]=Support de stockage +Name[fy]=Opslachapparaten +Name[ga]=Meán Stórais +Name[gl]=Medios de armacenaxe +Name[he]=×”×ª×§× ×™× +Name[hi]=à¤à¤‚डार मीडिया +Name[hr]=Mediji za pohranjivanje +Name[hu]=Tárolóeszközök +Name[is]=Geymslumiðlar +Name[it]=Dispositivi di archiviazione +Name[ja]=記憶メディア +Name[ka]=მáƒáƒœáƒáƒªáƒ”მთრშენáƒáƒ®áƒ•áƒ˜áƒ¡ მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ები +Name[kk]=Жинақтаушы құрылғылар +Name[km]=ឧបករណáŸâ€‹áž•áŸ’ទុក +Name[lt]=Saugojimo įrenginiai +Name[lv]=Datu nesÄ“js +Name[mk]=Медиуми за податоци +Name[ms]=Media Storan +Name[nb]=Lagringsenheter +Name[nds]=Spiekermedien +Name[ne]=à¤à¤£à¥à¤¡à¤¾à¤°à¤£ मिडिया +Name[nl]=Opslagapparaten +Name[nn]=Lagringsmedium +Name[pa]=ਸਟੋਰੇਜ਼ ਮੀਡਿਆ +Name[pl]=UrzÄ…dzenia przechowywania danych +Name[pt]=Dispositivos de Armazenamento +Name[pt_BR]=MÃdia de Armazenamento +Name[ro]=Mediu de stocare +Name[ru]=УÑтройÑтва Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… +Name[rw]=Uburyo bwo Kubika +Name[se]=Vurkenmedia +Name[sk]=Zálohovacie médiá +Name[sl]=Nosilci za shranjevanje +Name[sr]=Складишни медијуми +Name[sr@Latn]=SkladiÅ¡ni medijumi +Name[sv]=Lagringsmedia +Name[ta]=சேகரிபà¯à®ªà¯ ஊடகம௠+Name[tg]=Захирагоҳи маълумот +Name[th]=สื่à¸à¹€à¸à¹‡à¸šà¸‚้à¸à¸¡à¸¹à¸¥ +Name[tr]=Depolama Ortamı +Name[tt]=Saqlawlı Media +Name[uk]=ПриÑтрої Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— +Name[uz]=Saqlash uskunalari +Name[uz@cyrillic]=Сақлаш уÑкуналари +Name[vi]=á»” chứa Dữ liệu +Name[wa]=Sopoirts di wÃ¥rdaedje +Name[zh_CN]=å˜å‚¨ä»‹è´¨ +Name[zh_TW]=儲å˜åª’é«” +Icon=3floppy_unmount +X-KDE-Library=media_panelapplet diff --git a/kicker/applets/media/mediaapplet.h b/kicker/applets/media/mediaapplet.h new file mode 100644 index 000000000..5e2320be0 --- /dev/null +++ b/kicker/applets/media/mediaapplet.h @@ -0,0 +1,79 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MEDIAAPPLET_H +#define MEDIAAPPLET_H + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <kpanelapplet.h> +#include <qstring.h> +#include <kconfig.h> +#include <kurl.h> +#include <kfileitem.h> +#include <kdirlister.h> + +#include <qptrlist.h> +#include "mediumbutton.h" +typedef QValueList<MediumButton*> MediumButtonList; + + +class MediaApplet : public KPanelApplet +{ +Q_OBJECT + +public: + MediaApplet(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~MediaApplet(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + void about(); + void preferences(); + +protected: + void arrangeButtons(); + void resizeEvent(QResizeEvent *e); + void positionChange(Position p); + void reloadList(); + void loadConfig(); + void saveConfig(); + void mousePressEvent(QMouseEvent *e); + +protected slots: + void slotClear(); + void slotStarted(const KURL &url); + void slotCompleted(); + void slotNewItems(const KFileItemList &entries); + void slotDeleteItem(KFileItem *fileItem); + void slotRefreshItems(const KFileItemList &entries); + +private: + KDirLister *mpDirLister; + MediumButtonList mButtonList; + QStringList mExcludedTypesList; + QStringList mExcludedList; + KFileItemList mMedia; + int mButtonSizeSum; +}; + +#endif diff --git a/kicker/applets/media/mediumbutton.cpp b/kicker/applets/media/mediumbutton.cpp new file mode 100644 index 000000000..2c96601ea --- /dev/null +++ b/kicker/applets/media/mediumbutton.cpp @@ -0,0 +1,202 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mediumbutton.h" + +#include <qapplication.h> +#include <qclipboard.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qpopupmenu.h> +#include <qstyle.h> +#include <qtooltip.h> + +#include <kmessagebox.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kdesktopfile.h> +#include <krun.h> +#include <kglobalsettings.h> +#include <kcursor.h> +#include <kapplication.h> +#include <kipc.h> +#include <kiconloader.h> +#include <kurldrag.h> +#include <kpopupmenu.h> + +#include <konq_operations.h> +#include <konq_popupmenu.h> +#include <konq_drag.h> + +MediumButton::MediumButton(QWidget *parent, const KFileItem &fileItem) + : PanelPopupButton(parent), mActions(this, this), mFileItem(fileItem) +{ + KAction *a = KStdAction::paste(this, SLOT(slotPaste()), + &mActions, "pasteto"); + a->setShortcut(0); + a = KStdAction::copy(this, SLOT(slotCopy()), &mActions, "copy"); + a->setShortcut(0); + + setBackgroundOrigin(AncestorOrigin); + + resize(20, 20); + + setAcceptDrops(mFileItem.isWritable()); + + setTitle(mFileItem.text()); + + refreshType(); + + connect(&mOpenTimer, SIGNAL(timeout()), SLOT(slotDragOpen())); + + // Activate this code only if we find a way to have both an + // action and a popup menu for the same kicker button + //connect(this, SIGNAL(clicked()), this, SLOT(slotClicked())); + + setPopup(new QPopupMenu()); +} + +MediumButton::~MediumButton() +{ + QPopupMenu *menu = popup(); + setPopup(0); + delete menu; +} + +const KFileItem &MediumButton::fileItem() const +{ + return mFileItem; +} + +void MediumButton::setFileItem(const KFileItem &fileItem) +{ + mFileItem.assign(fileItem); + setAcceptDrops(mFileItem.isWritable()); + setTitle(mFileItem.text()); + refreshType(); +} + +void MediumButton::initPopup() +{ + QPopupMenu *old_popup = popup(); + + KFileItemList items; + items.append(&mFileItem); + + KonqPopupMenu::KonqPopupFlags kpf = + KonqPopupMenu::ShowProperties + | KonqPopupMenu::ShowNewWindow; + + KParts::BrowserExtension::PopupFlags bef = + KParts::BrowserExtension::DefaultPopupItems; + + KonqPopupMenu *new_popup = new KonqPopupMenu(0L, items, + KURL("media:/"), mActions, 0L, + this, kpf, bef); + KPopupTitle *title = new KPopupTitle(new_popup); + title->setTitle(mFileItem.text()); + + new_popup->insertItem(title, -1, 0); + + setPopup(new_popup); + + if (old_popup!=0L) delete old_popup; +} + +void MediumButton::refreshType() +{ + KMimeType::Ptr mime = mFileItem.determineMimeType(); + QToolTip::add(this, mime->comment()); + setIcon(mime->icon(QString::null, false)); +} + +// Activate this code only if we find a way to have both an +// action and a popup menu for the same kicker button +/* +void MediumButton::slotClicked() +{ + mFileItem.run(); +} +*/ + +void MediumButton::slotPaste() +{ + KonqOperations::doPaste(this, mFileItem.url()); +} + +void MediumButton::slotCopy() +{ + KonqDrag * obj = KonqDrag::newDrag(mFileItem.url(), false); + + QApplication::clipboard()->setData( obj ); +} + +void MediumButton::dragEnterEvent(QDragEnterEvent* e) +{ + if (mFileItem.isWritable()) + { + mOpenTimer.start(1000, true); + e->accept(true); + } +} + +void MediumButton::dragLeaveEvent(QDragLeaveEvent* e) +{ + mOpenTimer.stop(); + + PanelPopupButton::dragLeaveEvent( e ); +} + +void MediumButton::dropEvent(QDropEvent *e) +{ + mOpenTimer.stop(); + + KonqOperations::doDrop(&mFileItem, mFileItem.url(), e, this); +} + +void MediumButton::slotDragOpen() +{ + mFileItem.run(); +} + +QString MediumButton::tileName() +{ + return mFileItem.text(); +} + +void MediumButton::setPanelPosition(KPanelApplet::Position position) +{ + switch(position) + { + case KPanelApplet::pBottom: + setPopupDirection(KPanelApplet::Up); + break; + case KPanelApplet::pTop: + setPopupDirection(KPanelApplet::Down); + break; + case KPanelApplet::pRight: + setPopupDirection(KPanelApplet::Left); + break; + case KPanelApplet::pLeft: + setPopupDirection(KPanelApplet::Right); + break; + } +} + +#include "mediumbutton.moc" diff --git a/kicker/applets/media/mediumbutton.h b/kicker/applets/media/mediumbutton.h new file mode 100644 index 000000000..8d7970d89 --- /dev/null +++ b/kicker/applets/media/mediumbutton.h @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MEDIUMBUTTON_H +#define MEDIUMBUTTON_H + +#include <panelbutton.h> +#include <qpoint.h> +#include <qstring.h> +#include <qpixmap.h> +#include <qcursor.h> +#include <qtimer.h> +#include <kfileitem.h> +#include <kpanelapplet.h> +#include <kactioncollection.h> + +class MediumButton : public PanelPopupButton +{ +Q_OBJECT + +public: + MediumButton(QWidget *parent, const KFileItem &fileItem); + ~MediumButton(); + const KFileItem &fileItem() const; + void setFileItem(const KFileItem &fileItem); + void setPanelPosition(KPanelApplet::Position position); + +protected: + QString tileName(); + void refreshType(); + void initPopup(); + void dragEnterEvent( QDragEnterEvent* ); + void dragLeaveEvent( QDragLeaveEvent* ); + void dropEvent(QDropEvent *e); + +protected slots: + // Activate this code only if we find a way to have both an + // action and a popup menu for the same kicker button + //void slotClicked(); + void slotPaste(); + void slotCopy(); + void slotDragOpen(); + +private: + KActionCollection mActions; + KFileItem mFileItem; + QTimer mOpenTimer; +}; + +#endif diff --git a/kicker/applets/media/preferencesdialog.cpp b/kicker/applets/media/preferencesdialog.cpp new file mode 100644 index 000000000..179878e89 --- /dev/null +++ b/kicker/applets/media/preferencesdialog.cpp @@ -0,0 +1,167 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "preferencesdialog.h" + +#include <klocale.h> +#include <kmimetype.h> +#include <qvbox.h> +#include <qwhatsthis.h> +#include <klistview.h> +#include <kfiledetailview.h> + +class MediumTypeItem : public QCheckListItem +{ +public: + MediumTypeItem(QListView *parent, const QString name, + const QString mimetype) + : QCheckListItem(parent, name, CheckBox), + mMimeType(mimetype) { } + + const QString &mimeType() const { return mMimeType; } + +private: + QString mMimeType; +}; + +class MediumItem : public QCheckListItem +{ +public: + MediumItem(QListView *parent, const QString name, + const KFileItem medium) + : QCheckListItem(parent, name, CheckBox), + mMedium(medium) { } + + const QString itemURL() const { return mMedium.url().url(); } + +private: + KFileItem mMedium; +}; + + + +PreferencesDialog::PreferencesDialog(KFileItemList media, QWidget *parent, + const char *name) + : KDialogBase(Tabbed, i18n("Media Applet Preferences"), Ok|Cancel|Default, + Ok, parent, name, true), + mMedia(media) +{ + QVBox *types_page = addVBoxPage( i18n("Medium Types") ); + mpMediumTypesListView = new KListView(types_page); + + //mpMediumTypesListView->setFullWidth(true); + mpMediumTypesListView->addColumn( i18n("Types to Display") ); + QWhatsThis::add(mpMediumTypesListView, i18n("Deselect the medium types which you do not want to see in the applet")); + + + + QVBox *media_page = addVBoxPage( i18n("Media") ); + mpMediaListView = new KListView(media_page); + + //mpMediaListView->setFullWidth(true); + mpMediaListView->addColumn( i18n("Media to Display") ); + QWhatsThis::add(mpMediaListView, i18n("Deselect the media which you do not want to see in the applet")); + + slotDefault(); +} + +PreferencesDialog::~PreferencesDialog() +{ +} + +void PreferencesDialog::slotDefault() +{ + QStringList defaultExclude; + + defaultExclude << "media/hdd_mounted"; + defaultExclude << "media/hdd_unmounted"; + defaultExclude << "media/nfs_mounted"; + defaultExclude << "media/nfs_unmounted"; + defaultExclude << "media/smb_mounted"; + defaultExclude << "media/smb_unmounted"; + + setExcludedMediumTypes(defaultExclude); + setExcludedMedia(QStringList()); +} + +QStringList PreferencesDialog::excludedMediumTypes() +{ + QStringList excludedTypes; + + for(MediumTypeItem *it=static_cast<MediumTypeItem *>(mpMediumTypesListView->firstChild()); + it; it=static_cast<MediumTypeItem *>(it->nextSibling())) + { + if(!it->isOn()) excludedTypes << it->mimeType(); + } + + return excludedTypes; +} + +void PreferencesDialog::setExcludedMediumTypes(QStringList excludedTypesList) +{ + mpMediumTypesListView->clear(); + mpMediumTypesListView->setRootIsDecorated(false); + KMimeType::List mimetypes = KMimeType::allMimeTypes(); + + QValueListIterator<KMimeType::Ptr> it(mimetypes.begin()); + + for(; it != mimetypes.end(); ++it) + { + if ((*it)->name().startsWith("media/")) + { + bool ok=excludedTypesList.contains((*it)->name())==0; + MediumTypeItem *item = new MediumTypeItem(mpMediumTypesListView, (*it)->comment(), (*it)->name()); + item->setOn(ok); + } + } +} + +QStringList PreferencesDialog::excludedMedia() +{ + QStringList excluded; + + for(MediumItem *it=static_cast<MediumItem *>(mpMediaListView->firstChild()); + it; it=static_cast<MediumItem *>(it->nextSibling())) + { + if(!it->isOn()) excluded << it->itemURL(); + } + + return excluded; +} + +void PreferencesDialog::setExcludedMedia(QStringList excludedList) +{ + mpMediaListView->clear(); + mpMediaListView->setRootIsDecorated(false); + + KFileItemListIterator it( mMedia ); + KFileItem *file; + while ( (file = it.current()) != 0 ) + { + ++it; + + bool ok = excludedList.contains(file->url().url())==0; + MediumItem *item = new MediumItem(mpMediaListView, + file->text(), *file); + item->setOn(ok); + } +} + + +#include "preferencesdialog.moc" diff --git a/kicker/applets/media/preferencesdialog.h b/kicker/applets/media/preferencesdialog.h new file mode 100644 index 000000000..bb400564b --- /dev/null +++ b/kicker/applets/media/preferencesdialog.h @@ -0,0 +1,53 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include <qwidget.h> +#include <kdialogbase.h> +#include <kfileitem.h> + +/** + *@author ervin + */ + +class PreferencesDialog : public KDialogBase +{ + Q_OBJECT +public: + PreferencesDialog(KFileItemList media, QWidget *parent=0, const char *name=0); + ~PreferencesDialog(); + + QStringList excludedMediumTypes(); + void setExcludedMediumTypes(QStringList excludedTypesList); + + QStringList excludedMedia(); + void setExcludedMedia(QStringList excludedList); + +protected slots: + void slotDefault(); + +private: + KListView *mpMediumTypesListView; + KListView *mpMediaListView; + KFileItemList mMedia; +}; + +#endif diff --git a/kicker/applets/menu/Makefile.am b/kicker/applets/menu/Makefile.am new file mode 100644 index 000000000..5bfaeee18 --- /dev/null +++ b/kicker/applets/menu/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = menu_panelapplet.la + +menu_panelapplet_la_SOURCES = menuapplet.cpp menuapplet.skel + +noinst_HEADERS = menuapplet.h + +menu_panelapplet_la_METASOURCES = AUTO + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = menuapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +menu_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +menu_panelapplet_la_LIBADD = $(LIB_KDEUI) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/kmenuapplet.pot diff --git a/kicker/applets/menu/menuapplet.cpp b/kicker/applets/menu/menuapplet.cpp new file mode 100644 index 000000000..ae10614c6 --- /dev/null +++ b/kicker/applets/menu/menuapplet.cpp @@ -0,0 +1,511 @@ +/***************************************************************** + +Copyright (c) 2002 Siegfried Nijssen <snijssen@liacs.nl> +Copyright (c) 2003 Lubos Lunak <l.lunak@suse.cz> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#define _MENUAPPLET_CPP_ + +#include "menuapplet.h" + +#include <qlayout.h> +#include <qtooltip.h> +#include <qvariant.h> // avoid X11 #define's + +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kwin.h> +#include <kwinmodule.h> + +#include <netwm.h> + +#include <X11/Xlib.h> + +/* + + KMenuBar from KDE3.1 and older won't work very well with this applet. + This is because QMenuBar tries really hard to keep its preffered size, + se even if the X window for the menubar has the size enforced by this + applet, Qt thinks it has the size Qt wants. This results in parts + of the menubar not being repainted. Also, old KMenuBar always forced + with to be the width of the screen, so even if the menubar has only + few entries, this applet will still indicate the menubar doesn't + fit completely in it. There's no way to fix this, besides upgrading + to KDE3.2. + +*/ + + +extern Time qt_x_time; + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget* parent_P, const QString& configFile_P ) + { + KGlobal::locale()->insertCatalogue("kmenuapplet"); + return new KickerMenuApplet::Applet( configFile_P, parent_P ); + } +} + +namespace KickerMenuApplet +{ + +static const int MOVE_DIFF = 100; // size increment for left/right menu moving +static const int GROW_WIDTH = 10; // width of grow buttons + +const long SUPPORTED_WINDOW_TYPES = NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask + | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask; + +Applet::Applet( const QString& configFile_P, QWidget* parent_P ) + : KPanelApplet( configFile_P, Normal, 0, parent_P, "menuapplet" ), + DCOPObject( "menuapplet" ), + module( NULL ), + active_menu( NULL ), + selection( NULL ), + selection_watcher( NULL ), + desktop_menu( false ), + topEdgeOffset( 0 ) + { + setBackgroundOrigin(AncestorOrigin); + dcopclient.registerAs( "menuapplet", false ); + // toolbarAppearanceChanged(int) is sent when changing macstyle + connect( kapp, SIGNAL( toolbarAppearanceChanged( int )), + this, SLOT( readSettings())); + claimSelection(); + readSettings(); + updateTopEdgeOffset(); + } + +Applet::~Applet() + { + lostSelection(); // release all menu's before really loosing the selection + delete selection; + delete selection_watcher; + delete module; + KGlobal::locale()->removeCatalogue("kmenuapplet"); + } + +void Applet::windowAdded( WId w_P ) + { + NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(), NET::WMWindowType ); + if( info.windowType( SUPPORTED_WINDOW_TYPES ) != NET::TopMenu ) + return; +// kdDebug() << "embedding:" << w_P << endl; + Window transient_for = KWin::transientFor( w_P ); + if( transient_for == None ) + return; + MenuEmbed* embed; + if( transient_for == qt_xrootwin()) + { + embed = new MenuEmbed( transient_for, true, this ); + } + else + { + KWin::WindowInfo info2 = KWin::windowInfo( transient_for, NET::WMWindowType ); + embed = new MenuEmbed( transient_for, + info2.windowType( SUPPORTED_WINDOW_TYPES ) == NET::Desktop, this ); + } + embed->hide(); + embed->move( 0, -topEdgeOffset ); + embed->resize( embed->width(), height() + topEdgeOffset ); + embed->embed( w_P ); + if( embed->embeddedWinId() == None ) + { + delete embed; + return; + } + menus.append( embed ); + // in case the app mapped its menu after its mainwindow, check which menu should be shown + activeWindowChanged( module->activeWindow()); + } + +// - if the active window has its topmenu -> show the menu +// - if desktop menu is enabled (i.e. explicitly in kdesktop) : +// - show it +// - otherwise show nothing +void Applet::activeWindowChanged( WId w_P ) + { +// kdDebug() << "active:" << w_P << endl; + for( WId window = w_P; + window != None; + window = tryTransientFor( window )) + { + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( window == (*it)->mainWindow()) + { + activateMenu( *it ); + return; + } + } + } +// kdDebug() << "no active" << endl; + // No menu for active window found - if desktop menu + // (in kdesktoprc) is enabled, use kdesktop's menu instead of none. + bool try_desktop = desktop_menu; + if( !try_desktop && w_P != None ) + { // also use the desktop menu if the active window is desktop + KWin::WindowInfo info = KWin::windowInfo( w_P, NET::WMWindowType ); + if( info.windowType( SUPPORTED_WINDOW_TYPES ) == NET::Desktop ) + try_desktop = true; + } + if( try_desktop ) + { + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( (*it)->isDesktopMenu()) + { + activateMenu( *it ); + return; + } + } + } + activateMenu( NULL ); + } + +void Applet::activateMenu( MenuEmbed* embed_P ) + { + if( embed_P != active_menu ) + { +// kdDebug() << "activate:" << embed_P << endl; + if( active_menu != NULL ) + active_menu->hide(); + active_menu = embed_P; + if( active_menu != NULL ) + { + active_menu->show(); + //if (embed->isDesktopMenu()) + { + active_menu->setMinimumSize( width(), height() + topEdgeOffset ); + } + } + emit updateLayout(); + } + + setBackground(); + } + +void Applet::updateMenuGeometry( MenuEmbed* embed ) + { + if( embed == active_menu ) + emit updateLayout(); + } + +// If there's no menu for the window, try finding menu for its mainwindow +// (where the window's WM_TRANSIENT_FOR property points). +// If the window is modal (_NET_WM_STATE_MODAL), stop. +WId Applet::tryTransientFor( WId w_P ) + { + KWin::WindowInfo info = KWin::windowInfo( w_P, NET::WMState ); + if( info.state() & NET::Modal ) + return None; + WId ret = KWin::transientFor( w_P ); + if( ret == qt_xrootwin()) + ret = None; + return ret; + } + +void Applet::menuLost( MenuEmbed* embed ) + { + for( QValueList< MenuEmbed* >::Iterator it = menus.begin(); + it != menus.end(); + ++it ) + { + if( *it == embed ) + { + menus.remove( it ); + embed->deleteLater(); +// kdDebug() << "deleting:" << (*it)->mainWindow() << endl; + if( embed == active_menu ) + { + active_menu = NULL; + // trigger selecting new active menu + activeWindowChanged( module->activeWindow()); + } + return; + } + } + } + +void Applet::positionChange( Position ) + { + updateTopEdgeOffset(); + } + +// Detect mouse movement at the top screen edge also if the menubar +// has a popup open - in such case, Qt has a grab, and this avoids +// Kicker's FittsLawFrame. Therefore move the menubar a bit higher, +// so that it actually is positioned exactly at the screen edge +// (i.e. at a negative y coordinate within this applet, due to +// Kicker's frame). +void Applet::updateTopEdgeOffset() + { + QPoint p = topLevelWidget()->mapToGlobal( QPoint( 0, 0 )); + if( p.y() <= 2 ) // 2 = work also when running in appletproxy + topEdgeOffset = mapToGlobal( QPoint( 0, 0 )).y() - p.y(); + else + topEdgeOffset = 0; + if( active_menu != NULL ) + active_menu->move( active_menu->x(), -topEdgeOffset ); + } + +void Applet::paletteChange(const QPalette & /* oldPalette */) +{ + setBackground(); +} + +void Applet::moveEvent( QMoveEvent* ) +{ + setBackground(); +} + +void Applet::setBackground() +{ + if (active_menu) + active_menu->setBackground(); +} + +void Applet::claimSelection() + { + assert( selection == NULL ); + selection = new KSelectionOwner( makeSelectionAtom(), DefaultScreen( qt_xdisplay())); +// force taking the selection, but don't kill previous owner + if( selection->claim( true, false )) + { + delete selection_watcher; + selection_watcher = NULL; + connect( selection, SIGNAL( lostOwnership()), SLOT( lostSelection())); + module = new KWinModule; + connect( module, SIGNAL( windowAdded( WId )), this, SLOT( windowAdded( WId ))); + connect( module, SIGNAL( activeWindowChanged( WId )), + this, SLOT( activeWindowChanged( WId ))); + QValueList< WId > windows = module->windows(); + for( QValueList< WId >::ConstIterator it = windows.begin(); + it != windows.end(); + ++it ) + windowAdded( *it ); + activeWindowChanged( module->activeWindow()); + } + else + lostSelection(); + } + +void Applet::lostSelection() + { + if( selection == NULL ) + return; +// kdDebug() << "lost selection" << endl; + for( QValueList< MenuEmbed* >::ConstIterator it = menus.begin(); + it != menus.end(); + ++it ) + delete (*it); // delete all MenuEmbed's = release all menus + menus.clear(); + active_menu = NULL; + if( selection_watcher == NULL ) + { + selection_watcher = new KSelectionWatcher( makeSelectionAtom(), DefaultScreen( qt_xdisplay())); + connect( selection_watcher, SIGNAL( lostOwner()), this, SLOT( claimSelection())); + } + delete module; + module = NULL; + selection->deleteLater(); + selection = NULL; + // selection_watcher stays + } + +void Applet::readSettings() + { + KConfig cfg( "kdesktoprc", true ); + cfg.setGroup( "Menubar" ); + desktop_menu = cfg.readBoolEntry( "ShowMenubar", false ); + cfg.setGroup( "KDE" ); + if( cfg.readBoolEntry( "macStyle", false ) || desktop_menu ) + QToolTip::remove( this ); + else + QToolTip::add( this, i18n( + "You do not appear to have enabled the standalone menubar; " + "enable it in the Behavior control module for desktop." )); + if( !isDisabled() && active_menu == NULL ) + activeWindowChanged( module->activeWindow()); //enforce desktop_menu + } + +void Applet::configure() + { + readSettings(); + } + +int Applet::widthForHeight( int ) const + { + if (active_menu) + return active_menu->width(); + return 0; // we're stretch applet + } + +int Applet::heightForWidth( int ) const + { + // *shrug* running this applet in vertical mode is a bad idea anyway + return 50; + } + +static Atom selection_atom = None; +static Atom msg_type_atom = None; + +static +void initAtoms() + { + char nm[ 100 ]; + sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( qt_xdisplay())); + char nm2[] = "_KDE_TOPMENU_MINSIZE"; + char* names[ 2 ] = { nm, nm2 }; + Atom atoms[ 2 ]; + XInternAtoms( qt_xdisplay(), names, 2, False, atoms ); + selection_atom = atoms[ 0 ]; + msg_type_atom = atoms[ 1 ]; + } + +Atom Applet::makeSelectionAtom() + { + if( selection_atom == None ) + initAtoms(); + return selection_atom; + } + +MenuEmbed::MenuEmbed( WId mainwindow_P, bool desktop_P, + QWidget* parent_P, const char* name_P ) + : QXEmbed( parent_P, name_P ), + main_window( mainwindow_P ), + desktop( desktop_P ) + { + setAutoDelete( false ); + } + +void MenuEmbed::windowChanged( WId w_P ) + { + if( w_P == None ) + static_cast< Applet* >( parent())->menuLost( this ); + } + +bool MenuEmbed::x11Event( XEvent* ev_P ) + { + if( ev_P->type == ConfigureRequest + && ev_P->xconfigurerequest.window == embeddedWinId() + && ev_P->xconfigurerequest.value_mask & ( CWWidth | CWHeight )) + { + XConfigureRequestEvent& ev = ev_P->xconfigurerequest; + QSize new_size = size(); + if( ev.value_mask & CWWidth ) + new_size.setWidth( ev.width ); + if( ev.value_mask & CWHeight ) + new_size.setHeight( ev.height ); + // resize when the embedded window resizes (still obey min size) +// kdDebug() << "RES:" << embeddedWinId() << ":" << ev.width << ":" << ev.height << endl; + if( ev.width != width() || ev.height != height()) + { + resize( ev.width, ev.height ); + static_cast< Applet* >( parent())->updateMenuGeometry( this ); + } + sendSyntheticConfigureNotifyEvent(); +// int x, y; +// unsigned int w, h, d, b; +// Window root; +// XGetGeometry( qt_xdisplay(), embeddedWinId(), &root, &x, &y, &w, &h, &b, &d ); +// kdDebug() << "RES3:" << width() << ":" << height() << ":" << w << ":" << h << endl; + return true; + } + return QXEmbed::x11Event( ev_P ); + } + +void MenuEmbed::sendSyntheticConfigureNotifyEvent() +{ + QPoint globalPos = mapToGlobal(QPoint(0,0)); + if (embeddedWinId()) { + XConfigureEvent c; + memset(&c, 0, sizeof(c)); + c.type = ConfigureNotify; + c.display = qt_xdisplay(); + c.send_event = True; + c.event = embeddedWinId(); + c.window = winId(); + c.x = globalPos.x(); + c.y = globalPos.y(); + c.width = width(); + c.height = height(); + c.border_width = 0; + c.above = None; + c.override_redirect = 0; + XSendEvent(qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c); + } +} + +void MenuEmbed::setMinimumSize( int w, int h ) +{ + QXEmbed::setMinimumSize( w, h ); + // tell the menubar also the allowed minimum size + // the applet won't allow resizing to smaller size + if( embeddedWinId() != None ) + { +// kdDebug() << "RES2:" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight() << endl; + XEvent ev; + ev.xclient.display = qt_xdisplay(); + ev.xclient.type = ClientMessage; + ev.xclient.window = embeddedWinId(); + assert( msg_type_atom != None ); + ev.xclient.message_type = msg_type_atom; + ev.xclient.format = 32; + ev.xclient.data.l[0] = qt_x_time; + ev.xclient.data.l[1] = minimumWidth(); + ev.xclient.data.l[2] = minimumHeight(); + ev.xclient.data.l[3] = 0; + ev.xclient.data.l[4] = 0; + XSendEvent( qt_xdisplay(), embeddedWinId(), False, NoEventMask, &ev ); + } +} + +void MenuEmbed::setBackground() +{ + const QPixmap *pbg = parentWidget()->backgroundPixmap(); + + if (pbg) + { + QPixmap bg(width(), height()); + bg.fill(parentWidget(), pos()); + setPaletteBackgroundPixmap(bg); + setBackgroundOrigin(WidgetOrigin); + } + else + unsetPalette(); + + hide(); + show(); + //XClearArea(x11Display(), embeddedWinId(), 0, 0, 0, 0, True); +} + +} // namespace + +#include "menuapplet.moc" diff --git a/kicker/applets/menu/menuapplet.desktop b/kicker/applets/menu/menuapplet.desktop new file mode 100644 index 000000000..741c2ae29 --- /dev/null +++ b/kicker/applets/menu/menuapplet.desktop @@ -0,0 +1,128 @@ +[Desktop Entry] +Hidden=true +Type=Plugin +Name=Menu +Name[af]=Kieslys +Name[ar]=قائمة +Name[be]=Меню +Name[bg]=Меню +Name[bn]=মেনৠ+Name[br]=Meuziad +Name[bs]=Meni +Name[ca]=Menú +Name[cs]=NabÃdka +Name[cy]=Dewislen +Name[de]=Menü +Name[el]=ÎœÎµÎ½Î¿Ï +Name[eo]=Menuo +Name[es]=Menú +Name[et]=Menüü +Name[eu]=Menua +Name[fa]=گزینگان +Name[fi]=Valikko +Name[ga]=Roghchlár +Name[he]=תפריט +Name[hi]=मेनà¥à¤¯à¥‚ +Name[hr]=Izbornik +Name[hu]=Menü +Name[is]=Valmynd +Name[ja]=メニュー +Name[ka]=მენიუ +Name[kk]=Мәзір +Name[km]=ម៉ឺនុយ +Name[lt]=Meniu +Name[lv]=IzvÄ“lne +Name[mk]=Мени +Name[mn]=ЦÑÑ +Name[nb]=Meny +Name[nds]=Menü +Name[ne]=मेनॠ+Name[nn]=Meny +Name[pa]=ਮੇਨੂ +Name[ro]=Meniu +Name[ru]=Меню +Name[rw]=Ibikubiyemo +Name[sl]=Meni +Name[sr]=Мени +Name[sr@Latn]=Meni +Name[sv]=Meny +Name[ta]=படà¯à®Ÿà®¿ +Name[te]=పటà±à°Ÿà°¿ +Name[tg]=Меню +Name[th]=เมนู +Name[tr]=Menü +Name[tt]=Saylaq +Name[uk]=Меню +Name[uz]=Menyu +Name[uz@cyrillic]=Меню +Name[vi]=Thá»±c Ä‘Æ¡n +Name[wa]=Dressêye +Name[zh_CN]=èœå• +Name[zh_TW]=é¸å–® +Comment=Applet embedding standalone menubars +Comment[ar]=بريمج يضمّن أشرطة قوائم منÙردة بذاتها +Comment[be]=Ðплет з убудаваным меню +Comment[bg]=СиÑтемен панел за вграждане на ÑамоÑтоÑтелни менюта +Comment[bn]=আলাদা মেনà§à¦¬à¦¾à¦° ধারণ করার উপযোগী অà§à¦¯à¦¾à¦ªà¦²à§‡à¦Ÿ +Comment[bs]=Applet koji uvezuje samostalne menije +Comment[ca]=Un applet encastat està ndard per a les barres de menú +Comment[cs]=Applet pohlcujÃcà samostatné liÅ¡ty s nabÃdkami +Comment[csb]=Aplet zbiérajÄ…cy ùwòlnioné lëstwë menu +Comment[cy]=Rhaglennig sy'n mewn-adeiladu bariau dewislen unigol +Comment[da]=Applet der indlejrer alenestÃ¥ende menulinjer +Comment[de]=Programm zur Einbettung einzelner Menüleisten +Comment[el]=ΜικÏοεφαÏμογή που ενσωματώνει αυτόνομες γÏαμμÎÏ‚ Î¼ÎµÎ½Î¿Ï +Comment[eo]=Aplikaĵeniganta solfunkcia menuzono +Comment[es]=Una miniaplicación que incluye barras de menú autónomas +Comment[et]=Aplett, mis põimib endasse isseisvaid menüüribasid +Comment[eu]=Menu-barrak txertaturik dituen appleta +Comment[fa]=میله گزینگان خوداتکای نهÙتۀ برنامک +Comment[fi]=Sovelma, joka pystyy upottamaan yksittäisiä valikkorivejä +Comment[fr]=Une applet intégrant les barres de menu externes +Comment[fy]=Een applet die lossteande menubalken ynslút +Comment[gl]=Barras de menu estándar con incrustamento de applets +Comment[he]=שורת ×ª×¤×¨×™×˜×™× ×ž×©×•×‘×¦×ª ×™×™×©×•×ž×•× ×™× ×”×¢×•×ž×“×ª ×‘×¤× ×™ עצמה +Comment[hi]=à¤à¤ªà¤²à¥‡à¤Ÿ à¤à¤®à¥à¤¬à¥‡à¤¡à¤¿à¤‚ग सà¥à¤Ÿà¥ˆà¤‚डअलोन मेनà¥à¤¯à¥‚बारà¥à¤¸ +Comment[hr]=Samostalne trake izbornika s ugraÄ‘enim apletima +Comment[hu]=Kisalkalmazásokat tartalmazni képes önálló menüsorok +Comment[is]=Smáforrit sem byggir inn sjálfstæðar valmyndastikur +Comment[it]=Applet per inglobare le barre dei menu +Comment[ja]=å˜ç‹¬ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ãƒãƒ¼ã«çµ„ã¿è¾¼ã‚€ã‚¢ãƒ—レット +Comment[ka]=áƒáƒžáƒšáƒ”ტი, რáƒáƒ›áƒ”ლიც áƒáƒ›áƒáƒ¢áƒ”ბს áƒáƒ•áƒ¢áƒáƒœáƒáƒ›áƒ˜áƒ£áƒ პáƒáƒœáƒ”ლებს +Comment[kk]=Бөлек мәзір панельдерді құру апплеті +Comment[km]=របារ​ម៉ឺនុយ​នៅ​ážáŸ‚​ឯង​ដែល​បង្កប់​ក្នុង​អាប់ភ្លáŸáž +Comment[lt]=Ä®skiepis, rodantis atskiras meniu dalis +Comment[lv]=SÄ«klietotne, kas iegulda pastÄvÄ«gas izvÄ“lnes +Comment[mk]=Ðплет кој ги вгнездува ÑамоÑтојните менија +Comment[ms]=Menu bar tersendiri pembenaman aplet +Comment[mt]=Applet li fiha menubars indipendenti +Comment[nb]=Et panelprogram som bygger inn frittstÃ¥ende menylinjer +Comment[nds]=Lüttprogramm för't Inbetten vun enkelte Warktüüchbalkens +Comment[ne]=à¤à¤ªà¥à¤²à¥‡à¤Ÿ समà¥à¤®à¤¿à¤²à¤¿à¤¤ गरà¥à¤¨à¥‡ सà¥à¤Ÿà¥à¤¯à¤¾à¤¨à¥à¤¡à¤…लोन मेनà¥à¤ªà¤Ÿà¥à¤Ÿà¥€ +Comment[nl]=Een applet die losstaande menubalken insluit +Comment[nn]=Eit panelprogram som kan innehalda frittstÃ¥ande menylinjer +Comment[pa]=ਇੱਕਲੀ ਮੇਨੂਪੱਟੀ à¨à¨ªà¨²à¨¿à¨Ÿ +Comment[pl]=Aplet zbierajÄ…cy uwolnione paski menu +Comment[pt]=Uma 'applet' que incorpora barras de menu autónomas +Comment[pt_BR]=Mini-aplicativo para embutir barras de menu ao painel +Comment[ro]=O miniaplicaÈ›ie ce înglobează bare de meniu +Comment[ru]=Ðплет, вÑтраивающий автономные панели меню +Comment[rw]=Apuleti zifitemo umwanya-ibikubiyemo wigenga +Comment[se]=PrográmmaÅ¡ mii vuojuha oktanas fálloholggaid +Comment[sk]=Applet pre samostatné pruhy menu +Comment[sl]=Vstavek, ki vkljuÄuje samostojne menijske vrstice +Comment[sr]=Ðплет за уграђивање ÑамоÑталних менија +Comment[sr@Latn]=Aplet za ugraÄ‘ivanje samostalnih menija +Comment[sv]=Miniprogram för inbäddning av fristÃ¥ende menyer +Comment[ta]=கà¯à®±à¯à®¨à®¿à®°à®²à¯ பொதிநà¯à®¤ தனியான மெனà¯à®ªà®Ÿà¯à®Ÿà®¿à®•à®³à¯ +Comment[th]=à¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸•à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸±à¸‡à¹à¸–บเมนูลงพาเนล +Comment[tr]=Yalnız menü çubuklarını gömen uygulamacık +Comment[tt]=Ayırım torÄŸan saylaq-tirälär berläşterüçe applet +Comment[uk]=Ðплет вбудовних окремих Ñмужок меню +Comment[vi]=Tiểu ứng dụng nhúng các thanh thá»±c Ä‘Æ¡n đứng riêng +Comment[wa]=Aplikete po fé ravaler des bÃ¥rs di dressêye totes seules +Comment[zh_CN]=嵌入独立èœå•æ çš„å°ç¨‹åº +Comment[zh_TW]=å–®ç¨ç½®æ–¼é¢æ¿ä¸çš„é¸å–®åˆ— + +X-KDE-Library=menu_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/menu/menuapplet.h b/kicker/applets/menu/menuapplet.h new file mode 100644 index 000000000..8374e897b --- /dev/null +++ b/kicker/applets/menu/menuapplet.h @@ -0,0 +1,258 @@ +/***************************************************************** + +Copyright (c) 2002 Siegfried Nijssen <snijssen@liacs.nl> +Copyright (c) 2003 Lubos Lunak <l.lunak@suse.cz> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _MENUAPPLET_H_ +#define _MENUAPPLET_H_ + +#include <assert.h> + +#include <qvaluelist.h> +#include <qevent.h> +#include <qxembed.h> + +#include <kpanelapplet.h> +#include <kmanagerselection.h> + +#include <dcopobject.h> +#include <dcopclient.h> + +#include <karrowbutton.h> + +class KWinModule; + +namespace KickerMenuApplet +{ + +class MenuEmbed; + +/** + * @short A central menu bar + * + * @description All status change, such as when an window is activated, + * a new window popped up, etc, is received via @ref KWin::WindowInfo and @ref + * NETWinInfo. Status changes for X selections are done via KSelectionWatcher. + * + * How it works in broad terms: KickerMenuApplet gets notified as soon a window + * changes(a new pops up etc.) and accordingly updates the list @ref menus, + * which contains all known menus. When a new window gains focus, it looks up the + * correct MenuEmbed in @ref menus, and then switches to that one. + * + * The documentation is a bit rusty -- read it with a critical eye. + * + * @author Siegfried Nijssen <snijssen@liacs.nl> + * @author Lubos Lunak <l.lunak@suse.cz> + */ + +class Applet : public KPanelApplet, public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + + /** + * Called by the Kicker configuration(KCM). Does in turn call + * readSettings(). + */ + ASYNC configure(); + +public: + Applet( const QString& configFile, QWidget *parent ); + virtual ~Applet(); + virtual int widthForHeight( int height ) const; + virtual int heightForWidth( int width ) const; + + /** + * Looks up @param embed in @ref menus, and removes it. + */ + void menuLost( MenuEmbed* embed ); + void updateMenuGeometry( MenuEmbed* embed ); + void setBackground(); + +protected: + + virtual void paletteChange(const QPalette& ); + virtual void positionChange( Position p ); + virtual void moveEvent(QMoveEvent *); + +private slots: + + /** + * Called each time a window is added. When the selection is + * initially claimed, it is called for every window. It does the big + * work, and does the embedding with MenuEmbed. + */ + void windowAdded( WId w ); + + /** + * Finds @p w's menubar in @see menus, and then activates it. + * + * @param w the activated window. + */ + void activeWindowChanged( WId w ); + + /** + * Called when the selection(selection_atom) is lost. Deletes the + * embedded menus, and starts listening for the selection again. + * + */ + void lostSelection(); + + /** + * Reads whether a central menu bar should be used or not, basically. + */ + void readSettings(); + void claimSelection(); + +private: + + /** + * Returns true if the selection is Not owned. That is, the menu applet + * isn't "running" and is listening for the selection to be released. + */ + bool isDisabled() const; + + WId tryTransientFor( WId w ); + + /** + * Does some sanity checks, and then sets active_menu to @param embed. + */ + void activateMenu( MenuEmbed* embed ); + + /** + * Creates msg_type_atom and selection_atom, and returns the latter. + */ + static Atom makeSelectionAtom(); + void updateTopEdgeOffset(); + KWinModule* module; + + /** + * List of all known menus. + */ + QValueList< MenuEmbed* > menus; + + /** + * A pointer to the current active menu, which is member + * of @ref menus. + */ + MenuEmbed* active_menu; + + KSelectionOwner* selection; + + /** + * Only the messenger. Dispatches signals to claimSelection(). + */ + KSelectionWatcher* selection_watcher; + + /** + * Whether the Desktop menu should be used, when a window + * with no menu is used. + */ + bool desktop_menu; + DCOPClient dcopclient; + + /** + * The distance to the top of the screen. + */ + int topEdgeOffset; +}; + +/** + * + * @author Siegfried Nijssen <snijssen@liacs.nl> + * @author Lubos Lunak <l.lunak@suse.cz> + */ +class MenuEmbed + : public QXEmbed +{ + Q_OBJECT + +public: + + /** + * Default constructor + * + * @param mainwindow window ID for the window to be plugged + * @param desktop true if @p mainwindow is the desktop + */ + MenuEmbed( WId mainwindow, bool desktop, + QWidget* parent = NULL, const char* name = NULL ); + + void setBackground(); + + /** + * @returns the window ID for the handled window. + */ + WId mainWindow() const; + + /** + */ + bool isDesktopMenu() const; + virtual void setMinimumSize( int w, int h ); + void setMinimumSize( const QSize& s ) { setMinimumSize( s.width(), s.height()); } + +protected: + + /** + * When @p w is None, that is the embedded window was lost, it calls + * menuLost() such that the this is deleted from @ref menus list. + */ + virtual void windowChanged( WId w ); + + virtual bool x11Event( XEvent* ev ); + +private: + + void sendSyntheticConfigureNotifyEvent(); + WId main_window; + + /** + * If the window is the desktop window. + */ + bool desktop; +}; + +inline +bool Applet::isDisabled() const +{ + assert( ( selection == NULL && selection_watcher != NULL ) + || ( selection != NULL && selection_watcher == NULL )); + return selection == NULL; +} + +inline +WId MenuEmbed::mainWindow() const +{ + return main_window; +} + +inline +bool MenuEmbed::isDesktopMenu() const +{ + return desktop; +} + +} // namespace + +#endif diff --git a/kicker/applets/minipager/Makefile.am b/kicker/applets/minipager/Makefile.am new file mode 100644 index 000000000..da149f468 --- /dev/null +++ b/kicker/applets/minipager/Makefile.am @@ -0,0 +1,25 @@ +INCLUDES = $(all_includes) -I$(srcdir)/../../taskmanager \ + -I$(srcdir)/../../libkicker -I../../libkicker + +kde_module_LTLIBRARIES = minipager_panelapplet.la + +minipager_panelapplet_la_SOURCES = pagerapplet.cpp pagerbutton.cpp pagersettings.kcfgc + +minipager_panelapplet_la_METASOURCES = AUTO +noinst_HEADERS = pagerapplet.h pagerbutton.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = minipagerapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +minipager_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +minipager_panelapplet_la_LIBADD = $(LIB_KDEUI) \ + ../../taskmanager/libtaskmanager.la \ + ../../libkicker/libkickermain.la + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kminipagerapplet.pot + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/kminipagerapplet kminipagerapplet *.h -lqt -lkdecore -lkdeui -lkfile diff --git a/kicker/applets/minipager/minipagerapplet.desktop b/kicker/applets/minipager/minipagerapplet.desktop new file mode 100644 index 000000000..df5dcfb03 --- /dev/null +++ b/kicker/applets/minipager/minipagerapplet.desktop @@ -0,0 +1,122 @@ +[Desktop Entry] +Type=Plugin +Name=Desktop Preview & Pager +Name[af]=Werkskerm Voorskou & Boodskapper +Name[be]=ПраглÑд працоўных Ñталоў Ñ– пÑйджар +Name[bg]=Изглед на екрана и пейджър +Name[bn]=ডেসà§à¦•à¦Ÿà¦ª পà§à¦°à¦¾à¦•à¦¦à¦°à§à¦¶à¦¨ à¦à¦¬à¦‚ পেজার +Name[bs]=Pregled i promjena radnih povrÅ¡ina +Name[ca]=Vista prèvia d'escriptori i paginador +Name[cs]=PÅ™epÃnaÄ a náhled ploch +Name[csb]=Przestôwnik ë przezérnik pùltów +Name[da]=Desktop-forhÃ¥ndsviser & -pager +Name[de]=Umschalten zwischen Arbeitsflächen +Name[el]=Î Ïοεπισκόπηση και αλλαγή επιφάνειας εÏγασίας +Name[eo]=Tabula antaÅrigardilo kaj paÄilo +Name[es]=Paginador y previsualizador del escritorio +Name[et]=Töölaudade eelvaatlus ja vahetaja +Name[eu]=Mahaigain aurrebista eta orrialdekatzailea +Name[fa]=پیش‌نمایش Ùˆ پی‌جوی رومیزی +Name[fi]=Työpöydän esikatselu ja sivutus +Name[fr]=Gestionnaire et aperçu des bureaux +Name[fy]=Buroblêdfoarbyld en Pager +Name[gl]=Antevisor e Paxinador do Escritório +Name[hr]=Pager i preglednik radne povrÅ¡ine +Name[hu]=Asztali elÅ‘nézet és lapozó +Name[is]=Skjáborðs forskoðari & flettir +Name[it]=Anteprime e gestione dei desktop +Name[ja]=デスクトッププレビューã¨ãƒšãƒ¼ã‚¸ãƒ£ +Name[ka]=სáƒáƒ›áƒ£áƒ¨áƒáƒ დáƒáƒ¤áƒ˜áƒ¡áƒ დრგვერდების ჩვენებრ+Name[kk]=Ò®Ñтелдер ақтарғышы +Name[km]=ការ​មើលផ្ទៃážáž»â€‹áž‡áž¶áž˜áž»áž“ និង​ភáŸáž€áž™áŸážš +Name[lt]=Darbastalių peržiÅ«rÄ—jimo ir puslapiavimo priemonÄ— +Name[mk]=Преглед и пејџер на раб. површина +Name[nb]=ForhÃ¥ndsvising og bytte av skrivebord +Name[nds]=Schriefdisch-Ãœmschalter & Vöransicht +Name[ne]=डेसà¥à¤•à¤Ÿà¤ª पूरà¥à¤µà¤¾à¤µà¤²à¥‹à¤•à¤¨ र पेजर +Name[nl]=Bureaubladvoorbeeld en pager +Name[nn]=Førehandsvising og byte av skrivebord +Name[pa]=ਵੇਹੜਾ à¨à¨²à¨• ਅਤੇ ਪੇਜ਼ਰ +Name[pl]=PrzeÅ‚Ä…cznik i przeglÄ…darka pulpitów +Name[pt]=Antevisão e Paginador do Ecrã +Name[pt_BR]=Pager & Pré-visualizador de Ãrea de Trabalho +Name[ro]=Paginator È™i previzualizor pentru desktop +Name[ru]=Переключатель рабочих Ñтолов +Name[se]=Čállinbevddiid ovdaÄájeheaddji ja molssodeaddji +Name[sk]=Náhľad a stránkovaÄ pracovnej plochy +Name[sl]=Ogledovalnik in pozivnik namizja +Name[sr]=Прегледач и пејџер радних површина +Name[sr@Latn]=PregledaÄ i pejdžer radnih povrÅ¡ina +Name[sv]=Förhandsgranskning och hantering av skrivbord +Name[te]=à°°à°‚à°—à°¸à±à°¥à°² à°®à±à°‚దౠవీకà±à°·à°£à°‚ & పెజరౠ+Name[th]=à¹à¸ªà¸”งตัวà¸à¸¢à¹ˆà¸²à¸‡à¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸žà¸·à¹‰à¸™à¸—ี่ทำงาน +Name[tr]=Masaüstü Önizleyici ve Sayfalayıcı +Name[uk]=ПереглÑд Ñтільниці Ñ– пейджер +Name[uz]=Ish stolining peyjeri +Name[uz@cyrillic]=Иш Ñтолининг пейжери +Name[vi]=Xem thá» Mà n hình ná»n & Chuyển đổi +Name[wa]=Préveyeu et pÃ¥djeu do scribanne +Name[zh_CN]=æ¡Œé¢é¢„览器和页é¢åˆ‡æ¢å™¨ +Name[zh_TW]=æ¡Œé¢é 覽與縮圖 + +Comment=Preview, manage and switch to multiple virtual desktops +Comment[af]=Voorskou van, bestuur van en wissel tussen veelvuldige virtuelewerkskerms +Comment[ar]=عايين، دبÙر Ùˆ بدل إلى Ø£Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ الوهمية المتعددة +Comment[be]=ПраглÑд, кіраванне Ñ– пераключÑнне між некалькімі віртуальнымі працоўнымі Ñталамі +Comment[bg]=Преглед, управление и превключване към виртуалните работни плотове +Comment[bs]=Pregledajte, upravljajte i mijenjajte radne povrÅ¡ine +Comment[ca]=Vista prèvia, gestió i canvi entre diversos escriptoris virtuals +Comment[cs]=Správa, náhled a pÅ™epÃnánà virtuálnÃch pracovnÃch ploch +Comment[csb]=Pòdzérk, sprôwianié ë przestôwianié wirtualnëch pùltów +Comment[da]=ForhÃ¥ndsvis, hÃ¥ndtér og skift mellem flere virtuelle desktoppe +Comment[de]=Vorschau und Verwaltung der virtuellen Arbeitsflächen. +Comment[el]=Î Ïοεπισκόπηση, διαχείÏιση και εναλλαγή σε πολλαπλÎÏ‚ εικονικÎÏ‚ επιφάνειες εÏγασίας +Comment[eo]=AntaÅrigardi, mastrumi kaj komuti al pluraj virtualaj labortabloj +Comment[es]=Previsualizar, gestionar y cambiar a múltiples escritorios virtuales +Comment[et]=Virtuaalsete töölaudade eelvaatlus, haldus ja vahetamine +Comment[eu]=Aurrebista, kudeatu eta aldatu mahaigain birtual anitzez +Comment[fa]=پیش‌نمایش، مدیریت Ùˆ سودهی به رومیزیهای مجازی چندگانه +Comment[fi]=Esikatsele, hallitse ja vaihda virtuaalisia työpöytiä +Comment[fr]=Affichage, gestion et changement des bureaux virtuels multiples +Comment[fy]=Foarbyld, beheare en skeakel nei meardere firtuele buroblêden +Comment[gl]=Xestione, cambie e antevexa múltiplos escritórios virtuais +Comment[he]=תצוגה מקדימה, והעברה של ×©×•×œ×—× ×•×ª עבודה וירטו××œ×™× +Comment[hr]=Pregled, upravljanje i prebacivanje izmeÄ‘u viÅ¡estrukih virtualnih radnih povrÅ¡ina +Comment[hu]=A virtuális asztalok elÅ‘nézete, kezelése, használata +Comment[is]=Forskoðaðu, stjórnaðu og flettu á milli marga sýndarskjáborða +Comment[it]=Gestisce, cambia e mostra le anteprime dei desktop virtuali multipli +Comment[ja]=複数ã®ä»®æƒ³ãƒ‡ã‚¹ã‚¯ãƒˆãƒƒãƒ—ã®ãƒ—レビューã€ç®¡ç†ã¨åˆ‡ã‚Šæ›¿ãˆ +Comment[kk]=Көп қиртуалды Ò¯Ñтелдерді қарау, баÑқару және олаға ауыÑу +Comment[km]=ការ​មើល​ជាមុន, គ្រប់គ្រង និង​ប្ážáž¼ážšâ€‹áž‘ៅពហុផ្ទៃážáž»â€‹áž“ិម្មិážâ€‹ +Comment[lt]=PeržiÅ«rÄ—kite, tvarkykite ir lengvai vaikÅ¡Äiokite tarp daugelio menamų darbastalių +Comment[mk]=Преглед, управување и префрлање на повеќе виртуелни работни површини +Comment[nb]=ForhÃ¥ndsvisning, hÃ¥ndtere og bytte til virtuelle skrivebord +Comment[nds]=Vöransicht un Pleeg vun virtuelle Schriefdischen +Comment[ne]=पूरà¥à¤µà¤¾à¤µà¤²à¥‹à¤•à¤¨ अनि पà¥à¤°à¤¬à¤¨à¥à¤§ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ र अवासà¥à¤¤à¤µà¤¿à¤• डेसà¥à¤•à¤Ÿà¤ªà¤®à¤¾ सà¥à¤µà¤¿à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Comment[nl]=Vooruitblik, beheer en schakel naar meerdere virtuele bureaubladen +Comment[nn]=Førehandsvis, handter og byt til virtuelle skrivebord +Comment[pa]=ਕਈ ਫ਼ਰਜ਼ੀ ਵੇਹੜਿਆਂ ਦੀ à¨à¨²à¨• ਵੇਖਣ, ਉਹਨਾਂ ਦੇ ਪਰਬੰਧ ਅਤੇ ਤਬਦੀਲ ਕਰਨ ਲਈ ਹੈ +Comment[pl]=PodglÄ…d, zarzÄ…dzanie i przeÅ‚Ä…czanie wirtualnych pulpitów +Comment[pt]=Antever, gerir e mudar para vários ecrãs virtuais +Comment[pt_BR]=Fornece uma pré-visualização, gerencia e alterna entre múltiplos ambientes de trabalho virtuais +Comment[ro]=Previzualizează, gestionează È™i schimbă desktop-uri virtuale +Comment[ru]=Переключение между виртуальными рабочими Ñтолами Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтью показа их Ñодержимого +Comment[sk]=Náhľad, nastavenie a prepÃnanie viacerých virtuálnych pracovných plôch +Comment[sl]=Predogled, upravljanje in preklapljanje za veÄ navideznih namizij +Comment[sr]=Прегледајте, управљајте, и пребацујте Ñе између радних површина +Comment[sr@Latn]=Pregledajte, upravljajte, i prebacujte se izmeÄ‘u radnih povrÅ¡ina +Comment[sv]=Förhandsgranska, hantera och byt mellan flera virtuella skrivbord +Comment[te]=à°®à±à°‚దౠవీకà±à°·à°£, à°Žà°•à±à°•à±à°µ మిధà±à°¯à°¾ à°°à°‚à°—à°¸à±à°¥à°²à°¾à°² నియంతà±à°°à°£ మరయౠమారà±à°ªà± +Comment[th]=ดูตัวà¸à¸¢à¹ˆà¸²à¸‡, จัดà¸à¸²à¸£à¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹„ปใช้พื้นที่ทำงานเสมืà¸à¸™à¸à¸·à¹ˆà¸™à¹† +Comment[uk]=ПереглÑд, ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð° Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð½Ð° багато віртуальних Ñтільниць +Comment[uz]=Virtual ish stollarini koÊ»rib chiqish, boshqarish va ularga oÊ»tish uchun qulay vosita +Comment[uz@cyrillic]=Виртуал иш Ñтолларини кўриб чиқиш, бошқариш ва уларга ўтиш учун қулай воÑита +Comment[vi]=Xem thá», quản lý và chuyển đổi giữa các mà n hình ná»n ảo +Comment[wa]=Prévey, manaedjî et candjî viè sacwants forveyous scribannes +Comment[zh_CN]=预览ã€ç®¡ç†åŠåˆ‡æ¢å¤šä¸ªè™šæ‹Ÿæ¡Œé¢ +Comment[zh_TW]=é 覽ã€ç®¡ç†ä¸¦åˆ‡æ›åˆ°å¤šå€‹è™›æ“¬æ¡Œé¢ + +Icon=kpager + +X-KDE-Library=minipager_panelapplet +X-KDE-UniqueApplet=false diff --git a/kicker/applets/minipager/pagerapplet.cpp b/kicker/applets/minipager/pagerapplet.cpp new file mode 100644 index 000000000..3ba87c0b1 --- /dev/null +++ b/kicker/applets/minipager/pagerapplet.cpp @@ -0,0 +1,906 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qpainter.h> +#include <qtooltip.h> +#include <qlineedit.h> +#include <qpopupmenu.h> +#include <qlayout.h> +#include <qbuttongroup.h> + +#include <dcopref.h> +#include <kglobalsettings.h> +#include <kwin.h> +#include <kwinmodule.h> +#include <kapplication.h> +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> +#include <kprocess.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <dcopclient.h> +#include <netwm.h> +#include <kmanagerselection.h> + +#include "global.h" +#include "kickertip.h" +#include "kickerSettings.h" +#include "kshadowengine.h" +#include "kshadowsettings.h" +#include "paneldrag.h" +#include "taskmanager.h" + +#include "pagerapplet.h" +#include "pagerapplet.moc" + +#ifdef FocusOut +#undef FocusOut +#endif + +const int knDesktopPreviewSize = 12; +const int knBtnSpacing = 1; + +// The previews tend to have a 4/3 aspect ratio +static const int smallHeight = 32; +static const int smallWidth = 42; + +// config menu id offsets +static const int rowOffset = 2000; +static const int labelOffset = 200; +static const int bgOffset = 300; + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("kminipagerapplet"); + return new KMiniPager(configFile, KPanelApplet::Normal, 0, parent, "kminipagerapplet"); + } +} + +KMiniPager::KMiniPager(const QString& configFile, Type type, int actions, + QWidget *parent, const char *name) + : KPanelApplet( configFile, type, actions, parent, name ), + m_layout(0), + m_desktopLayoutOwner( NULL ), + m_shadowEngine(0), + m_contextMenu(0), + m_settings( new PagerSettings(sharedConfig()) ) +{ + setBackgroundOrigin( AncestorOrigin ); + int scnum = QApplication::desktop()->screenNumber(this); + QRect desk = QApplication::desktop()->screenGeometry(scnum); + if (desk.width() <= 800) + { + KConfigSkeleton::ItemBool* item = dynamic_cast<KConfigSkeleton::ItemBool*>(m_settings->findItem("Preview")); + if (item) + { + item->setDefaultValue(false); + } + } + m_settings->readConfig(); + m_windows.setAutoDelete(true); + if (m_settings->preview()) + { + TaskManager::the()->trackGeometry(); + } + + m_group = new QButtonGroup(this); + m_group->setBackgroundOrigin(AncestorOrigin); + m_group->setFrameStyle(QFrame::NoFrame); + m_group->setExclusive( true ); + + setFont( KGlobalSettings::taskbarFont() ); + + m_kwin = new KWinModule(this); + m_activeWindow = m_kwin->activeWindow(); + m_curDesk = m_kwin->currentDesktop(); + + if (m_curDesk == 0) // kwin not yet launched + { + m_curDesk = 1; + } + + desktopLayoutOrientation = Qt::Horizontal; + desktopLayoutX = -1; + desktopLayoutY = -1; + + QSize s(m_kwin->numberOfViewports(m_kwin->currentDesktop())); + m_useViewports = s.width() * s.height() > 1; + + drawButtons(); + + connect( m_kwin, SIGNAL( currentDesktopChanged(int)), SLOT( slotSetDesktop(int) ) ); + connect( m_kwin, SIGNAL( currentDesktopViewportChanged(int, const QPoint&)), + SLOT(slotSetDesktopViewport(int, const QPoint&))); + connect( m_kwin, SIGNAL( numberOfDesktopsChanged(int)), SLOT( slotSetDesktopCount(int) ) ); + connect( m_kwin, SIGNAL( activeWindowChanged(WId)), SLOT( slotActiveWindowChanged(WId) ) ); + connect( m_kwin, SIGNAL( windowAdded(WId) ), this, SLOT( slotWindowAdded(WId) ) ); + connect( m_kwin, SIGNAL( windowRemoved(WId) ), this, SLOT( slotWindowRemoved(WId) ) ); + connect( m_kwin, SIGNAL( windowChanged(WId,unsigned int) ), this, SLOT( slotWindowChanged(WId,unsigned int) ) ); + connect( m_kwin, SIGNAL( desktopNamesChanged() ), this, SLOT( slotDesktopNamesChanged() ) ); + connect( kapp, SIGNAL(backgroundChanged(int)), SLOT(slotBackgroundChanged(int)) ); + + if (kapp->authorizeKAction("kicker_rmb") && kapp->authorizeControlModule("kde-kcmtaskbar.desktop")) + { + m_contextMenu = new QPopupMenu(); + connect(m_contextMenu, SIGNAL(aboutToShow()), SLOT(aboutToShowContextMenu())); + connect(m_contextMenu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + setCustomMenu(m_contextMenu); + } + + QValueList<WId>::ConstIterator it; + QValueList<WId>::ConstIterator itEnd = m_kwin->windows().end(); + for ( it = m_kwin->windows().begin(); it != itEnd; ++it) + { + slotWindowAdded( (*it) ); + } + + slotSetDesktop( m_curDesk ); + updateLayout(); +} + +KMiniPager::~KMiniPager() +{ + KGlobal::locale()->removeCatalogue("kminipagerapplet"); + delete m_contextMenu; + delete m_settings; + delete m_shadowEngine; +} + +void KMiniPager::slotBackgroundChanged(int desk) +{ + unsigned numDesktops = m_kwin->numberOfDesktops(); + if (numDesktops != m_desktops.count()) + { + slotSetDesktopCount(numDesktops); + } + + if (desk < 1 || (unsigned) desk > m_desktops.count()) + { + // should not happen, but better to be paranoid than crash + return; + } + + m_desktops[desk - 1]->backgroundChanged(); +} + +void KMiniPager::slotSetDesktop(int desktop) +{ + if (m_kwin->numberOfDesktops() > static_cast<int>(m_desktops.count())) + { + slotSetDesktopCount( m_kwin->numberOfDesktops() ); + } + + if (!m_useViewports && (desktop != KWin::currentDesktop())) + { + // this can happen when the user clicks on a desktop, + // holds down the key combo to switch desktops, lets the + // mouse go but keeps the key combo held. the desktop will switch + // back to the desktop associated with the key combo and then it + // becomes a race condition between kwin's signal and the button's + // signal. usually kwin wins. + return; + } + + m_curDesk = desktop; + if (m_curDesk < 1) + { + m_curDesk = 1; + } + + KMiniPagerButton* button = m_desktops[m_curDesk - 1]; + if (!button->isOn()) + { + button->toggle(); + } +} + +void KMiniPager::slotSetDesktopViewport(int desktop, const QPoint& viewport) +{ + // ### + Q_UNUSED(desktop); + QSize s(m_kwin->numberOfViewports(m_kwin->currentDesktop())); + slotSetDesktop((viewport.y()-1) * s.width() + viewport.x() ); +} + +void KMiniPager::slotButtonSelected( int desk ) +{ + if (m_kwin->numberOfViewports(m_kwin->currentDesktop()).width() * + m_kwin->numberOfViewports(m_kwin->currentDesktop()).height() > 1) + { + QPoint p; + + p.setX( (desk-1) * QApplication::desktop()->width()); + p.setY( 0 ); + + KWin::setCurrentDesktopViewport(m_kwin->currentDesktop(), p); + } + else + KWin::setCurrentDesktop( desk ); + + slotSetDesktop( desk ); +} + +int KMiniPager::widthForHeight(int h) const +{ + if (orientation() == Qt::Vertical) + { + return width(); + } + + int deskNum = m_kwin->numberOfDesktops() * m_kwin->numberOfViewports(0).width() + * m_kwin->numberOfViewports(0).height(); + + int rowNum = m_settings->numberOfRows(); + if (rowNum == 0) + { + if (h <= 32 || deskNum <= 1) + { + rowNum = 1; + } + else + { + rowNum = 2; + } + } + + int deskCols = deskNum/rowNum; + if(deskNum == 0 || deskNum % rowNum != 0) + deskCols += 1; + + int bw = (h / rowNum); + if( m_settings->labelType() != PagerSettings::EnumLabelType::LabelName ) + { + if (desktopPreview() || m_settings->backgroundType() == PagerSettings::EnumBackgroundType::BgLive) + { + bw = (int) ( bw * (double) QApplication::desktop()->width() / QApplication::desktop()->height() ); + } + } + else + { + // scale to desktop width as a minimum + bw = (int) (bw * (double) QApplication::desktop()->width() / QApplication::desktop()->height()); + QFontMetrics fm = fontMetrics(); + for (int i = 1; i <= deskNum; i++) + { + int sw = fm.width( m_kwin->desktopName( i ) ) + 8; + if (sw > bw) + { + bw = sw; + } + } + } + + // we add one to the width for the spacing in between the buttons + // however, the last button doesn't have a space on the end of it (it's + // only _between_ buttons) so we then remove that one pixel + return (deskCols * (bw + 1)) - 1; +} + +int KMiniPager::heightForWidth(int w) const +{ + if (orientation() == Qt::Horizontal) + { + return height(); + } + + int deskNum = m_kwin->numberOfDesktops() * m_kwin->numberOfViewports(0).width() + * m_kwin->numberOfViewports(0).height(); + int rowNum = m_settings->numberOfRows(); // actually these are columns now... oh well. + if (rowNum == 0) + { + if (w <= 48 || deskNum == 1) + { + rowNum = 1; + } + else + { + rowNum = 2; + } + } + + int deskCols = deskNum/rowNum; + if(deskNum == 0 || deskNum % rowNum != 0) + { + deskCols += 1; + } + + int bh = (w/rowNum) + 1; + if ( desktopPreview() ) + { + bh = (int) ( bh * (double) QApplication::desktop()->height() / QApplication::desktop()->width() ); + } + else if ( m_settings->labelType() == PagerSettings::EnumLabelType::LabelName ) + { + bh = fontMetrics().lineSpacing() + 8; + } + + // we add one to the width for the spacing in between the buttons + // however, the last button doesn't have a space on the end of it (it's + // only _between_ buttons) so we then remove that one pixel + int nHg = (deskCols * (bh + 1)) - 1; + + return nHg; +} + +void KMiniPager::updateDesktopLayout(int o, int x, int y) +{ + if ((desktopLayoutOrientation == o) && + (desktopLayoutX == x) && + (desktopLayoutY == y)) + { + return; + } + + desktopLayoutOrientation = o; + desktopLayoutX = x; + desktopLayoutY = y; + if( x == -1 ) // do-the-maths-yourself is encoded as 0 in the wm spec + x = 0; + if( y == -1 ) + y = 0; + if( m_desktopLayoutOwner == NULL ) + { // must own manager selection before setting global desktop layout + int screen = DefaultScreen( qt_xdisplay()); + m_desktopLayoutOwner = new KSelectionOwner( QString( "_NET_DESKTOP_LAYOUT_S%1" ).arg( screen ).latin1(), + screen, this ); + if( !m_desktopLayoutOwner->claim( false )) + { + delete m_desktopLayoutOwner; + m_desktopLayoutOwner = NULL; + return; + } + } + NET::Orientation orient = o == Qt::Horizontal ? NET::OrientationHorizontal : NET::OrientationVertical; + NETRootInfo i( qt_xdisplay(), 0 ); + i.setDesktopLayout( orient, x, y, NET::DesktopLayoutCornerTopLeft ); +} + +void KMiniPager::resizeEvent(QResizeEvent*) +{ + bool horiz = orientation() == Horizontal; + + int deskNum = m_desktops.count(); + int rowNum = m_settings->numberOfRows(); + if (rowNum == 0) + { + if (((horiz && height()<=32)||(!horiz && width()<=48)) || deskNum <= 1) + rowNum = 1; + else + rowNum = 2; + } + + int deskCols = deskNum/rowNum; + if(deskNum == 0 || deskNum % rowNum != 0) + deskCols += 1; + + if (m_layout) + { + delete m_layout; + m_layout = 0; + } + + int nDX, nDY; + if (horiz) + { + nDX = rowNum; + nDY = deskCols; + updateDesktopLayout(Qt::Horizontal, -1, nDX); + } + else + { + nDX = deskCols; + nDY = rowNum; + updateDesktopLayout(Qt::Horizontal, nDY, -1); + } + + // 1 pixel spacing. + m_layout = new QGridLayout(this, nDX, nDY, 0, 1); + + QValueList<KMiniPagerButton*>::Iterator it = m_desktops.begin(); + QValueList<KMiniPagerButton*>::Iterator itEnd = m_desktops.end(); + int c = 0, + r = 0; + while( it != itEnd ) { + c = 0; + while( (it != itEnd) && (c < nDY) ) { + m_layout->addWidget( *it, r, c ); + ++it; + ++c; + } + ++r; + } + + m_layout->activate(); + updateGeometry(); +} + +void KMiniPager::wheelEvent( QWheelEvent* e ) +{ + int newDesk; + int desktops = KWin::numberOfDesktops(); + if (m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height() > 1 ) + desktops = m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height(); + if (e->delta() < 0) + { + newDesk = m_curDesk % desktops + 1; + } + else + { + newDesk = (desktops + m_curDesk - 2) % desktops + 1; + } + + slotButtonSelected(newDesk); +} + +void KMiniPager::drawButtons() +{ + int deskNum = m_kwin->numberOfDesktops(); + KMiniPagerButton *desk; + + int count = 1; + int i = 1; + do + { + QSize viewportNum = m_kwin->numberOfViewports(i); + for (int j = 1; j <= viewportNum.width() * viewportNum.height(); ++j) + { + QSize s(m_kwin->numberOfViewports(m_kwin->currentDesktop())); + QPoint viewport( (j-1) % s.width(), (j-1) / s.width()); + desk = new KMiniPagerButton( count, m_useViewports, viewport, this ); + if ( m_settings->labelType() != PagerSettings::EnumLabelType::LabelName ) + { + QToolTip::add( desk, desk->desktopName() ); + } + + m_desktops.append( desk ); + m_group->insert( desk, count ); + + connect(desk, SIGNAL(buttonSelected(int)), + SLOT(slotButtonSelected(int)) ); + connect(desk, SIGNAL(showMenu(const QPoint&, int )), + SLOT(slotShowMenu(const QPoint&, int )) ); + + desk->show(); + ++count; + } + } + while ( ++i <= deskNum ); +} + +void KMiniPager::slotSetDesktopCount( int ) +{ + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for( it = m_desktops.begin(); it != itEnd; ++it ) + { + delete (*it); + } + m_desktops.clear(); + + drawButtons(); + + m_curDesk = m_kwin->currentDesktop(); + if ( m_curDesk == 0 ) + { + m_curDesk = 1; + } + + resizeEvent(0); + updateLayout(); +} + +void KMiniPager::slotActiveWindowChanged( WId win ) +{ + if (desktopPreview()) + { + KWin::WindowInfo* inf1 = m_activeWindow ? info( m_activeWindow ) : NULL; + KWin::WindowInfo* inf2 = win ? info( win ) : NULL; + m_activeWindow = win; + + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for ( it = m_desktops.begin(); it != itEnd; ++it) + { + if ( ( inf1 && (*it)->shouldPaintWindow(inf1)) || + ( inf2 && (*it)->shouldPaintWindow(inf2)) ) + { + (*it)->windowsChanged(); + } + } + } +} + +void KMiniPager::slotWindowAdded( WId win) +{ + if (desktopPreview()) + { + KWin::WindowInfo* inf = info( win ); + + if (inf->state() & NET::SkipPager) + { + return; + } + + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for ( it = m_desktops.begin(); it != itEnd; ++it) + { + if ( (*it)->shouldPaintWindow(inf) ) + { + (*it)->windowsChanged(); + } + } + } +} + +void KMiniPager::slotWindowRemoved(WId win) +{ + if (desktopPreview()) + { + KWin::WindowInfo* inf = info(win); + bool onAllDesktops = inf->onAllDesktops(); + bool onAllViewports = inf->hasState(NET::Sticky); + bool skipPager = inf->state() & NET::SkipPager; + int desktop = inf->desktop(); + + if (win == m_activeWindow) + m_activeWindow = 0; + + m_windows.remove((long) win); + + if (skipPager) + { + return; + } + + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for (it = m_desktops.begin(); it != itEnd; ++it) + { + if (onAllDesktops || onAllViewports || desktop == (*it)->desktop()) + { + (*it)->windowsChanged(); + } + } + } + else + { + m_windows.remove(win); + return; + } + +} + +void KMiniPager::slotWindowChanged( WId win , unsigned int properties ) +{ + if ((properties & (NET::WMState | NET::XAWMState | NET::WMDesktop)) == 0 && + (!desktopPreview() || (properties & NET::WMGeometry) == 0) && + !(desktopPreview() && windowIcons() && + (properties & NET::WMIcon | NET::WMIconName | NET::WMVisibleIconName) == 0)) + { + return; + } + + if (desktopPreview()) + { + KWin::WindowInfo* inf = m_windows[win]; + bool skipPager = inf->hasState(NET::SkipPager); + QMemArray<bool> old_shouldPaintWindow(m_desktops.size()); + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + int i = 0; + for ( it = m_desktops.begin(); it != itEnd; ++it) + { + old_shouldPaintWindow[i++] = (*it)->shouldPaintWindow(inf); + } + + m_windows.remove(win); + inf = info(win); + + if (inf->hasState(NET::SkipPager) || skipPager) + { + return; + } + + for ( i = 0, it = m_desktops.begin(); it != itEnd; ++it) + { + if ( old_shouldPaintWindow[i++] || (*it)->shouldPaintWindow(inf)) + { + (*it)->windowsChanged(); + } + } + } + else + { + m_windows.remove(win); + return; + } +} + +KWin::WindowInfo* KMiniPager::info( WId win ) +{ + if (!m_windows[win]) + { + KWin::WindowInfo* info = new KWin::WindowInfo( win, + NET::WMWindowType | NET::WMState | NET::XAWMState | NET::WMDesktop | NET::WMGeometry | NET::WMKDEFrameStrut, 0 ); + + m_windows.insert(win, info); + return info; + } + + return m_windows[win]; +} + +KTextShadowEngine* KMiniPager::shadowEngine() +{ + if (!m_shadowEngine) + m_shadowEngine = new KTextShadowEngine(); + + return m_shadowEngine; +} + +void KMiniPager::refresh() +{ + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for ( it = m_desktops.begin(); it != itEnd; ++it) + { + (*it)->update(); + } +} + +void KMiniPager::aboutToShowContextMenu() +{ + m_contextMenu->clear(); + + m_contextMenu->insertItem(SmallIcon("kpager"), i18n("&Launch Pager"), LaunchExtPager); + m_contextMenu->insertSeparator(); + + m_contextMenu->insertItem(i18n("&Rename Desktop \"%1\"") + .arg(kwin()->desktopName(m_rmbDesk)), RenameDesktop); + m_contextMenu->insertSeparator(); + + KPopupMenu* showMenu = new KPopupMenu(m_contextMenu); + showMenu->setCheckable(true); + showMenu->insertTitle(i18n("Pager Layout")); + + QPopupMenu* rowMenu = new QPopupMenu(showMenu); + rowMenu->setCheckable(true); + rowMenu->insertItem(i18n("&Automatic"), 0 + rowOffset); + rowMenu->insertItem(i18n("one row or column", "&1"), 1 + rowOffset); + rowMenu->insertItem(i18n("two rows or columns", "&2"), 2 + rowOffset); + rowMenu->insertItem( i18n("three rows or columns", "&3"), 3 + rowOffset); + connect(rowMenu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + showMenu->insertItem((orientation()==Horizontal) ? i18n("&Rows"): + i18n("&Columns"), + rowMenu); + + showMenu->insertItem(i18n("&Window Thumbnails"), WindowThumbnails); + showMenu->insertItem(i18n("&Window Icons"), WindowIcons); + + showMenu->insertTitle(i18n("Text Label")); + showMenu->insertItem(i18n("Desktop N&umber"), + PagerSettings::EnumLabelType::LabelNumber + labelOffset); + showMenu->insertItem(i18n("Desktop N&ame"), + PagerSettings::EnumLabelType::LabelName + labelOffset); + showMenu->insertItem(i18n("N&o Label"), + PagerSettings::EnumLabelType::LabelNone + labelOffset); + + showMenu->insertTitle(i18n("Background")); + showMenu->insertItem(i18n("&Elegant"), + PagerSettings::EnumBackgroundType::BgPlain + bgOffset); + showMenu->insertItem(i18n("&Transparent"), + PagerSettings::EnumBackgroundType::BgTransparent + bgOffset); + showMenu->insertItem(i18n("&Desktop Wallpaper"), + PagerSettings::EnumBackgroundType::BgLive + bgOffset); + connect(showMenu, SIGNAL(activated(int)), SLOT(contextMenuActivated(int))); + m_contextMenu->insertItem(i18n("&Pager Options"),showMenu); + + m_contextMenu->insertItem(SmallIcon("configure"), + i18n("&Configure Desktops..."), + ConfigureDesktops); + + rowMenu->setItemChecked(m_settings->numberOfRows() + rowOffset, true); + m_contextMenu->setItemChecked(m_settings->labelType() + labelOffset, showMenu); + m_contextMenu->setItemChecked(m_settings->backgroundType() + bgOffset, showMenu); + + m_contextMenu->setItemChecked(WindowThumbnails, m_settings->preview()); + m_contextMenu->setItemChecked(WindowIcons, m_settings->icons()); + m_contextMenu->setItemEnabled(WindowIcons, m_settings->preview()); + m_contextMenu->setItemEnabled(RenameDesktop, + m_settings->labelType() == + PagerSettings::EnumLabelType::LabelName); +} + +void KMiniPager::slotShowMenu(const QPoint& pos, int desktop) +{ + if (!m_contextMenu) + { + return; + } + + m_rmbDesk = desktop; + m_contextMenu->exec(pos); + m_rmbDesk = -1; +} + +void KMiniPager::contextMenuActivated(int result) +{ + if (result < 1) + { + return; + } + + switch (result) + { + case LaunchExtPager: + showPager(); + return; + + case ConfigureDesktops: + kapp->startServiceByDesktopName("desktop"); + return; + + case RenameDesktop: + m_desktops[(m_rmbDesk == -1) ? m_curDesk - 1 : m_rmbDesk - 1]->rename(); + return; + } + + if (result >= rowOffset) + { + m_settings->setNumberOfRows(result - rowOffset); + resizeEvent(0); + } + + switch (result) + { + case WindowThumbnails: + m_settings->setPreview(!m_settings->preview()); + TaskManager::the()->trackGeometry(); + break; + + case WindowIcons: + m_settings->setIcons(!m_settings->icons()); + break; + + case PagerSettings::EnumBackgroundType::BgPlain + bgOffset: + m_settings->setBackgroundType(PagerSettings::EnumBackgroundType::BgPlain); + break; + case PagerSettings::EnumBackgroundType::BgTransparent + bgOffset: + m_settings->setBackgroundType(PagerSettings::EnumBackgroundType::BgTransparent); + break; + case PagerSettings::EnumBackgroundType::BgLive + bgOffset: + { + m_settings->setBackgroundType(PagerSettings::EnumBackgroundType::BgLive); + QValueList<KMiniPagerButton*>::ConstIterator it; + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + for( it = m_desktops.begin(); it != itEnd; ++it ) + { + (*it)->backgroundChanged(); + } + break; + } + + case PagerSettings::EnumLabelType::LabelNone + labelOffset: + m_settings->setLabelType(PagerSettings::EnumLabelType::LabelNone); + break; + case PagerSettings::EnumLabelType::LabelNumber + labelOffset: + m_settings->setLabelType(PagerSettings::EnumLabelType::LabelNumber); + break; + case PagerSettings::EnumLabelType::LabelName + labelOffset: + m_settings->setLabelType(PagerSettings::EnumLabelType::LabelName); + break; + } + + m_settings->writeConfig(); + updateGeometry(); + refresh(); +} + +void KMiniPager::slotDesktopNamesChanged() +{ + QValueList<KMiniPagerButton*>::ConstIterator it = m_desktops.begin(); + QValueList<KMiniPagerButton*>::ConstIterator itEnd = m_desktops.end(); + + for (int i = 1; it != itEnd; ++it, ++i) + { + QString name = m_kwin->desktopName(i); + (*it)->setDesktopName(name); + (*it)->repaint(); + QToolTip::remove((*it)); + QToolTip::add((*it), name); + } + + updateLayout(); +} + +void KMiniPager::showPager() +{ + DCOPClient *dcop=kapp->dcopClient(); + + if (dcop->isApplicationRegistered("kpager")) + { + showKPager(true); + } + else + { + // Let's run kpager if it isn't running + connect( dcop, SIGNAL( applicationRegistered(const QCString &) ), this, SLOT(applicationRegistered(const QCString &)) ); + dcop->setNotifications(true); + QString strAppPath(locate("exe", "kpager")); + if (!strAppPath.isEmpty()) + { + KProcess process; + process << strAppPath; + process << "--hidden"; + process.start(KProcess::DontCare); + } + } +} + +void KMiniPager::showKPager(bool toggleShow) +{ + QPoint pt; + switch ( position() ) + { + case pTop: + pt = mapToGlobal( QPoint(x(), y() + height()) ); + break; + case pLeft: + pt = mapToGlobal( QPoint(x() + width(), y()) ); + break; + case pRight: + case pBottom: + default: + pt=mapToGlobal( QPoint(x(), y()) ); + } + + DCOPClient *dcop=kapp->dcopClient(); + + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << pt.x() << pt.y() ; + if (toggleShow) + { + dcop->send("kpager", "KPagerIface", "toggleShow(int,int)", data); + } + else + { + dcop->send("kpager", "KPagerIface", "showAt(int,int)", data); + } +} + +void KMiniPager::applicationRegistered( const QCString & appName ) +{ + if (appName == "kpager") + { + disconnect( kapp->dcopClient(), SIGNAL( applicationRegistered(const QCString &) ), + this, SLOT(applicationRegistered(const QCString &)) ); + showKPager(false); + } +} + diff --git a/kicker/applets/minipager/pagerapplet.h b/kicker/applets/minipager/pagerapplet.h new file mode 100644 index 000000000..f47b0411d --- /dev/null +++ b/kicker/applets/minipager/pagerapplet.h @@ -0,0 +1,138 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __MINIPAGER_H +#define __MINIPAGER_H + +#include <qvaluelist.h> +#include <qintdict.h> + +#include <kpanelapplet.h> +#include <kwin.h> + +#include "pagerbutton.h" +#include "pagersettings.h" + +class QButtonGroup; +class QGridLayout; +class QTimer; + +class KProcess; +class KWinModule; +class KTextShadowEngine; +class KSelectionOwner; + +class PagerSettings; + +class KMiniPager : public KPanelApplet +{ + Q_OBJECT + +public: + KMiniPager(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + + virtual ~KMiniPager(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + + KWin::WindowInfo* info( WId win ); + KWinModule* kwin() { return m_kwin; } + KTextShadowEngine* shadowEngine(); + + void setActive( WId active ) { m_activeWindow = active; } + WId activeWindow() { return m_activeWindow; } + + enum ConfigOptions { LaunchExtPager = 96, WindowThumbnails, + WindowIcons, ConfigureDesktops, RenameDesktop }; + int labelType() const { return m_settings->labelType(); } + + int bgType() const { return m_settings->backgroundType(); } + + bool desktopPreview() const { return m_settings->preview(); } + bool windowIcons() const { return m_settings->icons(); } + + Orientation orientation() const { return KPanelApplet::orientation(); } + Direction popupDirection() { return KPanelApplet::popupDirection(); } + + void emitRequestFocus() { emit requestFocus(); } + + QPoint clickPos; + +public slots: + void slotSetDesktop(int desktop); + void slotSetDesktopViewport(int desktop, const QPoint& viewport); + void slotSetDesktopCount(int count); + void slotButtonSelected(int desk ); + void slotActiveWindowChanged( WId win ); + void slotWindowAdded( WId ); + void slotWindowRemoved( WId ); + void slotWindowChanged( WId, unsigned int ); + void slotShowMenu( const QPoint&, int ); + void slotDesktopNamesChanged(); + void slotBackgroundChanged( int ); + + void refresh(); + +protected: + void drawButtons(); + void startDrag( const QPoint &point ); + + void updateDesktopLayout(int,int,int); + void resizeEvent(QResizeEvent*); + void wheelEvent( QWheelEvent* e ); + void showKPager(bool toggleShow); + +protected slots: + void showPager(); + void applicationRegistered(const QCString &appName); + void aboutToShowContextMenu(); + void contextMenuActivated(int); + +private: + QValueList<KMiniPagerButton*> m_desktops; + int m_curDesk; + int m_rmbDesk; + + QIntDict<KWin::WindowInfo> m_windows; + WId m_activeWindow; + + QButtonGroup *m_group; + + QGridLayout *m_layout; + bool m_useViewports; + int desktopLayoutOrientation; + int desktopLayoutX; + int desktopLayoutY; + KSelectionOwner* m_desktopLayoutOwner; + + KWinModule *m_kwin; + KTextShadowEngine* m_shadowEngine; + + QPopupMenu *m_contextMenu; + PagerSettings *m_settings; +}; + +#endif + diff --git a/kicker/applets/minipager/pagerbutton.cpp b/kicker/applets/minipager/pagerbutton.cpp new file mode 100644 index 000000000..b4e268b8e --- /dev/null +++ b/kicker/applets/minipager/pagerbutton.cpp @@ -0,0 +1,824 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> + +#include <qcursor.h> +#include <qdrawutil.h> +#include <qlineedit.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qstylesheet.h> + +#include <netwm.h> +#include <dcopclient.h> + +#include <kwinmodule.h> +#include <ksharedpixmap.h> +#include <kpixmapio.h> +#include <kpixmapeffect.h> +#include <kstringhandler.h> +#include <kiconloader.h> + +#include "global.h" +#include "kickertip.h" +#include "kickerSettings.h" +#include "kshadowengine.h" +#include "paneldrag.h" + +#include "pagerapplet.h" +#include "pagerbutton.h" +#include "pagerbutton.moc" +#include "pagersettings.h" + +#ifdef FocusOut +#undef FocusOut +#endif + +KSharedPixmap* KMiniPagerButton::s_commonSharedPixmap; +KPixmap* KMiniPagerButton::s_commonBgPixmap; + +KMiniPagerButton::KMiniPagerButton(int desk, bool useViewPorts, const QPoint& viewport, + KMiniPager *parent, const char *name) + : QButton(parent, name), + m_pager(parent), + m_desktop(desk), + m_useViewports(useViewPorts), + m_viewport(viewport), + m_lineEdit(0), + m_sharedPixmap(0), + m_bgPixmap(0), + m_isCommon(false), + m_currentWindow(0), + m_inside(false) +{ + setToggleButton(true); + setAcceptDrops(true); + setWFlags(WNoAutoErase); + + setBackgroundOrigin(AncestorOrigin); + installEventFilter(KickerTip::the()); + + m_desktopName = m_pager->kwin()->desktopName(m_desktop); + + connect(this, SIGNAL(clicked()), SLOT(slotClicked())); + connect(this, SIGNAL(toggled(bool)), SLOT(slotToggled(bool))); + connect(&m_dragSwitchTimer, SIGNAL(timeout()), this, SLOT(slotDragSwitch())); + connect(&m_updateCompressor, SIGNAL(timeout()), this, SLOT(update())); + + if (m_pager->desktopPreview()) + { + setMouseTracking(true); + } + loadBgPixmap(); +} + +KMiniPagerButton::~KMiniPagerButton() +{ + delete m_sharedPixmap; + delete m_bgPixmap; +} + +QRect KMiniPagerButton::mapGeometryToViewport(const KWin::WindowInfo& info) const +{ + if (!m_useViewports) + return info.frameGeometry(); + + // ### fix vertically layouted viewports + QRect _r(info.frameGeometry()); + QPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop())); + + _r.moveBy( - (m_desktop - vx.x()) * QApplication::desktop()->width(), + 0); + + if ((info.state() & NET::Sticky)) + { + _r.moveTopLeft(QPoint(_r.x() % QApplication::desktop()->width(), + _r.y() % QApplication::desktop()->height())); + + } + + return _r; +} + +QPoint KMiniPagerButton::mapPointToViewport(const QPoint& _p) const +{ + if (!m_useViewports) return _p; + + QPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop())); + + // ### fix vertically layouted viewports + QPoint p(_p); + p.setX(p.x() + (m_desktop - vx.x()) * QApplication::desktop()->width()); + return p; +} + +bool KMiniPagerButton::shouldPaintWindow( KWin::WindowInfo *info ) const +{ + if (!info) + return false; + +// if (info->mappingState != NET::Visible) +// return false; + + NET::WindowType type = info->windowType( NET::NormalMask | NET::DesktopMask + | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask + | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask ); + + if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu) + return false; + + if (!m_useViewports && !info->isOnDesktop(m_desktop)) + return false; + + if (m_useViewports) { + QRect r = mapGeometryToViewport(*info); + + if (!info->hasState(NET::Sticky) && + !QApplication::desktop()->geometry().contains(r.topLeft()) && + !QApplication::desktop()->geometry().contains(r.topRight())) + return false; + } + + if (info->state() & NET::SkipPager || info->state() & NET::Shaded ) + return false; + + if (info->win() == m_pager->winId()) + return false; + + if ( info->isMinimized() ) + return false; + + return true; +} + +void KMiniPagerButton::resizeEvent(QResizeEvent *ev) +{ + if (m_lineEdit) + { + m_lineEdit->setGeometry(rect()); + } + + delete m_bgPixmap; + m_bgPixmap = 0; + + QButton::resizeEvent(ev); +} + +void KMiniPagerButton::windowsChanged() +{ + m_currentWindow = 0; + + if (!m_updateCompressor.isActive()) + { + m_updateCompressor.start(50, true); + } +} + +void KMiniPagerButton::backgroundChanged() +{ + delete s_commonSharedPixmap; + s_commonSharedPixmap = 0; + delete s_commonBgPixmap; + s_commonBgPixmap = 0; + loadBgPixmap(); +} + +void KMiniPagerButton::loadBgPixmap() +{ + if (m_pager->bgType() != PagerSettings::EnumBackgroundType::BgLive) + return; // not needed + + DCOPClient *client = kapp->dcopClient(); + if (!client->isAttached()) + { + client->attach(); + } + + QCString kdesktop_name; + int screen_number = DefaultScreen(qt_xdisplay()); + if (screen_number == 0) + kdesktop_name = "kdesktop"; + else + kdesktop_name.sprintf("kdesktop-screen-%d", screen_number); + + QByteArray data, replyData; + QCString replyType; + if (client->call(kdesktop_name, "KBackgroundIface", "isCommon()", + data, replyType, replyData)) + { + if (replyType == "bool") + { + QDataStream reply(replyData, IO_ReadOnly); + reply >> m_isCommon; + } + } + + if (m_isCommon) + { + if (s_commonBgPixmap) + { // pixmap is already ready, just use it + backgroundLoaded( true ); + return; + } + else if (s_commonSharedPixmap) + { // other button is already fetching the pixmap + connect(s_commonSharedPixmap, SIGNAL(done(bool)), + SLOT(backgroundLoaded(bool))); + return; + } + } + + QDataStream args( data, IO_WriteOnly ); + args << 1; + client->send(kdesktop_name, "KBackgroundIface", "setExport(int)", data); + + if (m_isCommon) + { + if (!s_commonSharedPixmap) + { + s_commonSharedPixmap = new KSharedPixmap; + connect(s_commonSharedPixmap, SIGNAL(done(bool)), + SLOT(backgroundLoaded(bool))); + } + s_commonSharedPixmap->loadFromShared(QString("DESKTOP1")); + } + else + { + if (!m_sharedPixmap) + { + m_sharedPixmap = new KSharedPixmap; + connect(m_sharedPixmap, SIGNAL(done(bool)), + SLOT(backgroundLoaded(bool))); + } + m_sharedPixmap->loadFromShared(QString("DESKTOP%1").arg(m_desktop)); + } +} + +static QPixmap scalePixmap(const QPixmap &pixmap, int width, int height) +{ + if (pixmap.width()>100) + { + KPixmapIO io; + QImage img( io.convertToImage( pixmap ) ); + return io.convertToPixmap( img.smoothScale( width, height ) ); + } + + QImage img( pixmap.convertToImage().smoothScale( width, height ) ); + QPixmap pix; + pix.convertFromImage( img ); + + return pix; +} + +void KMiniPagerButton::backgroundLoaded( bool loaded ) +{ + if (loaded) + { + if (!m_bgPixmap) + { + m_bgPixmap = new KPixmap; + } + if (m_isCommon) + { + if (!s_commonBgPixmap) + { + s_commonBgPixmap = new KPixmap; + *s_commonBgPixmap = scalePixmap(*s_commonSharedPixmap, width(), height()); + s_commonSharedPixmap->deleteLater(); // let others get the signal too + s_commonSharedPixmap = 0; + } + *m_bgPixmap = *s_commonBgPixmap; + } + else + { + *m_bgPixmap = scalePixmap(*m_sharedPixmap, width(), height()); + delete m_sharedPixmap; + m_sharedPixmap = 0L; + } + + update(); + } + else + { + kdWarning() << "Error getting the background\n"; + } +} + +void KMiniPagerButton::enterEvent(QEvent *) +{ + m_inside = true; + update(); +} + +void KMiniPagerButton::leaveEvent(QEvent *) +{ + m_inside = false; + update(); +} + +void KMiniPagerButton::drawButton(QPainter *bp) +{ + int w = width(); + int h = height(); + bool on = isOn(); + bool down = isDown(); + + QBrush background; + + bool liveBkgnd = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive; + bool transparent = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgTransparent; + + // background + + if (backgroundPixmap()) + { + QPoint pt = backgroundOffset(); + bp->drawTiledPixmap(0, 0, width(), height(), *backgroundPixmap(), pt.x(), pt.y()); + } + else + { + bp->fillRect(0, 0, width(), height(), paletteBackgroundColor()); + } + + + // desktop background + + if (liveBkgnd) + { + if (m_bgPixmap && !m_bgPixmap->isNull()) + { + if (on) + { + KPixmap tmp = *m_bgPixmap; + KPixmapEffect::intensity(tmp, 0.33); + bp->drawPixmap(0, 0, tmp); + } + else + { + bp->drawPixmap(0, 0, *m_bgPixmap); + } + } + else + { + liveBkgnd = false; + } + } + + if (!liveBkgnd) + { + if (transparent) + { + // transparent windows get an 1 pixel frame... + if (on) + { + bp->setPen(colorGroup().midlight()); + } + else if (down) + { + bp->setPen(KickerLib::blendColors(colorGroup().mid(), + colorGroup().midlight())); + } + else + { + bp->setPen(colorGroup().dark()); + } + + bp->drawRect(0, 0, w, h); + } + else + { + QBrush background; + + if (on) + { + background = colorGroup().brush(QColorGroup::Midlight); + } + else if (down) + { + background = KickerLib::blendColors(colorGroup().mid(), + colorGroup().midlight()); + } + else + { + background = colorGroup().brush(QColorGroup::Mid); + } + + bp->fillRect(0, 0, w, h, background); + } + } + + // window preview... + if (m_pager->desktopPreview()) + { + KWinModule* kwin = m_pager->kwin(); + KWin::WindowInfo *info = 0; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + + QValueList<WId> windows = kwin->stackingOrder(); + QValueList<WId>::const_iterator itEnd = windows.constEnd(); + for (QValueList<WId>::ConstIterator it = windows.constBegin(); it != itEnd; ++it) + { + info = m_pager->info(*it); + + if (shouldPaintWindow(info)) + { + QRect r = mapGeometryToViewport(*info); + r = QRect(r.x() * width() / dw, 2 + r.y() * height() / dh, + r.width() * width() / dw, r.height() * height() / dh); + + if (kwin->activeWindow() == info->win()) + { + QBrush brush = colorGroup().brush(QColorGroup::Highlight); + qDrawShadeRect(bp, r, colorGroup(), false, 1, 0, &brush); + } + else + { + QBrush brush = colorGroup().brush(QColorGroup::Button); + + if (on) + { + brush.setColor(brush.color().light(120)); + } + + bp->fillRect(r, brush); + qDrawShadeRect(bp, r, colorGroup(), true, 1, 0); + } + + if (m_pager->windowIcons() && r.width() > 15 && r.height() > 15) + { + QPixmap icon = KWin::icon(*it, 16, 16, true); + if (!icon.isNull()) + { + bp->drawPixmap(r.left() + ((r.width() - 16) / 2), + r.top() + ((r.height() - 16) / 2), + icon); + } + } + } + } + } + + if (liveBkgnd) + { + // draw a little border around the individual buttons + // makes it look a bit more finished. + if (on) + { + bp->setPen(colorGroup().midlight()); + } + else + { + bp->setPen(colorGroup().mid()); + } + + bp->drawRect(0, 0, w, h); + } + + if (m_pager->labelType() != PagerSettings::EnumLabelType::LabelNone) + { + QString label = (m_pager->labelType() == PagerSettings::EnumLabelType::LabelNumber) ? + QString::number(m_desktop) : m_desktopName; + + if (transparent || liveBkgnd) + { + bp->setPen(on ? colorGroup().midlight() : colorGroup().buttonText()); + m_pager->shadowEngine()->drawText(*bp, QRect(0, 0, w, h), AlignCenter, label, size()); + } + else + bp->drawText(0, 0, w, h, AlignCenter, label); + } + + if (m_inside) + KickerLib::drawBlendedRect(bp, QRect(1, 1, width() - 2, height() - 2), colorGroup().foreground()); +} + +void KMiniPagerButton::mousePressEvent(QMouseEvent * e) +{ + if (e->button() == RightButton) + { + // prevent LMB down -> RMB down -> LMB up sequence + if ((e->state() & MouseButtonMask ) == NoButton) + { + emit showMenu(e->globalPos(), m_desktop); + return; + } + } + + if (m_pager->desktopPreview()) + { + m_pager->clickPos = e->pos(); + } + + QButton::mousePressEvent(e); +} + +void KMiniPagerButton::mouseReleaseEvent(QMouseEvent* e) +{ + m_pager->clickPos = QPoint(); + QButton::mouseReleaseEvent(e); +} + +void KMiniPagerButton::mouseMoveEvent(QMouseEvent* e) +{ + if (!m_pager->desktopPreview()) + { + return; + } + + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + int w = width(); + int h = height(); + + QPoint pos(m_pager->clickPos.isNull() ? mapFromGlobal(QCursor::pos()) : m_pager->clickPos); + QPoint p = mapPointToViewport(QPoint(pos.x() * dw / w, pos.y() * dh / h)); + + Task::Ptr wasWindow = m_currentWindow; + m_currentWindow = TaskManager::the()->findTask(m_useViewports ? 1 : m_desktop, p); + + if (wasWindow != m_currentWindow) + { + KickerTip::Client::updateKickerTip(); + } + + if (m_currentWindow && !m_pager->clickPos.isNull() && + (m_pager->clickPos - e->pos()).manhattanLength() > KGlobalSettings::dndEventDelay()) + { + QRect r = m_currentWindow->geometry(); + + // preview window height, window width + int ww = r.width() * w / dw; + int wh = r.height() * h / dh; + QPixmap windowImage(ww, wh); + QPainter bp(&windowImage, this); + + bp.setPen(colorGroup().foreground()); + bp.drawRect(0, 0, ww, wh); + bp.fillRect(1, 1, ww - 2, wh - 2, colorGroup().background()); + + Task::List tasklist; + tasklist.append(m_currentWindow); + TaskDrag* drag = new TaskDrag(tasklist, this); + QPoint offset(m_pager->clickPos.x() - (r.x() * w / dw), + m_pager->clickPos.y() - (r.y() * h / dh)); + drag->setPixmap(windowImage, offset); + drag->dragMove(); + + if (isDown()) + { + setDown(false); + } + + m_pager->clickPos = QPoint(); + } +} + +void KMiniPagerButton::dragEnterEvent(QDragEnterEvent* e) +{ + if (PanelDrag::canDecode(e)) + { + // ignore container drags + return; + } + else if (TaskDrag::canDecode(e)) + { + // if it's a task drag don't switch the desktop, just accept it + e->accept(); + setDown(true); + } + else + { + // if a dragitem is held for over a pager button for two seconds, + // activate corresponding desktop + m_dragSwitchTimer.start(1000, true); + QButton::dragEnterEvent(e); + } +} + +void KMiniPagerButton::dropEvent(QDropEvent* e) +{ + if (TaskDrag::canDecode(e)) + { + e->accept(); + Task::List tasks(TaskDrag::decode(e)); + + if ((m_useViewports || e->source() == this) && tasks.count() == 1) + { + Task::Ptr task = tasks[0]; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + int w = width(); + int h = height(); + QRect location = mapGeometryToViewport(task->info()); + QPoint pos = mapPointToViewport(e->pos()); + int deltaX = pos.x() - m_pager->clickPos.x(); + int deltaY = pos.y() - m_pager->clickPos.y(); + + if (abs(deltaX) < 3) + { + deltaX = 0; + } + else + { + deltaX = deltaX * dw / w; + } + + if (abs(deltaY) < 3) + { + deltaY = 0; + } + else + { + deltaY = deltaY * dh / h; + } + + location.moveBy(deltaX, deltaY); + + XMoveWindow(x11Display(), task->window(), location.x(), location.y()); + if ((e->source() != this || !task->isOnAllDesktops()) && + task->desktop() != m_desktop) + { + task->toDesktop(m_desktop); + } + } + else + { + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->toDesktop(m_desktop); + } + } + + setDown(false); + } + + QButton::dropEvent( e ); +} + +void KMiniPagerButton::enabledChange( bool oldEnabled ) +{ + if (m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive) + { + m_pager->refresh(); + } + + QButton::enabledChange(oldEnabled); +} + +void KMiniPagerButton::dragLeaveEvent( QDragLeaveEvent* e ) +{ + m_dragSwitchTimer.stop(); + + if (m_pager->kwin()->currentDesktop() != m_desktop) + { + setDown(false); + } + + QButton::dragLeaveEvent( e ); +} + +void KMiniPagerButton::slotDragSwitch() +{ + emit buttonSelected(m_desktop); +} + +void KMiniPagerButton::slotClicked() +{ + emit buttonSelected(m_desktop); +} + +void KMiniPagerButton::rename() +{ + if ( !m_lineEdit ) { + m_lineEdit = new QLineEdit( this ); + connect( m_lineEdit, SIGNAL( returnPressed() ), m_lineEdit, SLOT( hide() ) ); + m_lineEdit->installEventFilter( this ); + } + m_lineEdit->setGeometry( rect() ); + m_lineEdit->setText(m_desktopName); + m_lineEdit->show(); + m_lineEdit->setFocus(); + m_lineEdit->selectAll(); + m_pager->emitRequestFocus(); +} + +void KMiniPagerButton::slotToggled( bool b ) +{ + if ( !b && m_lineEdit ) + { + m_lineEdit->hide(); + } +} + +bool KMiniPagerButton::eventFilter( QObject *o, QEvent * e) +{ + if (o && o == m_lineEdit && + (e->type() == QEvent::FocusOut || e->type() == QEvent::Hide)) + { + m_pager->kwin()->setDesktopName( m_desktop, m_lineEdit->text() ); + m_desktopName = m_lineEdit->text(); + QTimer::singleShot( 0, m_lineEdit, SLOT( deleteLater() ) ); + m_lineEdit = 0; + return true; + } + + return QButton::eventFilter(o, e); +} + +void KMiniPagerButton::updateKickerTip(KickerTip::Data &data) +{ + Task::Dict tasks = TaskManager::the()->tasks(); + Task::Dict::iterator taskEnd = tasks.end(); + uint taskCounter = 0; + uint taskLimiter = 4; + QString lastWindow; + + for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it) + { + if (it.data()->desktop() == m_desktop || it.data()->isOnAllDesktops()) + { + taskCounter++; + if (taskCounter > taskLimiter) + { + lastWindow = it.data()->visibleName(); + continue; + } + + QPixmap winIcon = it.data()->pixmap(); + QString bullet; + + if (winIcon.isNull()) + { + bullet = "•"; + } + else + { + data.mimeFactory->setPixmap(QString::number(taskCounter), winIcon); + bullet = QString("<img src=\"%1\" width=\"%2\" height=\"%3\">").arg(taskCounter).arg(16).arg(16); + } + + QString name = KStringHandler::cPixelSqueeze(it.data()->visibleName(), fontMetrics(), 400); + name = QStyleSheet::escape(name); + if (it.data() == m_currentWindow) + { + data.subtext.append(QString("<br>%1 <u>").arg(bullet)); + data.subtext.append(name).append("</u>"); + } + else + { + data.subtext.append(QString("<br>%1 ").arg(bullet)); + data.subtext.append(name); + } + } + } + + if (taskCounter > taskLimiter) + { + if (taskCounter - taskLimiter == 1) + { + data.subtext.append("<br>• ").append(lastWindow); + } + else + { + data.subtext.append("<br>• <i>") + .append(i18n("and 1 other", "and %n others", taskCounter - taskLimiter)) + .append("</i>"); + } + } + + if (taskCounter > 0) + { + data.subtext.prepend(i18n("One window:", + "%n windows:", + taskCounter)); + } + + data.duration = 4000; + data.icon = DesktopIcon("window_list", KIcon::SizeMedium); + data.message = QStyleSheet::escape(m_desktopName); + data.direction = m_pager->popupDirection(); +} + diff --git a/kicker/applets/minipager/pagerbutton.h b/kicker/applets/minipager/pagerbutton.h new file mode 100644 index 000000000..1547201e0 --- /dev/null +++ b/kicker/applets/minipager/pagerbutton.h @@ -0,0 +1,111 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __MINIPAGERBUTTON_H +#define __MINIPAGERBUTTON_H + +#include <qbutton.h> + +#include "taskmanager.h" +#include "kickertip.h" + +class KPixmap; +class KWinModule; +class KMiniPager; +class KSharedPixmap; +class QLineEdit; + +class KMiniPagerButton : public QButton, public KickerTip::Client +{ + Q_OBJECT +public: + KMiniPagerButton(int desk, bool useViewports, const QPoint& viewport, + KMiniPager *parent=0, const char *name=0); + ~KMiniPagerButton(); + + int desktop() { return m_desktop; } + + QString desktopName() { return m_desktopName; } + void setDesktopName( QString name ) { m_desktopName = name; } + + void rename(); + void backgroundChanged(); + void windowsChanged(); + + bool shouldPaintWindow( KWin::WindowInfo *info ) const; + +signals: + void buttonSelected( int desk ); + void showMenu( const QPoint&, int ); + +protected: + void drawButton(QPainter *); + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + void resizeEvent(QResizeEvent *ev); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + void dragEnterEvent(QDragEnterEvent* e); + void dragLeaveEvent(QDragLeaveEvent* e); + void enabledChange( bool oldEnabled ); + void dropEvent(QDropEvent* e); + + bool eventFilter(QObject*, QEvent*); + void updateKickerTip(KickerTip::Data &data); + +private slots: + void slotToggled(bool); + void slotClicked(); + void slotDragSwitch(); + + void backgroundLoaded( bool loaded ); + +private: + void loadBgPixmap(); + QRect mapGeometryToViewport(const KWin::WindowInfo&) const; + QPoint mapPointToViewport(const QPoint&) const; + + KMiniPager* m_pager; + int m_desktop; + bool m_useViewports; + QString m_desktopName; + QPoint m_viewport; + + QTimer m_updateCompressor; + QTimer m_dragSwitchTimer; + Task::Ptr m_dragging; + + QLineEdit* m_lineEdit; + + KSharedPixmap *m_sharedPixmap; + KPixmap *m_bgPixmap; + static KSharedPixmap *s_commonSharedPixmap; + static KPixmap *s_commonBgPixmap; + bool m_isCommon; + + Task::Ptr m_currentWindow; + bool m_inside; +}; + +#endif diff --git a/kicker/applets/minipager/pagersettings.kcfg b/kicker/applets/minipager/pagersettings.kcfg new file mode 100644 index 000000000..8a26bdc86 --- /dev/null +++ b/kicker/applets/minipager/pagersettings.kcfg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + + <kcfgfile arg="true"/> + <group name="General"> + <entry key="LabelType" type="Enum"> + <choices> + <choice name="LabelNone"> + <label>None</label> + </choice> + <choice name="LabelName"> + <label>Name</label> + </choice> + <choice name="LabelNumber"> + <label>Number</label> + </choice> + </choices> + <default>LabelNumber</default> + <label>Virtual desktop label type</label> + </entry> + + <entry key="BackgroundType" type="Enum"> + <choices> + <choice name="BgPlain"> + <label>Plain</label> + </choice> + <choice name="BgTransparent"> + <label>Transparent</label> + </choice> + <choice name="BgLive"> + <label>Live</label> + </choice> + </choices> + <default>BgPlain</default> + <label>Virtual desktop background type</label> + </entry> + + <entry name="NumberOfRows" type="Int"> + <label>Number of rows to arrange the desktop previews into</label> + <default>0</default> + <min>0</min> + <max>4</max> + </entry> + + <entry name="Preview" type="Bool"> + <label>Show desktop preview?</label> + <default>true</default> + </entry> + + <entry name="Icons" type="Bool"> + <label>Show window icons in previews?</label> + <default>true</default> + </entry> + </group> +</kcfg> diff --git a/kicker/applets/minipager/pagersettings.kcfgc b/kicker/applets/minipager/pagersettings.kcfgc new file mode 100644 index 000000000..47a1915f4 --- /dev/null +++ b/kicker/applets/minipager/pagersettings.kcfgc @@ -0,0 +1,4 @@ +File=pagersettings.kcfg +Singleton=false +ClassName=PagerSettings +Mutators=true diff --git a/kicker/applets/naughty/Makefile.am b/kicker/applets/naughty/Makefile.am new file mode 100644 index 000000000..533df19c3 --- /dev/null +++ b/kicker/applets/naughty/Makefile.am @@ -0,0 +1,30 @@ +pic_DATA = naughty-happy.png naughty-sad.png +picdir = $(kde_datadir)/naughtyapplet/pics + +INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = naughty_panelapplet.la + +naughty_panelapplet_la_SOURCES = \ + NaughtyProcessMonitor.cpp \ + NaughtyConfigDialog.cpp \ + NaughtyApplet.cpp + +METASOURCES = AUTO + +noinst_HEADERS = \ + NaughtyProcessMonitor.h \ + NaughtyConfigDialog.h \ + NaughtyApplet.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = naughtyapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +naughty_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +naughty_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KDEUI) $(LIB_KVM) + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/naughtyapplet.pot + diff --git a/kicker/applets/naughty/NaughtyApplet.cpp b/kicker/applets/naughty/NaughtyApplet.cpp new file mode 100644 index 000000000..c256aa36f --- /dev/null +++ b/kicker/applets/naughty/NaughtyApplet.cpp @@ -0,0 +1,223 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "NaughtyApplet.h" +#include "NaughtyProcessMonitor.h" +#include "NaughtyConfigDialog.h" + +#include <qmessagebox.h> +#include <qtoolbutton.h> +#include <qlayout.h> + +#include <kiconloader.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kaboutapplication.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> +#include <qpushbutton.h> + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget * parent, const QString & configFile) + { + KGlobal::locale()->insertCatalogue("naughtyapplet"); + + return new NaughtyApplet + ( + configFile, + KPanelApplet::Normal, + KPanelApplet::About | KPanelApplet::Preferences, + parent, + "naughtyapplet" + ); + } +} + +NaughtyApplet::NaughtyApplet +( + const QString & configFile, + Type t, + int actions, + QWidget * parent, + const char * name +) + : KPanelApplet(configFile, t, actions, parent, name) +{ + KGlobal::iconLoader()->addAppDir("naughtyapplet"); + setBackgroundOrigin( AncestorOrigin ); + + button_ = new SimpleButton(this); + button_->setFixedSize(20, 20); + + QVBoxLayout * layout = new QVBoxLayout(this); + layout->addWidget(button_); + + monitor_ = new NaughtyProcessMonitor(2, 20, this); + + connect + ( + button_, SIGNAL(clicked()), + this, SLOT(slotPreferences()) + ); + + connect + ( + monitor_, SIGNAL(runawayProcess(ulong, const QString &)), + this, SLOT(slotWarn(ulong, const QString &)) + ); + + connect + ( + monitor_, SIGNAL(load(uint)), + this, SLOT(slotLoad(uint)) + ); + + loadSettings(); + + monitor_->start(); +} + +NaughtyApplet::~NaughtyApplet() +{ + KGlobal::locale()->removeCatalogue("naughtyapplet"); +} + + void +NaughtyApplet::slotWarn(ulong pid, const QString & name) +{ + if (ignoreList_.contains(name)) + return; + + QString s = i18n("A program called '%1' is slowing down the others " + "on your machine. It may have a bug that is causing " + "this, or it may just be busy.\n" + "Would you like to try to stop the program?"); + + int retval = KMessageBox::warningYesNo(this, s.arg(name), QString::null, i18n("Stop"), i18n("Keep Running")); + + if (KMessageBox::Yes == retval) + monitor_->kill(pid); + else + { + s = i18n("In future, should busy programs called '%1' be ignored?"); + + retval = KMessageBox::questionYesNo(this, s.arg(name), QString::null, i18n("Ignore"), i18n("Do Not Ignore")); + + if (KMessageBox::Yes == retval) + { + ignoreList_.append(name); + config()->writeEntry("IgnoreList", ignoreList_); + config()->sync(); + } + } +} + + int +NaughtyApplet::widthForHeight(int) const +{ + return 20; +} + + int +NaughtyApplet::heightForWidth(int) const +{ + return 20; +} + + void +NaughtyApplet::slotLoad(uint l) +{ + if (l > monitor_->triggerLevel()) + button_->setPixmap(BarIcon("naughty-sad")); + else + button_->setPixmap(BarIcon("naughty-happy")); +} + + void +NaughtyApplet::about() +{ + KAboutData about + ( + "naughtyapplet", + I18N_NOOP("Naughty applet"), + "1.0", + I18N_NOOP("Runaway process catcher"), + KAboutData::License_GPL_V2, + "(C) 2000 Rik Hemsley (rikkus) <rik@kde.org>" + ); + + KAboutApplication a(&about, this); + a.exec(); +} + + void +NaughtyApplet::slotPreferences() +{ + preferences(); +} + + void +NaughtyApplet::preferences() +{ + NaughtyConfigDialog d + ( + ignoreList_, + monitor_->interval(), + monitor_->triggerLevel(), + this + ); + + QDialog::DialogCode retval = QDialog::DialogCode(d.exec()); + + if (QDialog::Accepted == retval) + { + ignoreList_ = d.ignoreList(); + monitor_->setInterval(d.updateInterval()); + monitor_->setTriggerLevel(d.threshold()); + saveSettings(); + } +} + + void +NaughtyApplet::loadSettings() +{ + ignoreList_ = config()->readListEntry("IgnoreList"); + monitor_->setInterval(config()->readUnsignedNumEntry("UpdateInterval", 2)); + monitor_->setTriggerLevel(config()->readUnsignedNumEntry("Threshold", 20)); + + // Add 'X' as a default. + if (ignoreList_.isEmpty() && !config()->hasKey("IgnoreList")) + ignoreList_.append("X"); +} + + void +NaughtyApplet::saveSettings() +{ + config()->writeEntry("IgnoreList", ignoreList_); + config()->writeEntry("UpdateInterval", monitor_->interval()); + config()->writeEntry("Threshold", monitor_->triggerLevel()); + config()->sync(); +} + +#include "NaughtyApplet.moc" + diff --git a/kicker/applets/naughty/NaughtyApplet.h b/kicker/applets/naughty/NaughtyApplet.h new file mode 100644 index 000000000..00df51ec4 --- /dev/null +++ b/kicker/applets/naughty/NaughtyApplet.h @@ -0,0 +1,76 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef NAUGHTY_H +#define NAUGHTY_H + +#include <kpanelapplet.h> +#include <qstringlist.h> + +#include "simplebutton.h" + +class NaughtyProcessMonitor; +class QPushButton; + +class NaughtyApplet : public KPanelApplet +{ + Q_OBJECT + + public: + + NaughtyApplet + ( + const QString & configFile, + Type t = Normal, + int actions = 0, + QWidget * parent = 0, + const char * name = 0 + ); + + ~NaughtyApplet(); + + virtual int widthForHeight(int h) const; + virtual int heightForWidth(int w) const; + + signals: + + void layoutChanged(); + + protected slots: + + void slotWarn(ulong pid, const QString & name); + void slotLoad(uint); + void slotPreferences(); + + protected: + + virtual void about(); + virtual void preferences(); + virtual void loadSettings(); + virtual void saveSettings(); + + private: + + NaughtyProcessMonitor * monitor_; + SimpleButton * button_; + QStringList ignoreList_; +}; + +#endif diff --git a/kicker/applets/naughty/NaughtyConfigDialog.cpp b/kicker/applets/naughty/NaughtyConfigDialog.cpp new file mode 100644 index 000000000..e03a955cc --- /dev/null +++ b/kicker/applets/naughty/NaughtyConfigDialog.cpp @@ -0,0 +1,98 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <keditlistbox.h> +#include <knuminput.h> +#include <klocale.h> +#include <qvbox.h> + +#include "NaughtyConfigDialog.h" +#include "NaughtyConfigDialog.moc" + +NaughtyConfigDialog::NaughtyConfigDialog +( + const QStringList & items, + uint updateInterval, + uint threshold, + QWidget * parent, + const char * name +) + : + KDialogBase + ( + parent, + name, + true, + i18n("Configuration"), + KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok, + true + ) +{ + QVBox * v = new QVBox(this); + setMainWidget(v); + + kini_updateInterval_ = new KIntNumInput(updateInterval, v); + kini_threshold_ = new KIntNumInput(kini_updateInterval_, threshold, v); + + kini_updateInterval_ ->setLabel(i18n("&Update interval:")); + kini_threshold_ ->setLabel(i18n("CPU &load threshold:")); + + kini_updateInterval_ ->setRange(1, 20); + kini_threshold_ ->setRange(10, 1000); + + listBox_ = new KEditListBox + (i18n("&Programs to Ignore"), + v, + "naughty config dialog ignore listbox", + false, + KEditListBox::Add | KEditListBox::Remove + ); + + listBox_->insertStringList(items); +} + +NaughtyConfigDialog::~NaughtyConfigDialog() +{ +} + + uint +NaughtyConfigDialog::updateInterval() const +{ + return uint(kini_updateInterval_->value()); +} + + uint +NaughtyConfigDialog::threshold() const +{ + return uint(kini_threshold_->value()); +} + + QStringList +NaughtyConfigDialog::ignoreList() const +{ + QStringList retval; + + for (int i = 0; i < listBox_->count(); i++) + retval << listBox_->text(i); + + return retval; +} + diff --git a/kicker/applets/naughty/NaughtyConfigDialog.h b/kicker/applets/naughty/NaughtyConfigDialog.h new file mode 100644 index 000000000..485cbf14f --- /dev/null +++ b/kicker/applets/naughty/NaughtyConfigDialog.h @@ -0,0 +1,58 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef NAUGHTY_CONFIG_DIALOG_H +#define NAUGHTY_CONFIG_DIALOG_H + +#include <kdialogbase.h> + +class KEditListBox; +class KIntNumInput; + +class NaughtyConfigDialog : public KDialogBase +{ + Q_OBJECT + + public: + + NaughtyConfigDialog + ( + const QStringList & items, + uint interval, + uint threshold, + QWidget * parent = 0, + const char * name = 0 + ); + + ~NaughtyConfigDialog(); + + QStringList ignoreList() const; + uint updateInterval() const; + uint threshold() const; + + private: + + KEditListBox * listBox_; + + KIntNumInput * kini_updateInterval_; + KIntNumInput * kini_threshold_; +}; + +#endif diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.cpp b/kicker/applets/naughty/NaughtyProcessMonitor.cpp new file mode 100644 index 000000000..f9d352902 --- /dev/null +++ b/kicker/applets/naughty/NaughtyProcessMonitor.cpp @@ -0,0 +1,475 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* OpenBSD support by Jean-Yves Burlett <jean-yves@burlett.org> */ + +#ifdef __OpenBSD__ +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/sysctl.h> +#include <sys/ucred.h> +#include <sys/dkstat.h> +#include <stdlib.h> +#endif + +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> + +#include <qfile.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qtextstream.h> +#include <qdir.h> +#include <qtimer.h> +#include <qmap.h> +#include <qdatetime.h> + +#include <klocale.h> + +#include "NaughtyProcessMonitor.h" + +class NaughtyProcessMonitorPrivate +{ + public: + + NaughtyProcessMonitorPrivate() + : interval_(0), + timer_(0), + oldLoad_(0), + triggerLevel_(0) + { + } + + ~NaughtyProcessMonitorPrivate() + { + // Empty. + } + + uint interval_; + QTimer * timer_; + QMap<ulong, uint> loadMap_; + QMap<ulong, uint> scoreMap_; +#ifdef __OpenBSD__ + QMap<ulong, uint> cacheLoadMap_; + QMap<ulong, uid_t> uidMap_; +#endif + uint oldLoad_; + uint triggerLevel_; + + private: + + NaughtyProcessMonitorPrivate(const NaughtyProcessMonitorPrivate &); + + NaughtyProcessMonitorPrivate & operator = + (const NaughtyProcessMonitorPrivate &); +}; + +NaughtyProcessMonitor::NaughtyProcessMonitor + ( + uint interval, + uint triggerLevel, + QObject * parent, + const char * name + ) + : QObject(parent, name) +{ + d = new NaughtyProcessMonitorPrivate; + d->interval_ = interval * 1000; + d->triggerLevel_ = triggerLevel; + d->timer_ = new QTimer(this); + connect(d->timer_, SIGNAL(timeout()), this, SLOT(slotTimeout())); +} + +NaughtyProcessMonitor::~NaughtyProcessMonitor() +{ + delete d; +} + + void +NaughtyProcessMonitor::start() +{ + d->timer_->start(d->interval_, true); +} + + void +NaughtyProcessMonitor::stop() +{ + d->timer_->stop(); +} + + uint +NaughtyProcessMonitor::interval() const +{ + return d->interval_ / 1000; +} + + void +NaughtyProcessMonitor::setInterval(uint i) +{ + stop(); + d->interval_ = i * 1000; + start(); +} + + uint +NaughtyProcessMonitor::triggerLevel() const +{ + return d->triggerLevel_; +} + + void +NaughtyProcessMonitor::setTriggerLevel(uint i) +{ + d->triggerLevel_ = i; +} + + void +NaughtyProcessMonitor::slotTimeout() +{ + uint cpu = cpuLoad(); + + emit(load(cpu)); + + if (cpu > d->triggerLevel_ * (d->interval_ / 1000)) + { + uint load; + QValueList<ulong> l(pidList()); + + for (QValueList<ulong>::ConstIterator it(l.begin()); it != l.end(); ++it) + if (getLoad(*it, load)) + _process(*it, load); + } + + d->timer_->start(d->interval_, true); +} + + void +NaughtyProcessMonitor::_process(ulong pid, uint load) +{ + if (!d->loadMap_.contains(pid)) + { + d->loadMap_.insert(pid, load); + return; + } + + uint oldLoad = d->loadMap_[pid]; + bool misbehaving = (load - oldLoad) > 40 * (d->interval_ / 1000); + bool wasMisbehaving = d->scoreMap_.contains(pid); + + if (misbehaving) + if (wasMisbehaving) + { + d->scoreMap_.replace(pid, d->scoreMap_[pid] + 1); + if (canKill(pid)) + emit(runawayProcess(pid, processName(pid))); + } + else + d->scoreMap_.insert(pid, 1); + else + if (wasMisbehaving) + d->scoreMap_.remove(pid); + + d->loadMap_.replace(pid, load); +} + +// Here begins the set of system-specific methods. + + bool +NaughtyProcessMonitor::canKill(ulong pid) const +{ +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/status"); + + if (!f.open(IO_ReadOnly)) + return false; + + QTextStream t(&f); + + QString s; + + while (!t.atEnd() && s.left(4) != "Uid:") + s = t.readLine(); + + QStringList l(QStringList::split('\t', s)); + + uint a(l[1].toUInt()); + +// What are these 3 fields for ? Would be nice if the Linux kernel docs +// were complete, eh ? +// uint b(l[2].toUInt()); +// uint c(l[3].toUInt()); +// uint d(l[4].toUInt()); + + return geteuid() == a; +#elif defined(__OpenBSD__) + // simply check if entry exists in the uid map and use it + if (!d->uidMap_.contains(pid)) + return false ; + + return geteuid () == d->uidMap_[pid] ; +#else + Q_UNUSED( pid ); + return false; +#endif +} + + QString +NaughtyProcessMonitor::processName(ulong pid) const +{ +#if defined(__linux__) || defined(__OpenBSD__) +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/cmdline"); + + if (!f.open(IO_ReadOnly)) + return i18n("Unknown"); + + QCString s; + + while (true) + { + int c = f.getch(); + + // Stop at NUL + if (c == -1 || char(c) == '\0') + break; + else + s += char(c); + } + + // Now strip 'kdeinit:' prefix. + QString unicode(QString::fromLocal8Bit(s)); + +#elif defined(__OpenBSD__) + int mib[4] ; + size_t size ; + char **argv ; + + // fetch argv for the process `pid' + + mib[0] = CTL_KERN ; + mib[1] = KERN_PROC_ARGS ; + mib[2] = pid ; + mib[3] = KERN_PROC_ARGV ; + + // we assume argv[0]'s size will be less than one page + + size = getpagesize () ; + argv = (char **)calloc (size, sizeof (char)) ; + size-- ; // ensure argv is ended by 0 + if (-1 == sysctl (mib, 4, argv, &size, NULL, 0)) { + free (argv) ; + return i18n("Unknown") ; + } + + // Now strip 'kdeinit:' prefix. + QString unicode(QString::fromLocal8Bit(argv[0])); + + free (argv) ; +#endif + + QStringList parts(QStringList::split(' ', unicode)); + + QString processName = parts[0] == "kdeinit:" ? parts[1] : parts[0]; + + int lastSlash = processName.findRev('/'); + + // Get basename, if there's a path. + if (-1 != lastSlash) + processName = processName.mid(lastSlash + 1); + + return processName; + +#else + Q_UNUSED( pid ); + return QString::null; +#endif +} + + uint +NaughtyProcessMonitor::cpuLoad() const +{ +#ifdef __linux__ + QFile f("/proc/stat"); + + if (!f.open(IO_ReadOnly)) + return 0; + + bool forgetThisOne = 0 == d->oldLoad_; + + QTextStream t(&f); + + QString s = t.readLine(); + + QStringList l(QStringList::split(' ', s)); + + uint user = l[1].toUInt(); + uint sys = l[3].toUInt(); + + uint load = user + sys; + uint diff = load - d->oldLoad_; + d->oldLoad_ = load; + + return (forgetThisOne ? 0 : diff); +#elif defined(__OpenBSD__) + int mib[2] ; + long cp_time[CPUSTATES] ; + size_t size ; + uint load, diff ; + bool forgetThisOne = 0 == d->oldLoad_; + + // fetch CPU time statistics + + mib[0] = CTL_KERN ; + mib[1] = KERN_CPTIME ; + + size = CPUSTATES * sizeof(long) ; + + if (-1 == sysctl (mib, 2, cp_time, &size, NULL, 0)) + return 0 ; + + load = cp_time[CP_USER] + cp_time[CP_SYS] ; + diff = load - d->oldLoad_ ; + d->oldLoad_ = load ; + + return (forgetThisOne ? 0 : diff); +#else + return 0; +#endif +} + + QValueList<ulong> +NaughtyProcessMonitor::pidList() const +{ +#ifdef __linux__ + QStringList dl(QDir("/proc").entryList()); + + QValueList<ulong> pl; + + for (QStringList::ConstIterator it(dl.begin()); it != dl.end(); ++it) + if (((*it)[0].isDigit())) + pl << (*it).toUInt(); + + return pl; +#elif defined(__OpenBSD__) + int mib[3] ; + int nprocs = 0, nentries ; + size_t size ; + struct kinfo_proc *kp ; + int i ; + QValueList<ulong> l; + + // fetch number of processes + + mib[0] = CTL_KERN ; + mib[1] = KERN_NPROCS ; + + if (-1 == sysctl (mib, 2, &nprocs, &size, NULL, 0)) + return l ; + + // magic size evaluation ripped from ps + + size = (5 * nprocs * sizeof(struct kinfo_proc)) / 4 ; + kp = (struct kinfo_proc *)calloc (size, sizeof (char)) ; + + // fetch process info + + mib[0] = CTL_KERN ; + mib[1] = KERN_PROC ; + mib[2] = KERN_PROC_ALL ; + + if (-1 == sysctl (mib, 3, kp, &size, NULL, 0)) { + free (kp) ; + return l ; + } + + nentries = size / sizeof (struct kinfo_proc) ; + + // time statistics and euid data are fetched only for processes in + // the pidList, so, instead of doing one sysctl per process for + // getLoad and canKill calls, simply cache the data we already have. + + d->cacheLoadMap_.clear () ; + d->uidMap_.clear () ; + for (i = 0; i < nentries; i++) { + l << (unsigned long) kp[i].kp_proc.p_pid ; + d->cacheLoadMap_.insert (kp[i].kp_proc.p_pid, + (kp[i].kp_proc.p_uticks + + kp[i].kp_proc.p_sticks)) ; + d->uidMap_.insert (kp[i].kp_proc.p_pid, + kp[i].kp_eproc.e_ucred.cr_uid) ; + } + + free (kp) ; + + return l ; +#else + QValueList<ulong> l; + return l; +#endif +} + + bool +NaughtyProcessMonitor::getLoad(ulong pid, uint & load) const +{ +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/stat"); + + if (!f.open(IO_ReadOnly)) + return false; + + QTextStream t(&f); + + QString line(t.readLine()); + + QStringList fields(QStringList::split(' ', line)); + + uint userTime (fields[13].toUInt()); + uint sysTime (fields[14].toUInt()); + + load = userTime + sysTime; + + return true; +#elif defined(__OpenBSD__) + // use cache + if (!d->cacheLoadMap_.contains(pid)) + return false ; + + load = d->cacheLoadMap_[pid] ; + return true ; +#else + Q_UNUSED( pid ); + Q_UNUSED( load ); + return false; +#endif +} + + bool +NaughtyProcessMonitor::kill(ulong pid) const +{ +#if defined(__linux__) || defined(__OpenBSD__) + return 0 == ::kill(pid, SIGKILL); +#else + Q_UNUSED( pid ); + return false; +#endif +} + +#include "NaughtyProcessMonitor.moc" diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.h b/kicker/applets/naughty/NaughtyProcessMonitor.h new file mode 100644 index 000000000..d7023dbd7 --- /dev/null +++ b/kicker/applets/naughty/NaughtyProcessMonitor.h @@ -0,0 +1,76 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef NAUGHTY_PROCESS_MONITOR_H +#define NAUGHTY_PROCESS_MONITOR_H + +#include <qobject.h> + +class NaughtyProcessMonitorPrivate; + +class NaughtyProcessMonitor : public QObject +{ + Q_OBJECT + + public: + + NaughtyProcessMonitor + ( + uint interval, + uint triggerLevel, + QObject * parent = 0, + const char * name = 0 + ); + + virtual ~NaughtyProcessMonitor(); + + void start(); + void stop(); + + uint triggerLevel() const; + void setTriggerLevel(uint); + uint interval() const; + void setInterval(uint); + + virtual uint cpuLoad() const; + virtual QValueList<ulong> pidList() const; + virtual bool getLoad(ulong pid, uint & load) const; + virtual QString processName(ulong pid) const; + virtual bool canKill(ulong pid) const; + virtual bool kill(ulong pid) const; + + protected slots: + + void slotTimeout(); + + signals: + + void load(uint); + void runawayProcess(ulong pid, const QString & name); + + private: + + void _process(ulong pid, uint load); + + NaughtyProcessMonitorPrivate * d; +}; + +#endif + diff --git a/kicker/applets/naughty/configure.in.in b/kicker/applets/naughty/configure.in.in new file mode 100644 index 000000000..5847780f0 --- /dev/null +++ b/kicker/applets/naughty/configure.in.in @@ -0,0 +1,5 @@ +case "$host" in + *-*-freebsd*) LIB_KVM="-lkvm" ;; + *) LIB_KVM="" ;; +esac +AC_SUBST(LIB_KVM) diff --git a/kicker/applets/naughty/naughty-happy.png b/kicker/applets/naughty/naughty-happy.png Binary files differnew file mode 100644 index 000000000..3200b5270 --- /dev/null +++ b/kicker/applets/naughty/naughty-happy.png diff --git a/kicker/applets/naughty/naughty-sad.png b/kicker/applets/naughty/naughty-sad.png Binary files differnew file mode 100644 index 000000000..9b6541907 --- /dev/null +++ b/kicker/applets/naughty/naughty-sad.png diff --git a/kicker/applets/naughty/naughtyapplet.desktop b/kicker/applets/naughty/naughtyapplet.desktop new file mode 100644 index 000000000..f7cb6a35f --- /dev/null +++ b/kicker/applets/naughty/naughtyapplet.desktop @@ -0,0 +1,131 @@ +[Desktop Entry] +Type=Plugin +Name=Runaway Process Catcher +Name[af]=Weghardloop Proses Vanger +Name[ar]=لاقط الإجرائات الهاربة +Name[az]=İşıək GediÅŸat Yaxalayıcı +Name[be]=Захоп завіÑнуўшых працÑÑаў +Name[bg]=ÐеуправлÑеми процеÑи +Name[bn]=অনিয়নà§à¦¤à§à¦°à¦¿à¦¤ পà§à¦°à¦¸à§‡à¦¸ পà§à¦°à¦¹à¦°à§€ +Name[bs]=HvataÄ odbjeglih procesa +Name[ca]=Capturador de processos descontrolats +Name[cs]=OdchytávaÄ chybných procesů +Name[csb]=Jachtôrz zagùbionëch procesów +Name[cy]=Arhosydd Prosesau Di-derfyn +Name[da]=Indfanger af løbsk-kørte processer +Name[de]=Beenden unkontrollierter Prozesse +Name[el]=Runaway Έλεγχος ΔιεÏγασιών +Name[eo]=Kaptilo por eskapitaj procezoj +Name[es]=Capturador de procesos desbocados +Name[et]=Hanguvate protsesside püüdja +Name[eu]=Ataza eroen harrapatzailea +Name[fa]=گیرندۀ Ùرآیند Ùراری +Name[fi]=Karanneiden prosessien kiinniottaja +Name[fr]=Détecteur de processus fous +Name[fy]=Processenmonitor +Name[ga]=Sriantóir na bPróiseas Éalaitheach +Name[gl]=Detector de Procesos Estragados +Name[he]=תופס ×ª×”×œ×™×›×™× × ×ž×œ×˜×™× +Name[hi]=रनअवे पà¥à¤°à¥‰à¤¸à¥‡à¤¸ कैचर +Name[hr]=HvataÄ odbjeglih procesa +Name[hu]=Folyamatszabályozó +Name[is]=Ferlafangari +Name[it]=Rilevatore di processi impazziti +Name[ja]=手ã«è² ãˆãªã„プãƒã‚»ã‚¹ã®ã‚ャッãƒãƒ£ãƒ¼ +Name[kk]=Ð–Ð°Ò£Ñ‹Ð»Ñ‹Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑÑтерді байқаушы +Name[km]=ឧបករណáŸâ€‹áž…ាប់​យក​ដំណើរការ​ដែល​មិន​អាច​បញ្ជា​បាន +Name[lo]=ດັàºàºˆàº±àºšà»‚ປຣເສດ +Name[lt]=PabÄ—gusių procesų gaudyklÄ— +Name[lv]=NevadÄmu Procesu SavÄcÄ“js +Name[mk]=Фаќач на процеÑи бегалци +Name[mn]=Удирдлагагүй процеÑÑуудыг төгÑгөх +Name[ms]=Penangkap Proses Luar Kawalan +Name[mt]=Programm biex Jaqbad ProÄ‹essi Maħruba +Name[nb]=Fanger løpske prosesser +Name[nds]=Dörgahn Perzessen infangen +Name[ne]=रन वे पà¥à¤°à¥‹à¤¸à¥‡à¤¸ कà¥à¤¯à¤¾à¤šà¤° +Name[nl]=Processenmonitor +Name[nn]=Løpsk prosess-fangar +Name[nso]=Moswari wa Tiragalo yeo e Tshabago +Name[pa]=ਬੇਕਾਬੂ ਕਾਰਜ ਸ਼ਿਕਾਰੀ +Name[pl]=Åowca zagubionych procesów +Name[pt]=Colector de Processos em Fuga +Name[pt_BR]=Captura de processos +Name[ro]=Monitor de procese +Name[ru]=Сторож Ñбойных процеÑÑов +Name[rw]=Mufata Igikorwa Ntagenzura +Name[se]=Báhtaran proseassaid dustejeaddji +Name[sk]=Zachytenie chybných procesov +Name[sl]=Prestrezovalnik pobeglih procesov +Name[sr]=Хватач одбеглих процеÑа +Name[sr@Latn]=HvataÄ odbeglih procesa +Name[sv]=FÃ¥nga bortsprungna processer +Name[ta]=ஓடà¯à®ªà®¾à®¤à¯ˆ செயல௠பிடிபà¯à®ªà®¾à®©à¯ +Name[tg]=ДаÑтгиркунандаи протÑеÑÑҳои қарорӣ +Name[th]=ดัà¸à¸à¸²à¸£à¸ˆà¸šà¹‚ปรเซส +Name[tr]=Sorunlu Süreç Yakalayıcı +Name[tt]=IçqınÄŸan EÅŸlänü Totqıç +Name[uk]=Захоплювач процеÑів-дезертирів +Name[ven]=TShitenwa tsha Catcher +Name[vi]=Bắt Tiến trình Chạy trốn +Name[wa]=Troûleu d' sot processus +Name[zh_CN]=è½è·‘进程æ•æ‰å™¨ +Name[zh_TW]=失控程å¼æ•æ‰å™¨ +Name[zu]=Umbambi wenqubo ebalekayo +Comment=Detect and end broken processes which consume too much CPU time +Comment[af]=Spoor stukkende prosesse op wat te veel CPU tyd opneem en stop hulle +Comment[ar]=إكتش٠و أنهي الإجرائات المقطوعة اللتي تستهلك الكثير من وقت تشغيل ÙˆØدة المعالجة المركزية +Comment[be]=Вызначае Ñ– забівае Ð·Ð»Ð°Ð¼Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ñ†ÑÑÑ‹, ÑÐºÑ–Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваюць працÑÑар надта моцна +Comment[bg]=Ðамиране и прекратÑване на процеÑи, които конÑумират твърде много реÑурÑи +Comment[bs]=Otkrij i zavrÅ¡i neispravne procese koji zauzimaju previÅ¡e CPU vremena +Comment[ca]=Detecta i finalitza processos espatllats que consumeixen massa temps de CPU +Comment[cs]=ZjiÅ¡tÄ›nà a ukonÄenà poÅ¡kozených procesů ubÃrajÃcÃch výkon +Comment[csb]=Ã’dnajdiwô ë kùńczi niesprôwné procesë, jaczé brëkùjÄ… za wiele procesora +Comment[da]=Detekterer og afslutter fejlagtige processer som bruger for meget processortid +Comment[de]=Erkennen und Beenden fehlerhafter Prozesse, die zu viel Rechenzeit verbrauchen +Comment[el]=Ανίχνευση και τεÏματισμός διεÏγασιών που καταναλώνουν μεγάλο χÏόνο του επεξεÏγαστή +Comment[eo]=Detekti kaj mortigi difektitajn procezojn konsumante tro da procezilo-tempon +Comment[es]=Detectar procesos rotos que consumen demasiado tiempo del procesador +Comment[et]=Liialt protsessoriaega kulutavate katkiste rakenduste avastamine ja nende töö lõpetamine +Comment[eu]=Detektatu eta amaitu CPU gehiegi erabiltzen ari diren prozesuak +Comment[fa]=آشکارسازی Ùˆ پایان Ùرآیندهای قطع‌شده، Ú©Ù‡ زمان خیلی زیاد واØد پردازش مرکزی را مصر٠می‌کند. +Comment[fi]=Tunnista ja lopeta rikkinäiset prosessit, jotka kuluttavat liikaa laskentatehoa. +Comment[fr]=Détection et arrêt des programmes consommant trop de ressources du processeur +Comment[fy]=Untdekke en stopje alle brutsen prosessen dy tefolle prosessortiid konsumearje +Comment[gl]=Detecta e mata procesos estragados que consumen tempo de CPU +Comment[he]=×–×”×” וסגור ×ª×”×œ×™×›×™× ×©×¦×•×¨×›×™× ×™×•×ª×¨ מדי זמן מעבד +Comment[hr]=Otkrivanje i zavrÅ¡avanje nedovrÅ¡enih procesa koji troÅ¡e previÅ¡e procesorskog vremena +Comment[hu]=A túl sok processzoridÅ‘t lefoglaló folyamatok meghatározása és bezárása +Comment[is]=Uppgötvaðu og slökktu á rofnum ferlum sem taka of mikinn örgjörvatÃma +Comment[it]=Trova e termina i processi impazziti che consuma troppo processore +Comment[ja]=CPU 時間を無駄ã«æ¶ˆè²»ã™ã‚‹å£Šã‚ŒãŸãƒ—ãƒã‚»ã‚¹ã‚’見ã¤ã‘ã¦çµ‚了ã•ã›ã‚‹ +Comment[kk]=ПроңеÑÑорды көп жұмÑайтын процеÑÑарды табу және жою +Comment[km]=រក និង​បញ្ចប់​ដំណើរការ​ážáž¼áž…​ដែល​ប្រើ​ពáŸáž›ážœáŸáž›áž¶ CPU ច្រើន​ពáŸáž€ +Comment[lt]=Aptikti ir užbaigti sugadintus procesus, kurie suryja per daug CPU laiko +Comment[mk]=Откривање и прекинување на нефункционални процеÑи што го трошат времето на процеÑорот +Comment[nb]=Finn og avslutt løpske prosesser som tar for mye prosessorkraft +Comment[nds]=Schaadhaftig Perzessen, de to veel Rekentiet bruukt, opdecken un beennen +Comment[ne]=पà¥à¤°à¤¸à¤¸à¥à¤¤ CPU समय खपत गरà¥à¤¨à¥‡ कमजोर पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ पतà¥à¤¤à¤¾ लगाउनà¥à¤¹à¥‹à¤¸à¥ र अनà¥à¤¤à¥à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Comment[nl]=Detecteer en stop gebroken processen die teveel processortijd consumeren +Comment[nn]=Finn og avslutt løpske prosessar som tek for myjke prosessorkraft. +Comment[pl]=Wykrywa i koÅ„czy niesprawne procesy, które zużywajÄ… za dużo procesora +Comment[pt]=Detectar e terminar os processos com problemas que estejam a consumir demasiado CPU +Comment[pt_BR]=Detecta e finaliza processos quebrados que consomem muito tempo de CPU +Comment[ro]=Detectează È™i termină procese defecte care consumă prea mult CPU +Comment[ru]=Обнаружение и завершение процеÑÑов, требующим Ñлишком много времени процеÑÑора +Comment[se]=Gávnna jea heaittit reakÄanan proseassaid mat geavahit menddo olu CPU-áiggi +Comment[sk]=Zistenie a ukonÄenie procesov, ktoré spotrebúvajú priveľa Äasu CPU +Comment[sl]=Zaznavanje in pobijanje procesov, ki porabljajo preveÄ procesorskega Äasa +Comment[sr]=Детектује и окончава покварене процеÑе који одузимају превише процеÑорÑког времена +Comment[sr@Latn]=Detektuje i okonÄava pokvarene procese koji oduzimaju previÅ¡e procesorskog vremena +Comment[sv]=Detekterar och avslutar felaktiga processer som använder för mycket processortid +Comment[th]=ตรวจจับà¹à¸¥à¸°à¸ˆà¸šà¹‚ปรเซสที่เสียหาย ซึ่งใช้เวลาขà¸à¸‡à¸«à¸™à¹ˆà¸§à¸¢à¸›à¸£à¸°à¸¡à¸§à¸¥à¸œà¸¥à¸¡à¸²à¸à¹€à¸à¸´à¸™à¹„ป +Comment[tr]=Sorunlu ve fazla iÅŸlemci gücü harcayan programları bulup yokeder +Comment[uk]=ВиÑÐ²Ð»ÐµÐ½Ð½Ñ Ñ– Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑів, Ñкі Ñпоживають забагато чаÑу процеÑора +Comment[vi]=Phát hiện và ngừng các tiến trình gây lãng phà bá»™ vi xá» lý +Comment[wa]=Trove et arestêye les schetés processus k' eployèt trop di tins CPU +Comment[zh_CN]=检测并结æŸå 用太多 CPU 时间的进程 +Comment[zh_TW]=åµæ¸¬ä¸¦çµ‚çµæµªè²»å¤šæ•¸ CPU æ™‚é–“çš„ç ´æç¨‹åº +Icon=runprocesscatcher +X-KDE-Library=naughty_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/run/Makefile.am b/kicker/applets/run/Makefile.am new file mode 100644 index 000000000..ec4de4984 --- /dev/null +++ b/kicker/applets/run/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = run_panelapplet.la + +run_panelapplet_la_SOURCES = runapplet.cpp + +METASOURCES = runapplet.moc +noinst_HEADERS = runapplet.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = runapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +run_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +run_panelapplet_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/krunapplet.pot diff --git a/kicker/applets/run/runapplet.cpp b/kicker/applets/run/runapplet.cpp new file mode 100644 index 000000000..93bb5d7ad --- /dev/null +++ b/kicker/applets/run/runapplet.cpp @@ -0,0 +1,294 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlabel.h> +#include <qfont.h> +#include <qstringlist.h> +#include <qpushbutton.h> +#include <qhbox.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klocale.h> +#include <kconfig.h> +#include <kcombobox.h> +#include <kurifilter.h> +#include <kdialog.h> +#include <krun.h> +#include <kmessagebox.h> + +#include "runapplet.h" +#include "runapplet.moc" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("krunapplet"); + return new RunApplet(configFile, KPanelApplet::Stretch, 0, parent, "krunapplet"); + } +} + +RunApplet::RunApplet(const QString& configFile, Type type, int actions, + QWidget *parent, const char *name) + : KPanelApplet(configFile, type, actions, parent, name) +{ + // setBackgroundMode(X11ParentRelative); + setBackgroundOrigin( AncestorOrigin ); + // setup label + _label = new QLabel(i18n("Run command:"), this); + QFont f(_label->font()); + f.setPixelSize(12); +// _label->setBackgroundMode(X11ParentRelative); + _label->setBackgroundOrigin( AncestorOrigin ); + _label->setFixedHeight(14); + _label->setFont(f); + + // setup popup button + _btn = new QPushButton(this); + f = _btn->font(); + f.setPixelSize(12); + _btn->setFont(f); + connect(_btn, SIGNAL(clicked()), SLOT(popup_combo())); + + // setup history combo + _input = new KHistoryCombo(this); + _input->setFocus(); + _input->clearEdit(); + watchForFocus(_input->lineEdit()); + connect(_input, SIGNAL(activated(const QString&)), + SLOT(run_command(const QString&))); + + KConfig *c = config(); + c->setGroup("General"); + + // restore history and completion list + QStringList list = c->readListEntry("Completion list"); + _input->completionObject()->setItems(list); + list = c->readListEntry("History list"); + _input->setHistoryItems(list); + int mode = c->readNumEntry( "CompletionMode", KGlobalSettings::completionMode() ); + _input->setCompletionMode( (KGlobalSettings::Completion) mode ); + + _filterData = new KURIFilterData(); + + _hbox = new QHBox( 0, 0, WStyle_Customize | WType_Popup ); + _hbox->setFixedSize(120, 22); +} + +RunApplet::~RunApplet() +{ + KConfig *c = config(); + c->setGroup("General"); + + // save history and completion list + QStringList list = _input->completionObject()->items(); + c->writeEntry("Completion list", list); + list = _input->historyItems(); + c->writeEntry("History list", list); + c->writeEntry( "CompletionMode", (int) _input->completionMode() ); + c->sync(); + + delete _filterData; + KGlobal::locale()->removeCatalogue("krunapplet"); +} + +void RunApplet::resizeEvent(QResizeEvent*) +{ + if(orientation() == Horizontal) + { + _btn->hide(); + _input->reparent(this, QPoint(0,0), true); + _label->setGeometry(0,0, width(), _label->height()); + + if(height() >= _input->sizeHint().height() + _label->height()) + { + int inputVOffset = height() - _input->sizeHint().height() - 2; + int labelHeight = _label->sizeHint().height(); + _label->setGeometry(0, inputVOffset - labelHeight, + width(), labelHeight); + _input->setGeometry(0, inputVOffset, + width(), _input->sizeHint().height()); + _label->show(); + } + else + { + _label->hide(); + + // make it as high as the combobox naturally wants to be + // but no taller than the panel is! + // don't forget to center it vertically either. + int newHeight = _input->sizeHint().height(); + if (newHeight > height()) + newHeight = height(); + _input->setGeometry(0, (height() - newHeight) / 2, + width(), newHeight); + } + } + else + { + _btn->show(); + _btn->setFixedSize(width(), 22); + _input->reparent( _hbox, QPoint(0, 0), false); + _label->hide(); + } + setButtonText(); +} + +void RunApplet::positionChange(KPanelApplet::Position) +{ + setButtonText(); +} + +void RunApplet::setButtonText() +{ + QString t; + + if (position() == pRight) + { + if (width() >= 42) + t = i18n("< Run"); + else + t = "<"; + } + else + { + if(width() >= 42) + t = i18n("Run >"); + else + t = ">"; + } + + _btn->setText(t); +} + +int RunApplet::widthForHeight(int ) const +{ + return _label->sizeHint().width(); +} + +int RunApplet::heightForWidth(int ) const +{ + return 22; +} + +void RunApplet::popup_combo() +{ + QPoint p; + if (position() == pRight) + p = mapToGlobal(QPoint(-_input->width()-1, 0)); + else + p = mapToGlobal(QPoint(width()+1, 0)); + _hbox->move(p); + _hbox->show(); + _input->setFocus(); +} + +void RunApplet::run_command(const QString& command) +{ + QString exec; + bool focusNeeded = false; + + kapp->propagateSessionManager(); + + _filterData->setData( _input->currentText().stripWhiteSpace() ); + QStringList filters; + filters << "kurisearchfilter" << "kshorturifilter"; + KURIFilter::self()->filterURI( *(_filterData), filters ); + + _input->addToHistory(command); + _input->clearEdit(); + + QString cmd = (_filterData->uri().isLocalFile() ? _filterData->uri().path():_filterData->uri().url()); + + // Nothing interesting. Quit! + if ( cmd.isEmpty() ){ + KMessageBox::sorry(0L, i18n("You have to enter a command to execute " + "or a URL to be opened first.")); + focusNeeded = true; + goto hide; + } + else if (cmd == "logout") + { + bool shutdown = kapp->requestShutDown(); + if( !shutdown ) + { + // This i18n string is in kdesktop/desktop.cc as well. Maybe we should DCOP to kdesktop instead ? + KMessageBox::error( 0, i18n("Unable to log out properly.\nThe session manager cannot " + "be contacted. You can try to force a shutdown by pressing " + "Ctrl+Alt+Backspace. Note, however, that your current " + "session will not be saved with a forced shutdown." ) ); + focusNeeded = true; + } + goto hide; + } + else + { + switch( _filterData->uriType() ) + { + case KURIFilterData::LOCAL_FILE: + case KURIFilterData::LOCAL_DIR: + case KURIFilterData::NET_PROTOCOL: + case KURIFilterData::HELP: + { + (void) new KRun( _filterData->uri() ); + goto hide; + } + case KURIFilterData::EXECUTABLE: + case KURIFilterData::SHELL: + { + exec = cmd; + if( _filterData->hasArgsAndOptions() ) + cmd += _filterData->argsAndOptions(); + break; + } + case KURIFilterData::UNKNOWN: + case KURIFilterData::ERROR: + default: + KMessageBox::sorry( 0, i18n("<qt>The program name or command <b>%1</b>\n" + "cannot be found. Please correct the command\n" + "or URL and try again</qt>").arg( cmd ) ); + _input->removeFromHistory( _input->currentText() ); + focusNeeded = true; + goto hide; + } + } + if (KRun::runCommand( cmd, exec, "" )) + goto hide; + else + { + KMessageBox::sorry( 0, i18n("<qt>Could not run <b>%1</b>.\nPlease correct" + " the command or URL and try again.</qt>").arg( cmd ) ); + _input->removeFromHistory( _input->currentText() ); + focusNeeded = true; + goto hide; + } + + needsFocus(focusNeeded); + return; + + hide: + if (orientation() == Vertical) + _hbox->hide(); + needsFocus(focusNeeded); +} diff --git a/kicker/applets/run/runapplet.desktop b/kicker/applets/run/runapplet.desktop new file mode 100644 index 000000000..66937ccae --- /dev/null +++ b/kicker/applets/run/runapplet.desktop @@ -0,0 +1,130 @@ +[Desktop Entry] +Type=Plugin +Name=Run Command +Name[af]=Hardloop Opdrag +Name[ar]=تنÙيذ الأمر +Name[be]=Выканаць праграму +Name[bg]=Изпълнение на команда +Name[bn]=কমানà§à¦¡ চালাও +Name[br]=Seveniñ ur Goulev +Name[bs]=IzvrÅ¡i naredbu +Name[ca]=Executa un comandament +Name[cs]=Spustit pÅ™Ãkaz +Name[csb]=Zrëszënié pòlétu +Name[cy]=Rhedeg Gorchymyn +Name[da]=Kør kommando +Name[de]=Befehl ausführen +Name[el]=ΕκτÎλεση εντολής +Name[eo]=Lanĉu komandon +Name[es]=Ejecutar una orden +Name[et]=Käsu käivitamine +Name[eu]=Exekutatu komandoa +Name[fa]=اجرای Ùرمان +Name[fi]=Suorita komento +Name[fr]=Lancer une commande +Name[fy]=kommando útfiere +Name[ga]=Rith Ordú +Name[gl]=Executar Comando +Name[he]=הפעלת פקודה +Name[hi]=कमांड चलाà¤à¤ +Name[hr]=Pokreni naredbu +Name[hu]=Parancs végrehajtása +Name[is]=Keyra skipun +Name[it]=Esegui comando +Name[ja]=コマンドを実行 +Name[ka]=ბრძáƒáƒœáƒ”ბის შესრულებრ+Name[kk]=Команданы орындау +Name[km]=ážšážáŸ‹â€‹áž–ាក្យ​បញ្ជា +Name[ko]=Penguin Command +Name[lt]=Paleisti komandÄ… +Name[lv]=DarbinÄt komandu +Name[mk]=Изврши команда +Name[ms]=Arahan Laksana +Name[nb]=Kjør kommando +Name[nds]=Befehl utföhren +Name[ne]=आदेश चलाउनà¥à¤¹à¥‹à¤¸à¥ +Name[nl]=Commando uitvoeren +Name[nn]=Køyr kommando +Name[pa]=ਕਮਾਂਡ ਚਲਾਓ +Name[pl]=Uruchomienie polecenia +Name[pt]=Executar um Comando +Name[pt_BR]=Executar Comando +Name[ro]=Execută comanda +Name[ru]=Выполнить команду +Name[rw]=Gutangiza Ibwiriza +Name[se]=Vuoje gohÄÄuma +Name[sk]=VykonaÅ¥ prÃkaz +Name[sl]=Poženi ukaz +Name[sr]=Покретање наредбе +Name[sr@Latn]=Pokretanje naredbe +Name[sv]=Kör kommando +Name[ta]=இயகà¯à®• கடà¯à®Ÿà®³à¯ˆ +Name[tg]=Иҷрои фармон +Name[th]=ใช้งานคำสั่ง +Name[tr]=Komut Çalıştır +Name[tt]=Boyırıq EÅŸlätü +Name[uk]=ЗапуÑк команди +Name[uz]=Buyruqni bajarish +Name[uz@cyrillic]=Буйруқни бажариш +Name[vi]=Gõ lệnh +Name[wa]=Enonder ene comande +Name[zh_CN]=è¿è¡Œå‘½ä»¤ +Name[zh_TW]=執行命令 +Comment=Launch single commands without a terminal window +Comment[af]=Lanseer enkel opdragte sonder 'n terminaal venster +Comment[ar]=أطلق أوامر ÙˆØيدة بدون الØاجة إلى ناÙذة المطرا٠+Comment[be]=ЗапуÑкае аÑÐ¾Ð±Ð½Ñ‹Ñ ÐºÐ°Ð¼Ð°Ð½Ð´Ñ‹ без Ñ‚Ñрмінальнага акна +Comment[bg]=Стартиране на команда без да има нужда от терминален прозорец +Comment[bn]=টারà§à¦®à¦¿à¦¨à¦¾à¦² উইণà§à¦¡à§‹ ছাড়াই à¦à¦•à¦Ÿà¦¿ কমানà§à¦¡ চালান +Comment[bs]=IzvrÅ¡ite pojedinaÄne naredbe bez prozora terminala +Comment[ca]=Engega ordres sense una finestra de terminal +Comment[cs]=SpouÅ¡tÄ›nà jednotlivých pÅ™Ãkazů bez terminálového okna +Comment[csb]=Zrëszanié pòjediÅ„czëch pòlétów kònsolë bez òtmëkaniô òkna terminala +Comment[da]=Start enkelte kommandoer uden et terminalvindue +Comment[de]=Ausführen einzelner Kommandos ohne Terminalfenster +Comment[el]=ΕκτÎλεση εντολών χωÏίς Îνα παÏάθυÏο τεÏÎ¼Î±Ï„Î¹ÎºÎ¿Ï +Comment[eo]=Lanĉi unuopajn komandojn sen terminala fenestro +Comment[es]=Lanzar órdenes individuales sin ventana de terminal +Comment[et]=Ãœksikute käskude käivitamine terminali abita +Comment[eu]=Abiarazi komandoak terminal leihorik gabe +Comment[fa]=راه‌اندازی Ùرمانهای تک بدون پنجرۀ پایانه +Comment[fi]=Käynnistä yksittäisiä komentoja ilman pääteikkunaa. +Comment[fr]=Lancer des commandes simples sans fenêtre de terminal +Comment[fy]=Fier losse kommando's út sûnder in terminalfinster +Comment[ga]=Rith orduithe aonair gan fhuinneog theirminéil +Comment[gl]=Executa comandos individuais sen usar unha terminal +Comment[he]=הפעל פקודות פשוטות ×œ×œ× ×—×œ×•×Ÿ מסוף +Comment[hr]=Pokretanje pojedinih naredbi bez terminalskog prozora +Comment[hu]=Parancs kiadása parancsértelmezÅ‘ ablak nélkül +Comment[is]=Keyrðu einstakar skipanir án skeljaglugga +Comment[it]=Lancia singoli comandi senza una finestra di terminale +Comment[ja]=ターミナルウィンドウを開ã‹ãšã«ä¸€ã¤ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’実行 +Comment[kk]=Болек командаларды терминал терезеÑінен Ñ‚Ñ‹Ñ Ð¶ÐµÐ³Ñƒ +Comment[km]=បើក​ពាក្យ​បញ្ជា​ážáŸ‚​មួយ ដោយ​គ្មាន​បង្អួច​ស្ážáž¶áž“ីយ +Comment[lt]=Vykdykite pavienes komandas ne terminalo lange +Comment[mk]=Стартување на единечни команди без терминалÑки прозорец +Comment[nb]=Kjør en enkelt kommando uten et skall +Comment[nds]=Enkel Befehlen ahn Terminalfinster starten +Comment[ne]=टरà¥à¤®à¤¿à¤¨à¤² सञà¥à¤à¥à¤¯à¤¾à¤² बिना à¤à¤•à¤² आदेश सà¥à¤°à¥à¤†à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Comment[nl]=Voer losse commando's uit zonder een terminalvenster +Comment[nn]=Køyr ein enkelt kommando utan eit skal. +Comment[pl]=Uruchamianie pojedynczych poleceÅ„ konsoli bez otwierania okna terminala +Comment[pt]=Lançar comandos simples sem uma janela de terminal +Comment[pt_BR]=Abre comandos digitados sem a necessidade de uma janela de terminal +Comment[ro]=Lansează comenzi fără o fereastră de terminal +Comment[ru]=Выполнение отдельной команды без окна терминала +Comment[se]=Vuoje oktonas gohÄÄomiid terminálaláse haga +Comment[sk]=SpustiÅ¥ prÃkaz bez okna terminálu +Comment[sl]=Poganjanje posameznih ukazov brez okna terminala +Comment[sr]=Покрените једноÑтруке наредбе без терминалÑког прозора +Comment[sr@Latn]=Pokrenite jednostruke naredbe bez terminalskog prozora +Comment[sv]=Starta enstaka kommandon utan ett terminalfönster +Comment[th]=เรียà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸„ำสั่งเดี่ยวๆ โดยไม่ต้à¸à¸‡à¹€à¸‚้าหน้าต่างเทà¸à¸£à¹Œà¸¡à¸´à¸™à¸±à¸¥ +Comment[uk]=ЗапуÑк окремих команд без вікна термінала +Comment[vi]=Chạy má»™t lệnh Ä‘Æ¡n mà không cần mở má»™t thiết bị đầu cuối +Comment[wa]=Lancî ene comande seule sins terminÃ¥ +Comment[zh_CN]=调用å•æ¡å‘½ä»¤è€Œæ— é¡»ä½¿ç”¨ç»ˆç«¯çª—å£ +Comment[zh_TW]=ä¸ä½¿ç”¨çµ‚端機視窗而é€å‡ºå–®è¡ŒæŒ‡ä»¤ +Icon=exec +X-KDE-Library=run_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/run/runapplet.h b/kicker/applets/run/runapplet.h new file mode 100644 index 000000000..ded8fc398 --- /dev/null +++ b/kicker/applets/run/runapplet.h @@ -0,0 +1,65 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __runapplet_h__ +#define __runapplet_h__ + +#include <qstring.h> +#include <kpanelapplet.h> + +class QLabel; +class QHBox; +class QPushButton; +class KHistoryCombo; +class KURIFilterData; + +class RunApplet : public KPanelApplet +{ + Q_OBJECT + +public: + RunApplet(const QString& configFile, Type t = Stretch, int actions = 0, + QWidget *parent = 0, const char *name = 0); + virtual ~RunApplet(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + +protected: + void resizeEvent(QResizeEvent*); + void positionChange(KPanelApplet::Position); + +protected slots: + void run_command(const QString&); + void popup_combo(); + void setButtonText(); + +private: + KHistoryCombo *_input; + KURIFilterData *_filterData; + QLabel *_label; + QPushButton *_btn; + QHBox *_hbox; +}; + +#endif diff --git a/kicker/applets/swallow/Makefile.am b/kicker/applets/swallow/Makefile.am new file mode 100644 index 000000000..1b88a0c10 --- /dev/null +++ b/kicker/applets/swallow/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = swallow_panelapplet.la + +swallow_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +swallow_panelapplet_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) + +swallow_panelapplet_la_SOURCES = swallow.cpp prefwidgetbase.ui prefwidget.cpp + +noinst_HEADERS = swallow.h prefwidget.h prefwidgetbase.h + +swallow_panelapplet_la_METASOURCES = AUTO + +applnk_DATA = swallowapplet.desktop +applnkdir = $(kde_datadir)/kicker/applets + +#messages: rc.cpp +# $(XGETTEXT) *.cpp -o $(podir)/swallowapplet.pot diff --git a/kicker/applets/swallow/prefwidget.cpp b/kicker/applets/swallow/prefwidget.cpp new file mode 100644 index 000000000..2e443a6b2 --- /dev/null +++ b/kicker/applets/swallow/prefwidget.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2001 Daniel Molkentin <molkentin@kde.org> + * + * 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 + */ + +#include <keditlistbox.h> + +#include "prefwidget.h" + +PreferencesWidget::PreferencesWidget( SwallowCommandList *swc, QWidget *parent ) + : PreferencesWidgetBase(parent) +{ + + SwallowCommandListIterator it( *swc ); + SwallowCommand *currentCL; + while ( ( currentCL = it.current() ) != 0 ) + { + ++it; + klebDockApps->insertItem( currentCL->title ); + } +} +/* +PreferencesWidget::~PreferencesWidget() +{ +} +*/ +#include "prefwidget.moc" diff --git a/kicker/applets/swallow/prefwidget.h b/kicker/applets/swallow/prefwidget.h new file mode 100644 index 000000000..76ecce35e --- /dev/null +++ b/kicker/applets/swallow/prefwidget.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2001 Daniel Molkentin <molkentin@kde.org> + * + * 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 + */ + +#ifndef PREFWIDGET_H +#define PREFWIDGET_H + +#include "prefwidgetbase.h" +#include "swallow.h" + +class PreferencesWidget : public PreferencesWidgetBase +{ + Q_OBJECT + +public: + PreferencesWidget( SwallowCommandList* swc, QWidget* parent = 0 ); +// ~PreferencesWidget(); + +}; + +#endif diff --git a/kicker/applets/swallow/prefwidgetbase.ui b/kicker/applets/swallow/prefwidgetbase.ui new file mode 100644 index 000000000..bd2673efa --- /dev/null +++ b/kicker/applets/swallow/prefwidgetbase.ui @@ -0,0 +1,134 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>PreferencesWidgetBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>PreferencesWidgetBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>409</width> + <height>366</height> + </rect> + </property> + <property name="caption"> + <string>AppDock Preferences</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="3" column="2"> + <property name="name"> + <cstring>PushButton1</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="on"> + <bool>false</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="KEditListBox" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>klebDockApps</cstring> + </property> + <property name="title"> + <string>Applications to Dock</string> + </property> + </widget> + <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Entry Details</string> + </property> + <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>&Name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>leName</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Command &line:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>urlCommandLine</cstring> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>leName</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Specify a short name for the application.</string> + </property> + </widget> + <widget class="KURLRequester" row="1" column="1"> + <property name="name"> + <cstring>urlCommandLine</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Specify a path to the application. This may include startup parameters. You can use the folder icon to select the application.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton" row="3" column="3"> + <property name="name"> + <cstring>PushButton2</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + <spacer row="3" column="1"> + <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>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<includes> + <include location="local" impldecl="in implementation">kdialog.h</include> +</includes> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>keditlistbox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kicker/applets/swallow/swallow.cpp b/kicker/applets/swallow/swallow.cpp new file mode 100644 index 000000000..b1224986b --- /dev/null +++ b/kicker/applets/swallow/swallow.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2000 Matthias Elter <elter@kde.org> + * 2000 Carsten Pfeiffer <pfeiffer@kde.org> + * based on keyes (C) 1999 by Jerome Tollet <tollet@magic.fr> + * + * 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 + */ + + +#include <stdlib.h> + +#include <qlayout.h> +#include <qstringlist.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kshell.h> +#include <kwin.h> +#include <kwinmodule.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "swallow.h" +#include "prefwidget.h" + +template class QPtrList<SwallowApp>; +typedef QPtrListIterator<SwallowApp> SwallowAppListIterator; +template class QPtrList<SwallowCommand>; + + +// init static variables +SwallowAppList * SwallowApplet::appList = 0L; +SwallowAppList * SwallowApplet::embeddedList = 0L; +KWinModule * SwallowApplet::wModule = 0L; +SwallowApplet * SwallowApplet::self = 0L; + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) { + return new SwallowApplet(configFile, parent, "kswallow applet"); + } +} + + +SwallowApplet::SwallowApplet( const QString& configFile, + QWidget *parent, const char *name ) + : KPanelApplet( configFile, Normal, Preferences, parent, name ) +{ + resize( 30, 30 ); + kdDebug() << "**** constructing swallow applet (" << configFile << ") ****" << endl; + self = this; + m_swcList = new SwallowCommandList; + m_swcList->setAutoDelete( true ); + wModule = new KWinModule(this); + embeddedList = new SwallowAppList; + embeddedList->setAutoDelete( false ); + appList = new SwallowAppList; + appList->setAutoDelete( true ); + + QBoxLayout::Direction d = (orientation() == Horizontal) ? + QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; + m_layout = new QBoxLayout( this, d, 0, 2 ); // make stretch configurable? + m_layout->setAutoAdd( false ); + + // read the config file and start all the configured apps + createApps( readConfig() ); + + if ( appList->count() == 0 ) { + if ( KMessageBox::questionYesNo(0L, i18n("There is no swallowed application, " + "do you want to configure or quit?"), i18n("No Swallowed Application"), + KGuiItem(i18n("Configure"),"configure"), KStdGuiItem::quit()) == KMessageBox::Yes ) + preferences(); + else { + delete this; + ::exit(0); + } + } + + emit updateLayout(); +} + +SwallowApplet::~SwallowApplet() +{ + kdDebug() << "********************** DELETING ************************" << endl; + + delete m_swcList; + delete embeddedList; + delete appList; + delete wModule; + wModule = 0L; +} + + +SwallowCommandList* SwallowApplet::readConfig() +{ + m_swcList->clear(); + KConfig *kc = config(); + + kc->setGroup("General"); + int count = kc->readNumEntry("Number of apps"); + kdDebug() << "*** Registered " << count << " App(s) to be swallow'ed!" << endl; + QString group = "SwallowApp %1"; + QString title, cmd; + ushort errors = 0; + SwallowCommand *swc = 0L; + + for ( int i = 1; i <= count; i++ ) { + kc->setGroup( group.arg(i) ); + cmd = kc->readPathEntry("Commandline"); + title = kc->readEntry("Window title"); + kdDebug() << "*** Found Entry: Cmd-Line: " << cmd << " Window-Title: " << title << endl; + + if ( !cmd.isEmpty() && !title.isEmpty() ) { + swc = new SwallowCommand; + swc->cmdline = cmd; + swc->title = title; + m_swcList->append( swc ); + } + // remember items with non-null cmdline or title, + // discard items with empty cmdline and empty title + else if ( !(cmd.isEmpty() && title.isEmpty()) ) + errors++; + } + + if ( errors > 0 ) { + QString entry = (errors == 1) ? i18n("entry") : i18n("entries"); + if ( KMessageBox::questionYesNo(0L, i18n("I found %1 invalid/incomplete %2\nin the configuration file.\n\nBoth the window title and the commandline\n of the to be swallowed application\nare required.\n\n.Do you want to correct this?").arg(errors).arg(entry), i18n("Configuration Error"),i18n("Correct"),i18n("Ignore Error")) == KMessageBox::Yes) + preferences(); + } + + return m_swcList; +} + + +void SwallowApplet::createApps( SwallowCommandList* list ) +{ + SwallowApp *app = 0L; + + SwallowCommandListIterator it( *list ); + while ( (it.current()) ) { + app = new SwallowApp( it.current(), this ); + app->hide(); + connect( app, SIGNAL( embedded(SwallowApp *)), + SLOT( embedded(SwallowApp *))); + appList->append( app ); + ++it; + kapp->processEvents(); + } + + m_layout->activate(); +} + + +void SwallowApplet::embedded( SwallowApp *app ) +{ + kdDebug() << " -> embedding " << app << ", current size is: " << width() << ", " << height() << endl; + if ( orientation() == Horizontal ) + app->resize(height() * app->sizeRatio(), height() ); + else + app->resize(width(), width() * app->sizeRatio()); + + kdDebug() << "--> ratio: " << app->sizeRatio() << endl; + kdDebug() << "**** " << app << " is embedded now, with (" << app->width() << ", " << app->height() << ")" << endl; + + disconnect( app, SIGNAL( embedded(SwallowApp *)), + this, SLOT( embedded(SwallowApp *))); + + embeddedList->append( app ); + + if ( orientation() == Horizontal ) + resize( widthForHeight( height() ), height() ); + else + resize( width(), heightForWidth( width() )); + + m_layout->addWidget( app ); + app->show(); + updateGeometry(); + emit updateLayout(); +} + +void SwallowApplet::preferences() +{ + PreferencesWidget *prefs = new PreferencesWidget(m_swcList,this); + prefs->show(); +} + + +int SwallowApplet::widthForHeight(int he) +{ + kdDebug() << "**** width for h: " << he << endl; + int w = embeddedList->isEmpty() ? 30 : 0; + layoutApps(); + SwallowAppListIterator it( *embeddedList ); + while ( it.current() ) { + kdDebug() << "current: " << it.current()->width() << endl; + w += (it.current())->width(); + ++it; + } + + kdDebug() << "**** wfh: " << w << " : count: " << embeddedList->count() << endl; + return w; +} + + +int SwallowApplet::heightForWidth(int) +{ + int h = embeddedList->isEmpty() ? 30 : 0; + layoutApps(); + SwallowAppListIterator it( *embeddedList ); + while ( it.current() ) { + h += (it.current())->height(); + ++it; + } + + kdDebug() << "**** hfw: " << h << endl; + return h; +} + +void SwallowApplet::layoutApps() +{ + if ( KPanelApplet::orientation() == Horizontal ) + m_layout->setDirection( QBoxLayout::LeftToRight ); + else + m_layout->setDirection( QBoxLayout::TopToBottom ); +} + + +void SwallowApplet::removeApplet( SwallowApp *app ) +{ + embeddedList->removeRef( app ); + appList->remove( app ); + emit self->updateLayout(); +} + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + + +static void parseCommand(KProcess *proc, QString cmd) +{ + int pos; + + cmd += " "; + + pos = cmd.find(' '); + *proc << cmd.left(pos); + cmd.remove(0,pos); + cmd = cmd.stripWhiteSpace(); + *proc << KShell::splitArgs(cmd, KShell::TildeExpand | KShell::AbortOnMeta); +} + + +SwallowApp::SwallowApp(const SwallowCommand *swc, QWidget* parent, + const char* /* name */) + : QXEmbed( parent ) +{ + wh_ratio = 1; + setAutoDelete( false ); + QXEmbed::initialize(); + + winTitle = swc->title; + connect(SwallowApplet::winModule(), SIGNAL(windowAdded(WId)), + this, SLOT(windowAdded(WId))); + + if (!swc->cmdline.isEmpty()) { + KProcess *process = new KProcess; + parseCommand(process, swc->cmdline); + + // move window out of sight + // *process << "-geometry"; + // *process << QString("32x32+%1+%2").arg(kapp->desktop()->width()).arg(kapp->desktop()->height()); + + connect(process, SIGNAL(processExited(KProcess*)), + this, SLOT(processExited(KProcess*))); + + process->start(); + } +} + + +SwallowApp::~SwallowApp() +{ + delete process; +} + + +void SwallowApp::windowAdded(WId win) +{ + // determine title of newly mapped window + XTextProperty nameProp; + XGetWMName(qt_xdisplay(), win, &nameProp); + char **names; + int count; + XTextPropertyToStringList(&nameProp, &names, &count); + if (count < 1) { + XFreeStringList(names); + return; + } + + // is this our client? + if (winTitle == names[0]) { + kdDebug()<< "embedding window with title: "<<winTitle.latin1() << endl; + + QRect r = KWin::windowInfo(win).geometry(); + int h = r.height(); + if ( h == 0 ) h = 1; + wh_ratio = (float) r.width() / (float) h; + kdDebug() << " - - - win is: " << r.width() << ", " << r.height() << endl; + resize( r.width(), r.height() ); + + embed(win); + XReparentWindow(qt_xdisplay(), win, winId(), 0, 0); + + disconnect(SwallowApplet::winModule(), SIGNAL(windowAdded(WId)), + this, SLOT(windowAdded(WId))); + + emit embedded( this ); + } + + XFreeStringList(names); +} + + +void SwallowApp::processExited(KProcess *) +{ + SwallowApplet::removeApplet( this ); // also deletes this app +} + +#include "swallow.moc" diff --git a/kicker/applets/swallow/swallow.h b/kicker/applets/swallow/swallow.h new file mode 100644 index 000000000..8e472f415 --- /dev/null +++ b/kicker/applets/swallow/swallow.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000 Matthias Hölzer-Klüpfel <hoelzer@kde.org> + 2000 Carsten Pfeiffer <pfeiffer@kde.org> + * + * 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 + */ + +#ifndef __swallow_h__ +#define __swallow_h__ + + +#include <qevent.h> +#include <qptrlist.h> +#include <qxembed.h> + +#include <kpanelapplet.h> + +class QBoxLayout; +class KConfig; +class KProcess; +class KWinModule; + +class SwallowApp; + +typedef struct _SwallowCommand { + QString cmdline; + QString title; +} SwallowCommand; + +typedef QPtrList<SwallowCommand> SwallowCommandList; +typedef QPtrListIterator<SwallowCommand> SwallowCommandListIterator; +typedef QPtrList<SwallowApp> SwallowAppList; + +class SwallowApplet : public KPanelApplet +{ + Q_OBJECT + +public: + SwallowApplet( const QString& configFile, QWidget *parent, + const char *name = 0L ); + ~SwallowApplet(); + + // returns 0L if we don't have a SwallowApplet object yet, + // but who cares + static KWinModule * winModule() { return wModule; } + static void removeApplet( SwallowApp * ); + +public: // for KPanelApplet + int widthForHeight( int w ); + int heightForWidth( int h ); + + void windowAdded(WId win); + void processExited(KProcess *proc); + +public slots: + virtual void preferences(); + +private slots: + void embedded( SwallowApp * ); + +private: + void layoutApps(); + SwallowCommandList* readConfig(); + void createApps( SwallowCommandList * ); + + + static SwallowApplet *self; + static SwallowAppList *appList; + static SwallowAppList *embeddedList; + static KWinModule *wModule; + + SwallowCommandList * m_swcList; + QBoxLayout *m_layout; + +}; + + +class SwallowApp : public QXEmbed +{ + Q_OBJECT + +public: + SwallowApp( const SwallowCommand * swc, QWidget* parent = 0, + const char* name = 0); + ~SwallowApp(); + + float sizeRatio() const { return wh_ratio; } + +signals: + void embedded( SwallowApp * ); + +protected slots: + void windowAdded(WId win); + void processExited(KProcess *proc); + +private: + KProcess *process; + QString winTitle; + float wh_ratio; + +}; + +#endif // __swallow_h__ diff --git a/kicker/applets/swallow/swallowapplet.desktop b/kicker/applets/swallow/swallowapplet.desktop new file mode 100644 index 000000000..2ea055461 --- /dev/null +++ b/kicker/applets/swallow/swallowapplet.desktop @@ -0,0 +1,142 @@ +[Desktop Entry] +Type=Plugin +Name=Swallow Applet +Name[af]=Sluk Miniprogram +Name[ar]=بريمج Swallow +Name[az]=Batıq Proqramcıq +Name[be]=Ðплет Ð¿Ñ€Ð°Ð³Ð»Ñ‹Ð½Ð°Ð½Ð½Ñ +Name[bn]=সোয়à§à¦¯à¦¾à¦²à§‹ অà§à¦¯à¦¾à¦ªà¦²à§‡à¦Ÿ +Name[bs]=Applet - gutaÄ +Name[ca]=Applet contenidor +Name[cs]=Pohlcovacà applet +Name[csb]=Aplet do zanurzaniô jinszëch +Name[cy]=Rhaglennig Llyncu +Name[da]=Swallow-panelprogram +Name[de]=Einbettungsprogramm +Name[el]=Ενσωμάτωση μικÏοεφαÏμογής +Name[eo]=Sistemaplikaĵetejo +Name[es]=Miniaplicación contenedora +Name[et]=Põimimise aplett +Name[eu]=Swallow appleta +Name[fa]=برنامک Swallow +Name[fi]=Upotussovelma +Name[fr]=Applet englobante +Name[fy]=Ynslúte applet +Name[gl]=Applet Swallow +Name[he]=יישומון מעגן +Name[hi]=सà¥à¤µà¤¾à¤²à¥‹ à¤à¤ªà¤²à¥‡à¤Ÿ +Name[hr]=Progutaj aplet +Name[hu]=ElnyelÅ‘ kisalkalmazás +Name[is]=Gleypi smáforrit +Name[it]=Applet che ingloba +Name[ja]=Swallow アプレット +Name[ka]=მშთáƒáƒœáƒ—ქáƒáƒ•áƒ˜ áƒáƒžáƒšáƒ”ტი +Name[kk]=Сіңіру апплеті +Name[km]=អាប់ភ្លáŸáž Swallow +Name[lt]=Swallow priemonÄ— +Name[mk]=Ðплет „Голтни“ +Name[mn]=ШигтгÑгч-програм +Name[ms]=Aplet Lelayang +Name[mt]=Applet "Swallow" +Name[nb]=Svelge-panelprogram +Name[nds]=Lüttprogramm för't Inbetten +Name[ne]=सà¥à¤µà¤¾à¤²à¥‹ à¤à¤ªà¥à¤²à¥‡à¤Ÿ +Name[nl]=Inbeddingsapplet +Name[nn]=Svelge-applet +Name[nso]=Applet ya Mometso +Name[pa]=ਸਵਾਲੋਓ à¨à¨ªà¨²à¨¿à¨Ÿ +Name[pl]=Programik do zanurzania innych +Name[pt]='Applet' Swallow +Name[pt_BR]=Mini-aplicativo de integração +Name[ro]=MiniaplicaÈ›ie de înglobare +Name[ru]=Ðплет Ð¿Ð¾Ð³Ð»Ð¾Ñ‰ÐµÐ½Ð¸Ñ +Name[rw]=Kwemera Apuleti +Name[se]=Njeallan-prográmmaÅ¡ +Name[sk]=Pohlcovacà applet +Name[sl]=Vstavek z lastovko +Name[sr]=Ðплет за гутање +Name[sr@Latn]=Aplet za gutanje +Name[sv]=Uppslukande miniprogram +Name[ta]=உளà¯à®µà®¾à®™à¯à®•à¯à®®à¯ சிறà¯à®¨à®¿à®°à®²à¯ +Name[te]=à°¸à±à°µà°¾à°²à±Š à°…à°ªà±à°²à±‡à°Ÿà± +Name[tg]=Барномаи қурт доданӣ +Name[tr]=Batık Programcık +Name[tt]=Yotu Applete +Name[uk]=Ðплет Swallow +Name[ven]=Apulete ya Swallow +Name[vi]=Tiểu ứng dụng Chim nhạn +Name[wa]=Aplikete avaleuse +Name[zh_CN]=Swallow å°ç¨‹åº +Name[zh_TW]=Swallow é¢æ¿å°ç¨‹å¼ +Name[zu]=I-Applet yokugwinya +Comment=The swallow panel applet +Comment[af]=Die sluk paneel miniprogram +Comment[az]=Batıq panel +Comment[be]=Ðплет Ð¿Ñ€Ð°Ð³Ð»Ñ‹Ð½Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¿Ð°Ð½Ñлі +Comment[bn]=সোয়à§à¦¯à¦¾à¦²à§‹ পà§à¦¯à¦¾à¦¨à§‡à¦² অà§à¦¯à¦¾à¦ªà¦²à§‡à¦Ÿ +Comment[bs]=Applet koji "guta" aplikacije u panel +Comment[ca]=L'applet contenidor del plafó +Comment[cs]=Pohlcovacà applet pro panel +Comment[csb]=Aplet dlô panelu jaczi ùsôdzô òbéńdã do zanurzaniô jinszëch +Comment[cy]=Rhaglennig llyncu i'r panel +Comment[da]=Swallow-panelprogrammet +Comment[de]=Leiste zum Einbetten von X-Anwendungen +Comment[el]=ΜικÏοεφαÏμογή του πίνακα που "καταπίνει" +Comment[eo]=La panelaplikaĵeto enhavanta la dokitajn programojn +Comment[es]=La miniaplicación del panel contenedora +Comment[et]=Paneelil töötav põimimise aplett +Comment[eu]=Swallow paneleko appleta +Comment[fa]=برنامک تابلوی Swallow +Comment[fi]=Paneelin upotussovelma +Comment[fr]=L'applet englobante du tableau de bord +Comment[fy]=Applet foar it ynlúte fan X-toepassingen +Comment[gl]=O applet swallow para o painel +Comment[he]=יישומון מעגן עבור הלוח +Comment[hi]=सà¥à¤µà¤¾à¤²à¥‹ फलक à¤à¤ªà¤²à¥‡à¤Ÿ +Comment[hr]=GutaÄ apleta za ploÄu +Comment[hu]=Egy elnyelÅ‘ panel-kisalkalmazás +Comment[id]=Aplet panel swallow +Comment[is]=Gleypispjalds smáforritið +Comment[it]=Applet per inglobare le applicazioni nel pannello +Comment[ja]=swallow パãƒãƒ«ã‚¢ãƒ—レット +Comment[ka]=პáƒáƒœáƒ”ლის მშთáƒáƒœáƒ—ქáƒáƒ•áƒ˜ áƒáƒžáƒšáƒ”ტი +Comment[kk]=Сіңіру панель апплеті +Comment[km]=អាប់ភ្លáŸážâ€‹áž”ន្ទះ swallow +Comment[lt]=Swallow pulto priemonÄ— +Comment[mk]=Ðплетот „Голтни“ од панелот +Comment[mn]=X-програмуудыг холбогч програм +Comment[ms]=Aplet panel lelayang +Comment[mt]=Applet għall-pannell "swallow" +Comment[nb]=Et panelprogram som svelger andre panelprogrammer +Comment[nds]=Paneel för't Inbetten vun X-Programmen +Comment[ne]=सà¥à¤µà¤¾à¤²à¥‹ पà¥à¤¯à¤¾à¤¨à¤² à¤à¤ªà¥à¤²à¥‡à¤Ÿ +Comment[nl]=Applet voor het inbedden van X-toepassingen +Comment[nn]=Svelge-panelappleten +Comment[nso]=Applet ya panel ya mometso +Comment[pa]=ਸਵਾਲੋਓ ਪੈਨਲ à¨à¨ªà¨²à¨¿à¨Ÿ +Comment[pl]=Programik dla panelu tworzÄ…cy przestrzeÅ„ do zanurzania innych +Comment[pt]=A 'applet' do painel swallow +Comment[pt_BR]=Mini-aplicativo de integração para o painel +Comment[ro]=MiniaplicaÈ›ie de panou pentru înglobare altor programe +Comment[ru]=Ðплет панели Ð¿Ð¾Ð³Ð»Ð¾Ñ‰ÐµÐ½Ð¸Ñ +Comment[rw]=Apuleti y'umwanya kumira +Comment[se]=Njeallan-panelprográmmaÅ¡ +Comment[sk]=Pohlcovacà applet pre panel +Comment[sl]=Vstavek lastovke za na pult +Comment[sr]=Ðплет панела за гутање +Comment[sr@Latn]=Aplet panela za gutanje +Comment[sv]=Uppslukande miniprogram för panelen +Comment[ta]=உளà¯à®µà®¾à®™à¯à®•à¯à®®à¯ பலக சிறà¯à®¨à®¿à®°à®²à¯ +Comment[tg]=Барномаи қурт додани Ñафҳа +Comment[th]=à¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸• swallow +Comment[tr]=Batık panel +Comment[tt]=Yotuçı taqta applete +Comment[uk]=Ðплет панелі swallow +Comment[vi]=Tiểu ứng dụng chạy bảng Ä‘iá»u khiển chim nhạn +Comment[wa]=L' aplikete avaleuse do scriftôr +Comment[xh]=I window eneenkcukacha ye swallow applet +Comment[zh_CN]=Swallow é¢æ¿å°ç¨‹åº +Comment[zh_TW]=swallow é¢æ¿å°ç¨‹å¼ +Comment[zu]=I-applet lewindi lemininingwane lokugwinya +X-KDE-Library=swallow_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/systemtray/Makefile.am b/kicker/applets/systemtray/Makefile.am new file mode 100644 index 000000000..849795a9e --- /dev/null +++ b/kicker/applets/systemtray/Makefile.am @@ -0,0 +1,24 @@ + +INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = systemtray_panelapplet.la + +systemtray_panelapplet_la_SOURCES = systemtrayapplet.cpp systemtrayapplet.skel + +systemtray_panelapplet_la_METASOURCES = AUTO +noinst_HEADERS = systemtrayapplet.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = systemtrayapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +systemtray_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +systemtray_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KDEUI) $(LIB_KIO) + + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/ksystemtrayapplet.pot + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/ksystemtrayapplet ksystemtrayapplet *.h -lqt -lkdecore -lkdeui -lkfile diff --git a/kicker/applets/systemtray/systemtrayapplet.cpp b/kicker/applets/systemtray/systemtrayapplet.cpp new file mode 100644 index 000000000..8ae502fb4 --- /dev/null +++ b/kicker/applets/systemtray/systemtrayapplet.cpp @@ -0,0 +1,1013 @@ +/***************************************************************** + +Copyright (c) 2000-2001 Matthias Ettrich <ettrich@kde.org> + 2000-2001 Matthias Elter <elter@kde.org> + 2001 Carsten Pfeiffer <pfeiffer@kde.org> + 2001 Martijn Klingens <mklingens@yahoo.com> + 2004 Aaron J. Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qlayout.h> +#include <qpopupmenu.h> +#include <qtimer.h> +#include <qpixmap.h> +#include <qevent.h> +#include <qstyle.h> +#include <qpainter.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <krun.h> +#include <kwinmodule.h> +#include <kdialogbase.h> +#include <kactionselector.h> +#include <kiconloader.h> +#include <kwin.h> + +#include "simplebutton.h" + +#include "systemtrayapplet.h" +#include "systemtrayapplet.moc" + +#include <X11/Xlib.h> + +#define ICON_MARGIN 1 + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("ksystemtrayapplet"); + return new SystemTrayApplet(configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, parent, "ksystemtrayapplet"); + } +} + +SystemTrayApplet::SystemTrayApplet(const QString& configFile, Type type, int actions, + QWidget *parent, const char *name) + : KPanelApplet(configFile, type, actions, parent, name), + m_showFrame(false), + m_showHidden(false), + m_expandButton(0), + m_settingsDialog(0), + m_iconSelector(0), + m_autoRetractTimer(0), + m_autoRetract(false), + m_iconSize(24), + m_layout(0) +{ + loadSettings(); + + setBackgroundOrigin(AncestorOrigin); + + kwin_module = new KWinModule(this); + + // kApplication notifies us of settings changes. added to support + // disabling of frame effect on mouse hover + kapp->dcopClient()->setNotifications(true); + connectDCOPSignal("kicker", "kicker", "configurationChanged()", "loadSettings()", false); + + QTimer::singleShot(0, this, SLOT(initialize())); +} + +void SystemTrayApplet::initialize() +{ + // register existing tray windows + const QValueList<WId> systemTrayWindows = kwin_module->systemTrayWindows(); + bool existing = false; + for (QValueList<WId>::ConstIterator it = systemTrayWindows.begin(); + it != systemTrayWindows.end(); ++it ) + { + embedWindow(*it, true); + existing = true; + } + + showExpandButton(!m_hiddenWins.isEmpty()); + + if (existing) + { + updateVisibleWins(); + layoutTray(); + } + + // the KWinModule notifies us when tray windows are added or removed + connect( kwin_module, SIGNAL( systemTrayWindowAdded(WId) ), + this, SLOT( systemTrayWindowAdded(WId) ) ); + connect( kwin_module, SIGNAL( systemTrayWindowRemoved(WId) ), + this, SLOT( updateTrayWindows() ) ); + + QCString screenstr; + screenstr.setNum(qt_xscreen()); + QCString trayatom = "_NET_SYSTEM_TRAY_S" + screenstr; + + Display *display = qt_xdisplay(); + + net_system_tray_selection = XInternAtom(display, trayatom, false); + net_system_tray_opcode = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", false); + + // Acquire system tray + XSetSelectionOwner(display, + net_system_tray_selection, + winId(), + CurrentTime); + + WId root = qt_xrootwin(); + + if (XGetSelectionOwner (display, net_system_tray_selection) == winId()) + { + XClientMessageEvent xev; + + xev.type = ClientMessage; + xev.window = root; + + xev.message_type = XInternAtom (display, "MANAGER", False); + xev.format = 32; + xev.data.l[0] = CurrentTime; + xev.data.l[1] = net_system_tray_selection; + xev.data.l[2] = winId(); + xev.data.l[3] = 0; /* manager specific data */ + xev.data.l[4] = 0; /* manager specific data */ + + XSendEvent (display, root, False, StructureNotifyMask, (XEvent *)&xev); + } + + setBackground(); +} + +SystemTrayApplet::~SystemTrayApplet() +{ + for (TrayEmbedList::const_iterator it = m_hiddenWins.constBegin(); + it != m_hiddenWins.constEnd(); + ++it) + { + delete *it; + } + + for (TrayEmbedList::const_iterator it = m_shownWins.constBegin(); + it != m_shownWins.constEnd(); + ++it) + { + delete *it; + } + + KGlobal::locale()->removeCatalogue("ksystemtrayapplet"); +} + +bool SystemTrayApplet::x11Event( XEvent *e ) +{ +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + if ( e->type == ClientMessage ) { + if ( e->xclient.message_type == net_system_tray_opcode && + e->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if( isWinManaged( (WId)e->xclient.data.l[2] ) ) // we already manage it + return true; + embedWindow( e->xclient.data.l[2], false ); + layoutTray(); + return true; + } + } + return KPanelApplet::x11Event( e ) ; +} + +void SystemTrayApplet::preferences() +{ + if (m_settingsDialog) + { + m_settingsDialog->show(); + m_settingsDialog->raise(); + return; + } + + m_settingsDialog = new KDialogBase(0, "systrayconfig", + false, i18n("Configure System Tray"), + KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel, + KDialogBase::Ok, true); + m_settingsDialog->resize(450, 400); + connect(m_settingsDialog, SIGNAL(applyClicked()), this, SLOT(applySettings())); + connect(m_settingsDialog, SIGNAL(okClicked()), this, SLOT(applySettings())); + connect(m_settingsDialog, SIGNAL(finished()), this, SLOT(settingsDialogFinished())); + + m_iconSelector = new KActionSelector(m_settingsDialog); + m_iconSelector->setAvailableLabel(i18n("Visible icons:")); + m_iconSelector->setSelectedLabel(i18n("Hidden icons:")); + m_iconSelector->setShowUpDownButtons(false); + m_settingsDialog->setMainWidget(m_iconSelector); + + QListBox *shownListBox = m_iconSelector->availableListBox(); + QListBox *hiddenListBox = m_iconSelector->selectedListBox(); + + TrayEmbedList::const_iterator it = m_shownWins.begin(); + TrayEmbedList::const_iterator itEnd = m_shownWins.end(); + for (; it != itEnd; ++it) + { + QString name = KWin::windowInfo((*it)->embeddedWinId()).name(); + if(!shownListBox->findItem(name, Qt::ExactMatch | Qt::CaseSensitive)) + { + shownListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name); + } + } + + it = m_hiddenWins.begin(); + itEnd = m_hiddenWins.end(); + for (; it != itEnd; ++it) + { + QString name = KWin::windowInfo((*it)->embeddedWinId()).name(); + if(!hiddenListBox->findItem(name, Qt::ExactMatch | Qt::CaseSensitive)) + { + hiddenListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name); + } + } + + m_settingsDialog->show(); +} + +void SystemTrayApplet::settingsDialogFinished() +{ + m_settingsDialog->delayedDestruct(); + m_settingsDialog = 0; + m_iconSelector = 0; +} + +void SystemTrayApplet::applySettings() +{ + if (!m_iconSelector) + { + return; + } + + KConfig *conf = config(); + conf->setGroup("HiddenTrayIcons"); + QString name; + + // use the following snippet of code someday to implement ordering + // of icons + /* + m_visibleIconList.clear(); + QListBoxItem* item = m_iconSelector->availableListBox()->firstItem(); + for (; item; item = item->next()) + { + m_visibleIconList.append(item->text()); + } + conf->writeEntry("Visible", m_visibleIconList); + selection.clear();*/ + + m_hiddenIconList.clear(); + QListBoxItem* item = m_iconSelector->selectedListBox()->firstItem(); + for (; item; item = item->next()) + { + m_hiddenIconList.append(item->text()); + } + conf->writeEntry("Hidden", m_hiddenIconList); + conf->sync(); + + TrayEmbedList::iterator it = m_shownWins.begin(); + while (it != m_shownWins.end()) + { + if (shouldHide((*it)->embeddedWinId())) + { + m_hiddenWins.append(*it); + it = m_shownWins.erase(it); + } + else + { + ++it; + } + } + + it = m_hiddenWins.begin(); + while (it != m_hiddenWins.end()) + { + if (!shouldHide((*it)->embeddedWinId())) + { + m_shownWins.append(*it); + it = m_hiddenWins.erase(it); + } + else + { + ++it; + } + } + + showExpandButton(!m_hiddenWins.isEmpty()); + + updateVisibleWins(); + layoutTray(); +} + +void SystemTrayApplet::checkAutoRetract() +{ + if (!m_autoRetractTimer) + { + return; + } + + if (!geometry().contains(mapFromGlobal(QCursor::pos()))) + { + m_autoRetractTimer->stop(); + if (m_autoRetract) + { + m_autoRetract = false; + + if (m_showHidden) + { + retract(); + } + } + else + { + m_autoRetract = true; + m_autoRetractTimer->start(2000, true); + } + + } + else + { + m_autoRetract = false; + m_autoRetractTimer->start(250, true); + } +} + +void SystemTrayApplet::showExpandButton(bool show) +{ + if (show) + { + if (!m_expandButton) + { + m_expandButton = new SimpleArrowButton(this); + m_expandButton->installEventFilter(this); + refreshExpandButton(); + + if (orientation() == Vertical) + { + m_expandButton->setFixedSize(width() - 4, + m_expandButton->sizeHint() + .height()); + } + else + { + m_expandButton->setFixedSize(m_expandButton->sizeHint() + .width(), + height() - 4); + } + connect(m_expandButton, SIGNAL(clicked()), + this, SLOT(toggleExpanded())); + + m_autoRetractTimer = new QTimer(this); + connect(m_autoRetractTimer, SIGNAL(timeout()), + this, SLOT(checkAutoRetract())); + } + else + { + refreshExpandButton(); + } + + m_expandButton->show(); + } + else if (m_expandButton) + { + m_expandButton->hide(); + } +} + +void SystemTrayApplet::orientationChange( Orientation /*orientation*/ ) +{ + refreshExpandButton(); +} + +void SystemTrayApplet::loadSettings() +{ + // set our defaults + setFrameStyle(NoFrame); + m_showFrame = false; + + KConfig *conf = config(); + conf->setGroup("General"); + + if (conf->readBoolEntry("ShowPanelFrame", false)) + { + setFrameStyle(Panel | Sunken); + } + + conf->setGroup("HiddenTrayIcons"); + m_hiddenIconList = conf->readListEntry("Hidden"); + + //Note This setting comes from kdeglobal. + conf->setGroup("System Tray"); + m_iconSize = conf->readNumEntry("systrayIconWidth", 22); +} + +void SystemTrayApplet::systemTrayWindowAdded( WId w ) +{ + if (isWinManaged(w)) + { + // we already manage it + return; + } + + embedWindow(w, true); + updateVisibleWins(); + layoutTray(); + + if (m_showFrame && frameStyle() == NoFrame) + { + setFrameStyle(Panel|Sunken); + } +} + +void SystemTrayApplet::embedWindow( WId w, bool kde_tray ) +{ + TrayEmbed* emb = new TrayEmbed(kde_tray, this); + emb->setAutoDelete(false); + + if (kde_tray) + { + static Atom hack_atom = XInternAtom( qt_xdisplay(), "_KDE_SYSTEM_TRAY_EMBEDDING", False ); + XChangeProperty( qt_xdisplay(), w, hack_atom, hack_atom, 32, PropModeReplace, NULL, 0 ); + emb->embed(w); + XDeleteProperty( qt_xdisplay(), w, hack_atom ); + } + else + { + emb->embed(w); + } + + if (emb->embeddedWinId() == 0) // error embedding + { + delete emb; + return; + } + + connect(emb, SIGNAL(embeddedWindowDestroyed()), SLOT(updateTrayWindows())); + emb->getIconSize(m_iconSize); + + if (shouldHide(w)) + { + emb->hide(); + m_hiddenWins.append(emb); + showExpandButton(true); + } + else + { + //emb->hide(); + emb->setBackground(); + emb->show(); + m_shownWins.append(emb); + } +} + +bool SystemTrayApplet::isWinManaged(WId w) +{ + TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + { + if ((*emb)->embeddedWinId() == w) // we already manage it + { + return true; + } + } + + lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + { + if ((*emb)->embeddedWinId() == w) // we already manage it + { + return true; + } + } + + return false; +} + +bool SystemTrayApplet::shouldHide(WId w) +{ + return m_hiddenIconList.find(KWin::windowInfo(w).name()) != m_hiddenIconList.end(); +} + +void SystemTrayApplet::updateVisibleWins() +{ + TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); + TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); + + if (m_showHidden) + { + for (; emb != lastEmb; ++emb) + { + //(*emb)->hide(); + (*emb)->setBackground(); + (*emb)->show(); + } + } + else + { + for (; emb != lastEmb; ++emb) + { + (*emb)->hide(); + } + } +} + +void SystemTrayApplet::toggleExpanded() +{ + if (m_showHidden) + { + retract(); + } + else + { + expand(); + } +} + +void SystemTrayApplet::refreshExpandButton() +{ + if (!m_expandButton) + { + return; + } + + Qt::ArrowType a; + + if (orientation() == Vertical) + a = m_showHidden ? Qt::DownArrow : Qt::UpArrow; + else + a = (m_showHidden ^ kapp->reverseLayout()) ? Qt::RightArrow : Qt::LeftArrow; + + m_expandButton->setArrowType(a); +} + +void SystemTrayApplet::expand() +{ + m_showHidden = true; + refreshExpandButton(); + + updateVisibleWins(); + layoutTray(); + + if (m_autoRetractTimer) + { + m_autoRetractTimer->start(250, true); + } +} + +void SystemTrayApplet::retract() +{ + if (m_autoRetractTimer) + { + m_autoRetractTimer->stop(); + } + + m_showHidden = false; + refreshExpandButton(); + + updateVisibleWins(); + layoutTray(); +} + +void SystemTrayApplet::updateTrayWindows() +{ + TrayEmbedList::iterator emb = m_shownWins.begin(); + while (emb != m_shownWins.end()) + { + WId wid = (*emb)->embeddedWinId(); + if ((wid == 0) || + ((*emb)->kdeTray() && + !kwin_module->systemTrayWindows().contains(wid))) + { + (*emb)->deleteLater(); + emb = m_shownWins.erase(emb); + } + else + { + ++emb; + } + } + + emb = m_hiddenWins.begin(); + while (emb != m_hiddenWins.end()) + { + WId wid = (*emb)->embeddedWinId(); + if ((wid == 0) || + ((*emb)->kdeTray() && + !kwin_module->systemTrayWindows().contains(wid))) + { + (*emb)->deleteLater(); + emb = m_hiddenWins.erase(emb); + } + else + { + ++emb; + } + } + + showExpandButton(!m_hiddenWins.isEmpty()); + updateVisibleWins(); + layoutTray(); +} + +int SystemTrayApplet::maxIconWidth() const +{ + int largest = m_iconSize; + + TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + { + if (*emb == 0) + { + continue; + } + + int width = (*emb)->width(); + if (width > largest) + { + largest = width; + } + } + + if (m_showHidden) + { + lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + { + int width = (*emb)->width(); + if (width > largest) + { + largest = width; + } + } + } + + return largest; +} + +int SystemTrayApplet::maxIconHeight() const +{ + int largest = m_iconSize; + + TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != m_shownWins.end(); ++emb) + { + if (*emb == 0) + { + continue; + } + + int height = (*emb)->height(); + if (height > largest) + { + largest = height; + } + } + + if (m_showHidden) + { + lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != m_hiddenWins.end(); ++emb) + { + if (*emb == 0) + { + continue; + } + + int height = (*emb)->height(); + if (height > largest) + { + largest = height; + } + } + } + + return largest; +} + +bool SystemTrayApplet::eventFilter(QObject* watched, QEvent* e) +{ + if (watched == m_expandButton) + { + QPoint p; + if (e->type() == QEvent::ContextMenu) + { + p = static_cast<QContextMenuEvent*>(e)->globalPos(); + } + else if (e->type() == QEvent::MouseButtonPress) + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if (me->button() == Qt::RightButton) + { + p = me->globalPos(); + } + } + + if (!p.isNull()) + { + QPopupMenu* contextMenu = new QPopupMenu(this); + contextMenu->insertItem(SmallIcon("configure"), i18n("Configure System Tray..."), + this, SLOT(configure())); + + contextMenu->exec(static_cast<QContextMenuEvent*>(e)->globalPos()); + + delete contextMenu; + return true; + } + } + + return false; +} + +int SystemTrayApplet::widthForHeight(int h) const +{ + if (orientation() == Qt::Vertical) + { + return width(); + } + + int currentHeight = height(); + if (currentHeight != h) + { + SystemTrayApplet* me = const_cast<SystemTrayApplet*>(this); + me->setMinimumSize(0, 0); + me->setMaximumSize(32767, 32767); + me->setFixedHeight(h); + } + + return sizeHint().width(); +} + +int SystemTrayApplet::heightForWidth(int w) const +{ + if (orientation() == Qt::Horizontal) + { + return height(); + } + + int currentWidth = width(); + if (currentWidth != w) + { + SystemTrayApplet* me = const_cast<SystemTrayApplet*>(this); + me->setMinimumSize(0, 0); + me->setMaximumSize(32767, 32767); + me->setFixedWidth(w); + } + + return sizeHint().height(); +} + +void SystemTrayApplet::moveEvent( QMoveEvent* ) +{ + setBackground(); +} + + +void SystemTrayApplet::resizeEvent( QResizeEvent* ) +{ + layoutTray(); + // we need to give ourselves a chance to adjust our size before calling this + QTimer::singleShot(0, this, SIGNAL(updateLayout())); +} + +void SystemTrayApplet::layoutTray() +{ + setUpdatesEnabled(false); + + int iconCount = m_shownWins.count(); + + if (m_showHidden) + { + iconCount += m_hiddenWins.count(); + } + + /* heightWidth = height or width in pixels (depends on orientation()) + * nbrOfLines = number of rows or cols (depends on orientation()) + * line = what line to draw an icon in */ + int i = 0, line, nbrOfLines, heightWidth; + bool showExpandButton = m_expandButton && m_expandButton->isVisibleTo(this); + delete m_layout; + m_layout = new QGridLayout(this, 1, 1, ICON_MARGIN, ICON_MARGIN); + + if (m_expandButton) + { + if (orientation() == Vertical) + { + m_expandButton->setFixedSize(width() - 4, m_expandButton->sizeHint().height()); + } + else + { + m_expandButton->setFixedSize(m_expandButton->sizeHint().width(), height() - 4); + } + } + + // col = column or row, depends on orientation(), + // the opposite direction of line + int col = 0; + + // + // The margin and spacing specified in the layout implies that: + // [-- ICON_MARGIN pixels --] [-- first icon --] [-- ICON_MARGIN pixels --] ... [-- ICON_MARGIN pixels --] [-- last icon --] [-- ICON_MARGIN pixels --] + // + // So, if we say that iconWidth is the icon width plus the ICON_MARGIN pixels spacing, then the available width for the icons + // is the widget width minus ICON_MARGIN pixels margin. Forgetting these ICON_MARGIN pixels broke the layout algorithm in KDE <= 3.5.9. + // + // This fix makes the workarounds in the heightForWidth() and widthForHeight() methods unneeded. + // + + if (orientation() == Vertical) + { + int iconWidth = maxIconWidth() + ICON_MARGIN; // +2 for the margins that implied by the layout + heightWidth = width() - ICON_MARGIN; + // to avoid nbrOfLines=0 we ensure heightWidth >= iconWidth! + heightWidth = heightWidth < iconWidth ? iconWidth : heightWidth; + nbrOfLines = heightWidth / iconWidth; + + if (showExpandButton) + { + m_layout->addMultiCellWidget(m_expandButton, + 0, 0, + 0, nbrOfLines - 1, + Qt::AlignHCenter | Qt::AlignVCenter); + col = 1; + } + + if (m_showHidden) + { + TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); + emb != lastEmb; ++emb) + { + line = i % nbrOfLines; + //(*emb)->hide(); + (*emb)->show(); + m_layout->addWidget(*emb, col, line, + Qt::AlignHCenter | Qt::AlignVCenter); + + if ((line + 1) == nbrOfLines) + { + ++col; + } + + ++i; + } + } + + TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); + emb != lastEmb; ++emb) + { + line = i % nbrOfLines; + //(*emb)->hide(); + (*emb)->show(); + m_layout->addWidget(*emb, col, line, + Qt::AlignHCenter | Qt::AlignVCenter); + + if ((line + 1) == nbrOfLines) + { + ++col; + } + + ++i; + } + } + else // horizontal + { + int iconHeight = maxIconHeight() + ICON_MARGIN; // +2 for the margins that implied by the layout + heightWidth = height() - ICON_MARGIN; + heightWidth = heightWidth < iconHeight ? iconHeight : heightWidth; // to avoid nbrOfLines=0 + nbrOfLines = heightWidth / iconHeight; + + if (showExpandButton) + { + m_layout->addMultiCellWidget(m_expandButton, + 0, nbrOfLines - 1, + 0, 0, + Qt::AlignHCenter | Qt::AlignVCenter); + col = 1; + } + + if (m_showHidden) + { + TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + { + line = i % nbrOfLines; + //(*emb)->hide(); + (*emb)->show(); + m_layout->addWidget(*emb, line, col, + Qt::AlignHCenter | Qt::AlignVCenter); + + if ((line + 1) == nbrOfLines) + { + ++col; + } + + ++i; + } + } + + TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); + emb != lastEmb; ++emb) + { + line = i % nbrOfLines; + //(*emb)->hide(); + (*emb)->show(); + m_layout->addWidget(*emb, line, col, + Qt::AlignHCenter | Qt::AlignVCenter); + + if ((line + 1) == nbrOfLines) + { + ++col; + } + + ++i; + } + } + + setUpdatesEnabled(true); + updateGeometry(); + setBackground(); +} + +void SystemTrayApplet::paletteChange(const QPalette & /* oldPalette */) +{ + setBackground(); +} + +void SystemTrayApplet::setBackground() +{ + TrayEmbedList::const_iterator lastEmb; + + lastEmb = m_shownWins.end(); + for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + (*emb)->setBackground(); + + lastEmb = m_hiddenWins.end(); + for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + (*emb)->setBackground(); +} + + +TrayEmbed::TrayEmbed( bool kdeTray, QWidget* parent ) + : QXEmbed( parent ), kde_tray( kdeTray ) +{ + hide(); +} + +void TrayEmbed::getIconSize(int defaultIconSize) +{ + QSize minSize = minimumSizeHint(); + + int width = minSize.width(); + int height = minSize.height(); + + if (width < 1 || width > defaultIconSize) + width = defaultIconSize; + if (height < 1 || height > defaultIconSize) + height = defaultIconSize; + + setFixedSize(width, height); + setBackground(); +} + +void TrayEmbed::setBackground() +{ + const QPixmap *pbg = parentWidget()->backgroundPixmap(); + + if (pbg) + { + QPixmap bg(width(), height()); + bg.fill(parentWidget(), pos()); + setPaletteBackgroundPixmap(bg); + setBackgroundOrigin(WidgetOrigin); + } + else + unsetPalette(); + + if (!isHidden()) + { + XClearArea(x11Display(), embeddedWinId(), 0, 0, 0, 0, True); + } +} + diff --git a/kicker/applets/systemtray/systemtrayapplet.desktop b/kicker/applets/systemtray/systemtrayapplet.desktop new file mode 100644 index 000000000..ab737d83c --- /dev/null +++ b/kicker/applets/systemtray/systemtrayapplet.desktop @@ -0,0 +1,158 @@ +[Desktop Entry] +Type=Plugin +Name=System Tray +Name[af]=Stelsel Laai +Name[ar]=لوØØ© النظام +Name[az]=Sistem RÉ™fi +Name[be]=СіÑÑ‚Ñмны латок +Name[bg]=СиÑтемен панел +Name[bn]=সিসà§à¦Ÿà§‡à¦® টà§à¦°à§‡ +Name[br]=Barlenn ar reizhiad +Name[ca]=Safata del sistema +Name[cs]=Systémová Äást panelu +Name[csb]=Systemòwi zabiérnik +Name[cy]=Bar Tasgau +Name[da]=Statusfelt +Name[de]=Systemabschnitt der Kontrollleiste +Name[el]=Πλαίσιο συστήματος +Name[eo]=Sistempleto +Name[es]=Bandeja del sistema +Name[et]=Süsteemne dokk +Name[eu]=Sistemaren azpila +Name[fa]=سینی سیستم +Name[fi]=Ilmoitusalue +Name[fr]=Boîte à miniatures +Name[fy]=Systeemfak +Name[ga]=Tráidire an Chórais +Name[gl]=Bandexa do Sistema +Name[he]=מגש מערכת +Name[hi]=तंतà¥à¤° तशà¥à¤¤à¤°à¥€ +Name[hr]=Sistemska traka +Name[hu]=Rendszertálca +Name[id]=Tray Sistem +Name[is]=Smáforritabakki +Name[it]=Vassoio di sistema +Name[ja]=システムトレイ +Name[ka]=სისტემური პáƒáƒœáƒ”ლი +Name[kk]=Жүйелік Ñөре +Name[km]=ážáž¶ážŸâ€‹áž”្រពáŸáž“្ធ +Name[ko]=시스템 íŠ¸ë ˆì´ +Name[lo]=ຖາດຂàºàº‡àº¥àº°àºšàº»àºš +Name[lt]=Sistemos dÄ—klas +Name[lv]=SistÄ“mas Tekne +Name[mk]=СиÑтемÑка лента +Name[mn]=Удирдах Ñамбарын ÑиÑтемийн Ñ…ÑÑÑг +Name[ms]=Dulang Sistem +Name[mt]=Tray tas-Sistema +Name[nb]=Systemkurv +Name[nds]=Systeemafsnitt vun't Paneel +Name[ne]=पà¥à¤°à¤£à¤¾à¤²à¥€ टà¥à¤°à¥‡ +Name[nl]=Systeemvak +Name[nn]=Systemtrau +Name[nso]=Tray ya System +Name[oc]=Safata dèu sistemo +Name[pa]=ਸਿਸਟਮ ਟਰੇ +Name[pl]=Tacka systemowa +Name[pt]=Bandeja do Painel +Name[pt_BR]=Ãcones do sistema +Name[ro]=Tavă de sistem +Name[ru]=СиÑтемный лоток +Name[rw]=Igitwara cya Sisitemu +Name[se]=Vuogádatgárcu +Name[sk]=Systémová liÅ¡ta +Name[sl]=Sistemska vrstica +Name[sr]=СиÑтемÑка каÑета +Name[sr@Latn]=Sistemska kaseta +Name[sv]=Systembricka +Name[ta]=சாதன தடà¯à®Ÿà¯ +Name[te]=à°µà±à°¯à°µà°¸à±à°¥ à°Ÿà±à°°à±† +Name[tg]=Сафҳаи идоракунии ÑиÑтема +Name[th]=ถาดขà¸à¸‡à¸£à¸°à¸šà¸š +Name[tr]=Sistem Çekmecesi +Name[tt]=Sistem Tiräse +Name[uk]=СиÑтемний лоток +Name[ven]=Thirei ya sistemu +Name[vi]=Khay Hệ thống +Name[wa]=Boesse Ã¥s imÃ¥djetes sistinme +Name[xh]=Itreyi Yendlela yokusebenza +Name[zh_CN]=系统托盘 +Name[zh_TW]=系統匣 +Name[zu]=Itreyi lesistimu + +Comment=The system tray panel applet +Comment[af]=Die stelsel laai paneel miniprogram +Comment[ar]=بريمج لوØØ© النظام +Comment[az]=BildiriÅŸ sahÉ™si panel appleti +Comment[be]=Ðплет ÑÑ–ÑÑ‚Ñмнага латка +Comment[bg]=СиÑтемен аплет за региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð½Ð° програми и поддържане на иконите им +Comment[bn]=সিসà§à¦Ÿà§‡à¦® টà§à¦°à§‡ পà§à¦¯à¦¾à¦¨à§‡à¦² অà§à¦¯à¦¾à¦ªà¦²à§‡à¦Ÿ +Comment[br]=Arloadig banell barlenn ar reizhiad +Comment[bs]=Applet za system tray +Comment[ca]=L'applet per al plafó de la safata del sistema +Comment[cs]=Systémová Äást panelu urÄená pro applety +Comment[csb]=Aplet systemòwégò zabiérnika dlô panelu +Comment[cy]=Rhaglennig bar tasgau i'r panel +Comment[da]=Statusfelt-panelprogrammet +Comment[de]=Systemabschnitt der Kontrollleiste +Comment[el]=ΜικÏοεφαÏμογή του πίνακα για το πλαίσιο συστήματος +Comment[eo]=La sistempleta panelaplikaĵeto +Comment[es]=La bandeja del sistema (miniaplicación del panel) +Comment[et]=Paneelil töötav süsteemse doki aplett +Comment[eu]=Sistemaren azpila (paneleko appleta) +Comment[fa]=برنامک تابلوی سینی سیستم +Comment[fi]=Paneelin ilmoitusalue +Comment[fr]=L'applet de boîte à miniatures du tableau de bord +Comment[fy]=It systeemfak panielapplet +Comment[gl]=A applet do painel coa bandexa do sistema +Comment[he]=יישומון מגש המערכת ללוח +Comment[hi]=तंतà¥à¤° तशà¥à¤¤à¤°à¥€ फलक à¤à¤ªà¤²à¥‡à¤Ÿ +Comment[hr]=Aplet ploÄe za sistemsku traku +Comment[hu]=A rendszertálca alkalmazás +Comment[id]=Applet panel tray sistem +Comment[is]=Ãforrit sem birtir lista yfir forrit sem eru à gangi +Comment[it]=Applet del pannello per il vassoio di sistema +Comment[ja]=システムトレイパãƒãƒ«ã‚¢ãƒ—レット +Comment[ka]=სისტემური პáƒáƒœáƒ”ლის áƒáƒžáƒšáƒ”ტი +Comment[kk]=Жүйелік Ñөре панель апплеті +Comment[km]=អាប់ភ្លáŸážâ€‹áž”ន្ទះ​ážáž¶ážŸâ€‹áž”្រពáŸáž“្ធ +Comment[lo]=à»àºàºšà»àºžàº±àº”ຖາດຂàºàº‡àº¥àº°àºšàº»àºšàºžàº²à»€àº™àº¥ +Comment[lt]=Sistemos dÄ—klo pulto priemonÄ— +Comment[lv]=SistÄ“mas teknes paneļa aplets +Comment[mk]=ПанелÑки аплет од ÑиÑтемÑката лента +Comment[mn]=Удирдах Ñамбарын ÑиÑтемийн Ñ…ÑÑÑг +Comment[ms]=Aplet panel dulang sistem +Comment[mt]=Applet għat-tray tas-sistema +Comment[nb]=Panelprogram for systemkurven +Comment[nds]=Lüttprogramm för den Systeemafsnitt vun't Paneel +Comment[ne]=पà¥à¤°à¤£à¤¾à¤²à¥€ टà¥à¤°à¥‡ पà¥à¤¯à¤¾à¤¨à¤² à¤à¤ªà¥à¤²à¥‡à¤Ÿ +Comment[nl]=De systeemvak paneelapplet +Comment[nn]=Systemtrau-panelapplet +Comment[nso]=Applet ya panel ya tray ya system +Comment[oc]=L'aplet de plafon de la safata dèu sistemo +Comment[pa]=ਸਿਸਟਮ ਟਰੇ ਪੈਨਲ à¨à¨ªà¨²à¨¿à¨Ÿ +Comment[pl]=Programik tacki systemowej dla panelu +Comment[pt]=Uma 'applet' com a bandeja do painel +Comment[pt_BR]=Mini-aplicativo de Ãcones do sistema +Comment[ro]=MiniaplicaÈ›ia tavă de sistem pentru panou +Comment[ru]=Ðплет панели ÑиÑтемного лотка +Comment[rw]=Apuleti y'umwanya w'igitwara sisitemu +Comment[se]=Vuogádatgárcu-panelprográmmaÅ¡ +Comment[sk]=Applet Systémová liÅ¡ta +Comment[sl]=Vstavek za sistemsko vrstico v pultu +Comment[sr]=Ðплет ÑиÑтемÑке каÑете за панел +Comment[sr@Latn]=Aplet sistemske kasete za panel +Comment[sv]=Panelminiprogram för systembricka +Comment[ta]=சாதன தடà¯à®Ÿà¯ பலக சிறà¯à®¨à®¿à®°à®²à¯ +Comment[tg]=Барномаи Ñафҳаи идоракунии ÑиÑтемаи Ñафҳа +Comment[th]=à¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸•à¸–าดขà¸à¸‡à¸£à¸°à¸šà¸šà¸šà¸™à¸žà¸²à¹€à¸™à¸¥ +Comment[tr]=Sistem çekmece paneli +Comment[uk]=Ðплет ÑиÑтемного лотку панелі +Comment[vi]=Tiểu ứng dụng có bảng Ä‘iá»u khiển chứa khay hệ thống +Comment[wa]=L' aplikete boesse Ã¥s imÃ¥djetes sistinme do scriftôr +Comment[xh]=I applet yeqela lenjongo ethile yendlela yetreyi yokusebenza +Comment[zh_CN]=系统托盘å°ç¨‹åº +Comment[zh_TW]=系統匣 (system tray) é¢æ¿å°ç¨‹å¼ +Comment[zu]=I-applet yewindi lemininingwane yetreyi lesistimu +Icon=systemtray +X-KDE-Library=systemtray_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker/applets/systemtray/systemtrayapplet.h b/kicker/applets/systemtray/systemtrayapplet.h new file mode 100644 index 000000000..7afc18bf9 --- /dev/null +++ b/kicker/applets/systemtray/systemtrayapplet.h @@ -0,0 +1,126 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __systemtrayapplet_h__ +#define __systemtrayapplet_h__ + +#include <qvaluevector.h> +#include <qstringlist.h> +#include <qevent.h> +#include <qxembed.h> + +#include <dcopobject.h> +#include <kapplication.h> +#include <kpanelapplet.h> + +#include "simplebutton.h" + +class QGridLayout; +class QTimer; +class KWinModule; +class TrayEmbed; +class KDialogBase; +class KActionSelector; + +class SystemTrayApplet : public KPanelApplet, public DCOPObject +{ + Q_OBJECT + K_DCOP + typedef QValueVector<TrayEmbed*> TrayEmbedList; + +public: + + SystemTrayApplet(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~SystemTrayApplet(); + + int widthForHeight(int h) const; + int heightForWidth(int w) const; + int maxIconWidth() const; + int maxIconHeight() const; + + bool eventFilter(QObject* watched, QEvent* e); + +k_dcop: + void loadSettings(); + +protected: + void resizeEvent(QResizeEvent*); + void moveEvent(QMoveEvent *); + bool x11Event( XEvent *e ); + void preferences(); + void orientationChange( Orientation ); + +protected slots: + void initialize(); + void systemTrayWindowAdded( WId ); + void updateTrayWindows(); + void layoutTray(); + void paletteChange(const QPalette & /* oldPalette */); + void toggleExpanded(); + void settingsDialogFinished(); + void applySettings(); + void checkAutoRetract(); + void configure() { preferences(); } + void setBackground(); + +private: + void embedWindow( WId w, bool kde_tray ); + bool isWinManaged( WId w); + bool shouldHide( WId w); + void updateVisibleWins(); + void expand(); + void retract(); + void showExpandButton(bool show); + void refreshExpandButton(); + + TrayEmbedList m_shownWins; + TrayEmbedList m_hiddenWins; + QStringList m_hiddenIconList; + KWinModule *kwin_module; + Atom net_system_tray_selection; + Atom net_system_tray_opcode; + bool m_showFrame; + bool m_showHidden; + SimpleArrowButton *m_expandButton; + KDialogBase* m_settingsDialog; + KActionSelector* m_iconSelector; + QTimer* m_autoRetractTimer; + bool m_autoRetract; + int m_iconSize; + QGridLayout* m_layout; +}; + +class TrayEmbed : public QXEmbed +{ + Q_OBJECT +public: + TrayEmbed( bool kdeTray, QWidget* parent = NULL ); + bool kdeTray() const { return kde_tray; } + void setBackground(); + void getIconSize(int defaultIconSize); +private: + bool kde_tray; +}; + +#endif diff --git a/kicker/applets/taskbar/Makefile.am b/kicker/applets/taskbar/Makefile.am new file mode 100644 index 000000000..35cb337e6 --- /dev/null +++ b/kicker/applets/taskbar/Makefile.am @@ -0,0 +1,22 @@ +INCLUDES = -I$(srcdir)/../../taskbar -I$(srcdir)/../../taskmanager -I$(srcdir)/../../libkicker $(all_includes) + +kde_module_LTLIBRARIES = taskbar_panelapplet.la + +taskbar_panelapplet_la_SOURCES = taskbarapplet.cpp + +taskbar_panelapplet_la_METASOURCES = AUTO +taskbar_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +taskbar_panelapplet_la_LIBADD = $(LIB_KDEUI) ../../taskbar/libtaskbar.la ../../libkicker/libkickermain.la + +noinst_HEADERS = taskbarapplet.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = taskbarapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/ktaskbarapplet.pot + +srcdoc: + kdoc -a -p -H -d $$HOME/web/src/ktaskbarapplet ktaskbarapplet *.h -lqt -lkdecore -lkdeui -lkfile diff --git a/kicker/applets/taskbar/taskbarapplet.cpp b/kicker/applets/taskbar/taskbarapplet.cpp new file mode 100644 index 000000000..dc3428bf8 --- /dev/null +++ b/kicker/applets/taskbar/taskbarapplet.cpp @@ -0,0 +1,126 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlayout.h> +#include <qpalette.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> + +#include "global.h" + +#include "taskbarcontainer.h" + +#include "taskbarapplet.h" +#include "taskbarapplet.moc" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString& configFile ) + { + // FIXME: what about two taskbars? perhaps this should be inserted just once + KGlobal::locale()->insertCatalogue( "ktaskbarapplet" ); + int options = 0; + if (kapp->authorizeControlModule("kde-kcmtaskbar.desktop")) + options = KPanelApplet::Preferences; + TaskbarApplet *taskbar = new TaskbarApplet( configFile, KPanelApplet::Stretch, + options, parent, "ktaskbarapplet" ); + return taskbar; + } +} + +TaskbarApplet::TaskbarApplet( const QString& configFile, Type type, int actions, + QWidget *parent, const char *name ) + : KPanelApplet( configFile, type, actions, parent, name ) +{ + setBackgroundOrigin( AncestorOrigin ); + QHBoxLayout* layout = new QHBoxLayout( this ); + container = new TaskBarContainer( false, this ); + container->setBackgroundOrigin( AncestorOrigin ); + connect(container, SIGNAL(containerCountChanged()), this, SIGNAL(updateLayout())); + layout->addWidget( container, 1 ); + container->popupDirectionChange(popupDirection()); +} + +TaskbarApplet::~TaskbarApplet() +{ + // FIXME: what about TWO taskbars? + KGlobal::locale()->removeCatalogue( "ktaskbarapplet" ); +} + +int TaskbarApplet::widthForHeight(int h) const +{ + if (orientation() == Qt::Vertical) + { + return width(); + } + + // FIXME KDE4: when either TaskBarContainer or Applet smartens up + // simplify this + KPanelExtension::Position d = orientation() == Qt::Horizontal ? + KPanelExtension::Top : + KPanelExtension::Left; + return container->sizeHint(d, QSize(200, h)).width(); +} + +int TaskbarApplet::heightForWidth(int w) const +{ + if (orientation() == Qt::Horizontal) + { + return height(); + } + + // FIXME KDE4: when either TaskBarContainer or Applet smartens up + // simplify this + KPanelExtension::Position d = orientation() == Qt::Horizontal ? + KPanelExtension::Top : + KPanelExtension::Left; + return container->sizeHint(d, QSize(w, 200)).height(); +} + +void TaskbarApplet::preferences() +{ + container->preferences(); +} + +void TaskbarApplet::orientationChange( Orientation o ) +{ + container->orientationChange( o ); +} + +void TaskbarApplet::popupDirectionChange( Direction d ) +{ + container->popupDirectionChange( d ); +} + +void TaskbarApplet::moveEvent(QMoveEvent *) +{ + container->setBackground(); +} + +void TaskbarApplet::paletteChange(const QPalette &) +{ + container->setBackground(); +} diff --git a/kicker/applets/taskbar/taskbarapplet.desktop b/kicker/applets/taskbar/taskbarapplet.desktop new file mode 100644 index 000000000..d54e39832 --- /dev/null +++ b/kicker/applets/taskbar/taskbarapplet.desktop @@ -0,0 +1,138 @@ +[Desktop Entry] +Type=Plugin +Name=Taskbar +Name[af]=Kasbar +Name[ar]=شريط المهام +Name[az]=VÉ™zifÉ™ ÇubuÄŸu +Name[be]=ПанÑль заданнÑÑž +Name[bg]=Панел за задачи +Name[bn]=টাসà§à¦•à¦¬à¦¾à¦° +Name[br]=Barrenn dleadoù +Name[ca]=Barra de tasques +Name[cs]=Pruh úloh +Name[csb]=Lëstew dzejaniów +Name[cy]=Bar tasgau +Name[da]=Opgavelinje +Name[de]=Fensterleiste +Name[el]=ΓÏαμμή εÏγασιών +Name[eo]=Taskostrio +Name[es]=Barra de tareas +Name[et]=Tegumiriba +Name[eu]=Ataza-barra +Name[fa]=میله تکلی٠+Name[fi]=Tehtäväpalkki +Name[fr]=Barre des tâches +Name[fy]=Taakbalke +Name[ga]=Tascbharra +Name[gl]=Barra de tarefas +Name[he]=שורת המשימות +Name[hi]=कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ +Name[hr]=Traka zadataka +Name[hu]=Feladatlista +Name[is]=Verkefnaslá +Name[it]=Barra delle applicazioni +Name[ja]=タスクãƒãƒ¼ +Name[ka]=áƒáƒ›áƒáƒªáƒáƒœáƒáƒ—რპáƒáƒœáƒ”ლი +Name[kk]=ТапÑырмалар панелі +Name[km]=របារ​ភារកិច្ច +Name[ko]=ìž‘ì—… 표시줄 +Name[lo]=à»àº–ບຫນ້າຕ່າງງານ +Name[lt]=UžduoÄių juosta +Name[lv]=Uzdevumjosla +Name[mk]=Лента Ñо програми +Name[mn]=Цонхны Ñамбар +Name[nb]=Oppgavelinje +Name[nds]=Programmbalken +Name[ne]=कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ +Name[nl]=Taakbalk +Name[nn]=OppgÃ¥velinje +Name[nso]=Bar ya Mosongwana +Name[oc]=Barra de tasques +Name[pa]=ਸੰਦਪੱਟੀ +Name[pl]=Pasek zadaÅ„ +Name[pt]=Barra de Tarefas +Name[pt_BR]=Barra de tarefas +Name[ro]=Bara de procese +Name[ru]=Панель задач +Name[rw]=Umurongoibikorwa +Name[se]=Bargoholga +Name[sk]=Panel úloh +Name[sl]=Opravilna vrstica +Name[sr]=Трака задатака +Name[sr@Latn]=Traka zadataka +Name[ss]=Ibar yemsebenti +Name[sv]=Aktivitetsfält +Name[ta]=பணிபà¯à®ªà®Ÿà¯à®Ÿà®¿ +Name[tg]=Пайраҳаи вазифа +Name[th]=à¹à¸–บหน้าต่างงาน +Name[tr]=Görev ÇubuÄŸu +Name[tt]=Qoraltirä +Name[uk]=Смужка задач +Name[uz]=Vazifalar paneli +Name[uz@cyrillic]=Вазифалар панели +Name[ven]=Bara ya mushumo +Name[vi]=Thanh tác vụ +Name[wa]=BÃ¥r des bouyes +Name[xh]=Ibar yomsebenzi +Name[zh_CN]=ä»»åŠ¡æ¡ +Name[zh_TW]=工作列 +Name[zu]=Ibha yemisebenzi + +Comment=The default task bar for window management +Comment[af]=Die standaard taak balk vir venster bestuur +Comment[be]=Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð¿Ð°Ð½Ñль заданнÑÑž Ð´Ð»Ñ ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½Ñ Ð²Ð¾ÐºÐ½Ð°Ð¼Ñ– +Comment[bg]=СиÑтемен панел за лентата ÑÑŠÑ Ð·Ð°Ð´Ð°Ñ‡Ð¸Ñ‚Ðµ +Comment[bn]=উইণà§à¦¡à§‹ বà§à¦¯à¦¬à¦¸à§à¦¥à¦¾à¦ªà¦¨à¦¾à¦° জনà§à¦¯ ডিফলà§à¦Ÿ টাসà§à¦• বার +Comment[bs]=Osnovni taskbar za upravljanje prozorima +Comment[ca]=La barra de tasques per omissió per a la gestió de finestres +Comment[cs]=Výchozà pruh úloh pro správu oken +Comment[csb]=Domëslnô lëstew dzejaniów do sprôwianiô òknama +Comment[da]=Standard-opgavelinje for vindueshÃ¥ndtering +Comment[de]=Standardmäßiger Bereich für offene Fenster in der Kontrollleiste +Comment[el]=Η Ï€ÏοκαθοÏισμÎνη γÏαμμή εÏγασιών για τη διαχείÏιση των παÏαθÏÏων +Comment[eo]=La defaÅlta taskostrio por fenestroadministrado. +Comment[es]=La barra de tareas predeterminada para gestionar las ventanas +Comment[et]=Vaikimisi kasutatav tegumiriba akende halduseks +Comment[eu]=Ataza-barra lehenetsia leihoen kudeaketarako +Comment[fa]=میله تکلی٠پیش‌Ùرض برای مدیریت پنجره +Comment[fi]=Oletustyökalupalkki ikkunoiden hallintaan +Comment[fr]=La barre des tâches gérant les fenêtres +Comment[fy]=De standert taakbalke foar finsterbehear +Comment[gl]=A barra de tarefas por defeito para xestión de fiestras. +Comment[he]=ברירת מחדל של יישומון שורת משימות ללוח +Comment[hr]=Zadana traka zadataka za upravljanje prozorima +Comment[hu]=Az alapértelmezett feladatlista ablakkezeléshez +Comment[is]=Sjálfgefna verkefnasláin fyrir gluggastjórnun +Comment[it]=La barra delle applicazioni per la gestione delle finestre +Comment[ja]=ウィンドウマãƒãƒ¼ã‚¸ãƒ£ç”¨ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ã‚¿ã‚¹ã‚¯ãƒãƒ¼ +Comment[ka]=ფáƒáƒœáƒ¯áƒ ის მáƒáƒ თვის ძირითáƒáƒ“ი პულტი +Comment[kk]=Терезелерді баÑқару әдетті тапÑырмалар панелі +Comment[km]=របារ​ភារកិច្ច​លំនាំដើម សម្រាប់​គ្រប់គ្រង​បង្អួច +Comment[lt]=Numatyta užduoÄių juostos langų tvarkymo priemonÄ— +Comment[mk]=Стандардната линија Ñо задачи за менаџмент на прозорци +Comment[nb]=Den vanlige oppgavelinja for Ã¥ behandle vinduer +Comment[nds]=Standard-Programmbalken för de Finsterpleeg +Comment[ne]=सञà¥à¤à¥à¤¯à¤¾à¤² वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨à¤•à¤¾ लागि पूरà¥à¤µà¤¨à¤¿à¤°à¥à¤§à¤¾à¤°à¤¿à¤¤ उपकरणपटà¥à¤Ÿà¥€ +Comment[nl]=De standaard taakbalk voor vensterbeheer +Comment[nn]=Den vanlege oppgÃ¥velinja for Ã¥ handsama vindauge +Comment[pa]=ਮੂਲ ਵੇਹੜੇ ਲਈ ਮੂਲ ਕੰਮ ਪੱਟੀ +Comment[pl]=DomyÅ›lny pasek zadaÅ„ do zarzÄ…dzania oknami +Comment[pt]=A barra de tarefas por omissão para a gestão de janelas +Comment[pt_BR]=A barra de tarefas padrão para o gerenciamento de janelas. +Comment[ro]=Bara de procese implicită pentru managementul ferestrelor +Comment[ru]=Панель ÑпиÑка задач по умолчанию Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾ÐºÐ½Ð°Ð¼Ð¸ +Comment[se]=Standárda bargoholga lásegieÄ‘aheami várás +Comment[sk]=Prednastavený panel úloh pre správcu okien +Comment[sl]=Privzeta opravilna vrstica za upravljanje z okni +Comment[sr]=Подразумевана трака задатака за управљање прозорима +Comment[sr@Latn]=Podrazumevana traka zadataka za upravljanje prozorima +Comment[sv]=Det förvalda aktivitetsfältet för fönsterhantering +Comment[th]=à¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸•à¸–าดงานโดยปริยายขà¸à¸‡à¸žà¸²à¹€à¸™à¸¥à¸ªà¸³à¸«à¸£à¸±à¸šà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡ +Comment[tr]=Pencere yönetimi için öntanımlı görev çubuÄŸu +Comment[uk]=Типова панель задач Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–ÐºÐ½Ð°Ð¼Ð¸ +Comment[vi]=Thanh tác vụ mặc định cho trình quản lý cá»a sổ +Comment[wa]=Li prémetowe bÃ¥r di bouyes do manaedjmint d' purnea +Comment[zh_CN]=窗å£ç®¡ç†çš„默认任务æ +Comment[zh_TW]=é è¨çš„視窗管ç†å·¥ä½œåˆ— +Icon=taskbar +X-KDE-Library=taskbar_panelapplet diff --git a/kicker/applets/taskbar/taskbarapplet.h b/kicker/applets/taskbar/taskbarapplet.h new file mode 100644 index 000000000..f0842baca --- /dev/null +++ b/kicker/applets/taskbar/taskbarapplet.h @@ -0,0 +1,56 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskbarapplet_h__ +#define __taskbarapplet_h__ + +#include <kpanelapplet.h> + +class TaskBarContainer; +class QPalette; + +class TaskbarApplet : public KPanelApplet +{ + Q_OBJECT + +public: + TaskbarApplet( const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0 ); + ~TaskbarApplet(); + + int widthForHeight( int h ) const; + int heightForWidth( int w ) const; + + void preferences(); + +protected: + void moveEvent(QMoveEvent *); + void popupDirectionChange( Direction ); + void orientationChange( Orientation ); + void paletteChange(const QPalette &); + +private: + TaskBarContainer* container; +}; + +#endif diff --git a/kicker/applets/trash/Makefile.am b/kicker/applets/trash/Makefile.am new file mode 100644 index 000000000..a34f87d1c --- /dev/null +++ b/kicker/applets/trash/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = -I$(top_srcdir)/libkonq -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = trash_panelapplet.la +trash_panelapplet_la_SOURCES = trashbutton.cpp trashapplet.cpp + +METASOURCES = AUTO + +noinst_HEADERS = \ + trashapplet.h trashbutton.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = trashapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +trash_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +trash_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la ../../../libkonq/libkonq.la $(LIB_KDEUI) $(LIB_KIO) $(LIB_KUTILS) + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/trashapplet.pot + diff --git a/kicker/applets/trash/trashapplet.cpp b/kicker/applets/trash/trashapplet.cpp new file mode 100644 index 000000000..c27c4e281 --- /dev/null +++ b/kicker/applets/trash/trashapplet.cpp @@ -0,0 +1,165 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kglobal.h> +#include <klocale.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <kaboutapplication.h> +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kiconloader.h> + +#include "trashapplet.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("trashapplet"); + return new TrashApplet(configFile, KPanelApplet::Normal, + KPanelApplet::About, parent, "trashapplet"); + } +} + +TrashApplet::TrashApplet(const QString& configFile, Type type, int actions, QWidget *parent, const char *name) + : KPanelApplet(configFile, type, actions, parent, name), mButton(0) +{ + mButton = new TrashButton(this); + + if (!parent) + setBackgroundMode(X11ParentRelative); + + mButton->setPanelPosition(position()); + + setAcceptDrops(true); + + mpDirLister = new KDirLister(); + + connect( mpDirLister, SIGNAL( clear() ), + this, SLOT( slotClear() ) ); + connect( mpDirLister, SIGNAL( completed() ), + this, SLOT( slotCompleted() ) ); + connect( mpDirLister, SIGNAL( deleteItem( KFileItem * ) ), + this, SLOT( slotDeleteItem( KFileItem * ) ) ); + + mpDirLister->openURL("trash:/"); +} + +TrashApplet::~TrashApplet() +{ + // disconnect the dir lister before quitting so as not to crash + // on kicker exit + disconnect( mpDirLister, SIGNAL( clear() ), + this, SLOT( slotClear() ) ); + delete mpDirLister; + KGlobal::locale()->removeCatalogue("trashapplet"); +} + +void TrashApplet::about() +{ + KAboutData data("trashapplet", + I18N_NOOP("Trash Applet"), + "1.0", + I18N_NOOP("\"trash:/\" ioslave frontend applet"), + KAboutData::License_GPL_V2, + "(c) 2004, Kevin Ottens"); + + data.addAuthor("Kevin \'ervin\' Ottens", + I18N_NOOP("Maintainer"), + "ervin ipsquad net", + "http://ervin.ipsquad.net"); + + KAboutApplication dialog(&data); + dialog.exec(); +} + +int TrashApplet::widthForHeight( int height ) const +{ + if ( !mButton ) + { + return height; + } + + return mButton->widthForHeight( height ); +} + +int TrashApplet::heightForWidth( int width ) const +{ + if ( !mButton ) + { + return width; + } + + return mButton->heightForWidth( width ); +} + +void TrashApplet::resizeEvent( QResizeEvent * ) +{ + if (!mButton) + { + return; + } + + int size = 1; + + size = std::max( size, + orientation() == Qt::Vertical ? + mButton->heightForWidth( width() ) : + mButton->widthForHeight( height() ) ); + + + if(orientation() == Vertical) + { + mButton->resize( width(), size ); + } + else + { + mButton->resize( size, height() ); + } +} + +void TrashApplet::slotClear() +{ + kdDebug()<<"MediaApplet::slotClear"<<endl; + + mButton->setItemCount(0); +} + +void TrashApplet::slotCompleted() +{ + mCount = mpDirLister->items(KDirLister::AllItems).count(); + mButton->setItemCount( mCount ); +} + +void TrashApplet::slotDeleteItem(KFileItem *) +{ + mCount--; + mButton->setItemCount( mCount ); +} + + +void TrashApplet::positionChange(Position p) +{ + mButton->setPanelPosition(p); +} + + +#include "trashapplet.moc" diff --git a/kicker/applets/trash/trashapplet.desktop b/kicker/applets/trash/trashapplet.desktop new file mode 100644 index 000000000..f1c1eff0a --- /dev/null +++ b/kicker/applets/trash/trashapplet.desktop @@ -0,0 +1,138 @@ +[Desktop Entry] +Type=Plugin +Comment=Displays the trashcan and allows files to be dropped onto it +Comment[af]=Vertoon die asblik en laat toe dat lêers in dit gegooi mag word +Comment[ar]=يظهر سلّة المهملات Ùˆ ÙŠØ³Ù…Ø Ø¨Ø¥Ø³Ù‚Ø§Ø· الملÙات Ùيها +Comment[be]=Паказвае Ñметніцу Ñ– дазвалÑе кідаць файлы Ñž Ñе +Comment[bg]=Показване на кошчето и възможноÑÑ‚ за премеÑтване на файлове в него +Comment[bn]=আবরà§à¦œà¦¨à¦¾à¦° বাকà§à¦¸ দেখায়, যাতে ফাইল ডà§à¦°à¦ª করা যায় +Comment[bs]=Prikazuje kantu za smeće i omogućuje da se u nju bacaju datoteke +Comment[ca]=Mostra la paperera i permet amollar-hi fitxers +Comment[cs]=Zobrazuje koÅ¡ a umožňuje do nÄ›j odhazovat soubory +Comment[csb]=Wëskrzëniwô zamkłósc kòsza ë zezwôlô przecygac do niegò lopczi +Comment[da]=Viser affaldsspanden og tillader at filer droppes pÃ¥ den +Comment[de]=Mülleimerfunktion in der Kontrollleiste +Comment[el]=Εμφανίζει τον Κάδο ΑποÏÏιμμάτων και επιτÏÎπει την απόθεση αÏχείων πάνω του +Comment[en_GB]=Displays the wastebin and allows files to be dropped onto it +Comment[eo]=Montras rubujon kaj ebligas dosiero-alfaligon +Comment[es]=Muestra la papelera y permite tirar archivos en ella +Comment[et]=Näitab prügikasti ning lubab faile sellesse visata +Comment[eu]=Zakarontzia bistaratzen du, fitxategiak jauregitea lagunduz +Comment[fa]=زباله‌دان را نمایش داده Ùˆ به پرونده‌ها اجازه می‌دهد در آن بیÙتند +Comment[fi]=Näyttää roskakorin ja sallii tiedostojen pudottamisen siihen +Comment[fr]=Affiche la corbeille et permet d'y déposer des fichiers +Comment[fy]=Lit it jiskefet sjen en stiet ta dat triemmen fuortsmiten wurde troch se nei it byldkaike ta te slepen +Comment[gl]=Mostra a papeleira e permite deitar ficheiros nela +Comment[he]=מציג ×ת פח ×”×שפה ומ×פשר לך לזרוק ×ליו ×§×‘×¦×™× +Comment[hr]=Prikazuje kantu za otpad i omogućuje ispuÅ¡tanje datoteka u nju +Comment[hu]=MegjelenÃti a szemétkosarat, lehetÅ‘vé téve fájlok belehelyezését +Comment[is]=Sýnir ruslakörfuna og leyfir að skrám sé sleppt á hana +Comment[it]=Mostra il cestino e permette di trascinarci sopra i file +Comment[ja]=ã”ã¿ç®±ã‚’表示ã—ã€ã”ã¿ç®±ã¸ã®ãƒ•ã‚¡ã‚¤ãƒ«ã®ãƒ‰ãƒãƒƒãƒ—ã‚’å¯èƒ½ã«ã—ã¾ã™ +Comment[kk]=Өшірілгендер шелегін керÑетіп, оған файлдарды таÑтауға мүмкіндік береді +Comment[km]=បង្ហាញ​ធុង​សំរាម និង​អនុញ្ញាážâ€‹áž²áŸ’យ​ទម្លាក់​ឯកសារ​លើ​វា +Comment[lt]=Rodo Å¡iukÅ¡liadėžę ir leidžia į jÄ… tempiant numesti bylas +Comment[mk]=Ја прикажува корпата и овозможува пуштање датотеки врз неа +Comment[nb]=Viser papirkurven og lar deg legge filer i den +Comment[nds]=Wiest de Affalltünn, Dateien köönt dor op droppt warrn. +Comment[ne]=रदà¥à¤¦à¥€à¤Ÿà¥‹à¤•à¤°à¥€ पà¥à¤°à¤¦à¤°à¥à¤¶à¤¨ गरà¥à¤› र यसमा फाइलहरू राखà¥à¤¨ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤› +Comment[nl]=Toont de prullenbak en maakt het mogelijk bestanden weg te gooien door ze naar het pictogram te slepen +Comment[nn]=Viser papirkorga og lèt deg leggja filer i henne +Comment[pl]=Pokazuje kosz i pozwala przeciÄ…gać do niego pliki +Comment[pt]=Mostra o caixote do lixo e permite largar ficheiros nele +Comment[pt_BR]=Mostra a lixeira e permite que arquivos sejam arrastados até ela +Comment[ro]=AfiÈ™ează coÈ™ul de gunoi È™i permite aruncare fiÈ™ierelor în acesta +Comment[ru]=Показать на рабочем Ñтоле корзину Ð´Ð»Ñ Ð½ÐµÐ½ÑƒÐ¶Ð½Ñ‹Ñ… файлов +Comment[sk]=Zobrazà odpadkový kôš a povolà vhodenie súborov do neho +Comment[sl]=Prikaz ikone za Smeti, na katero lahko odvržete datoteke +Comment[sr]=Приказује канту за Ñмеће и омогућава иÑпуштање фајлова на њу +Comment[sr@Latn]=Prikazuje kantu za smeće i omogućava ispuÅ¡tanje fajlova na nju +Comment[sv]=Visar papperskorgen och tillÃ¥ter att filer släpps pÃ¥ den +Comment[th]=à¹à¸ªà¸”งถังขยะà¹à¸¥à¸°à¸à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¸¡à¸µà¸à¸²à¸£à¸›à¸¥à¹ˆà¸à¸¢à¹à¸Ÿà¹‰à¸¡à¸¥à¸‡à¹„ปได้ +Comment[tr]=Çöp kutusunu gösterir ve dosyaların üzerine taşınmasına izin verir +Comment[uk]=Показує Ñмітник Ñ– дає змогу вкидати в нього файли +Comment[vi]=Hiển thị thùng rác và cho phép thả các táºp tin và o đó +Comment[wa]=HÃ¥yneye l' batch et permete di mete des fitchîs Ã¥ dvins +Comment[zh_CN]=显示回收站,并å…许您将文件拖至其上 +Comment[zh_TW]=顯示垃圾ç’並且å…è¨±å°‡æª”æ¡ˆä¸Ÿåˆ°å…¶ä¸ +Name=Trash +Name[af]=Gemors +Name[ar]=سلة النÙايات +Name[az]=Zibil +Name[be]=Сметніца +Name[bg]=Кошче +Name[bn]=আবরà§à¦œà¦¨à¦¾ +Name[br]=Pod-lastez +Name[bs]=Smeće +Name[ca]=Paperera +Name[cs]=KoÅ¡ +Name[csb]=Kòsz +Name[cy]=Sbwriel +Name[da]=Affald +Name[de]=Mülleimer +Name[el]=Κάδος αποÏÏιμμάτων +Name[en_GB]=Wastebin +Name[eo]=Rubujo +Name[es]=Papelera +Name[et]=Prügikast +Name[eu]=Zaborra +Name[fa]=زباله +Name[fi]=Roskakori +Name[fr]=Corbeille +Name[fy]=Jiskefet +Name[ga]=Bruscar +Name[gl]=Lixo +Name[he]=×שפה +Name[hi]=रदà¥à¤¦à¥€ +Name[hr]=Otpad +Name[hsb]=Papjernik +Name[hu]=Szemétkosár +Name[is]=Rusl +Name[it]=Cestino +Name[ja]=ã”ã¿ç®± +Name[ka]=ურნრ+Name[kk]=Өшірілгендер +Name[km]=ធុងសំរាម +Name[lo]=ຖັງຂີ້ເຫàºàº·à»ˆàº +Name[lt]=Å iukÅ¡liadėžė +Name[lv]=Miskaste +Name[mk]=Корпа +Name[mn]=Хогийн Ñав +Name[ms]=Sampah +Name[mt]=Skart +Name[nb]=Papirkurv +Name[nds]=Affalltünn +Name[ne]=रदà¥à¤¦à¥€à¤Ÿà¥‹à¤•à¤°à¥€ +Name[nl]=Prullenbak +Name[nn]=Papirkorg +Name[nso]=Seswaraditlakala +Name[pa]=ਰੱਦੀ +Name[pl]=Kosz +Name[pt]=Lixo +Name[pt_BR]=Lixo +Name[ro]=Gunoi +Name[ru]=Корзина +Name[se]=Ruskalihtti +Name[sk]=Kôš +Name[sl]=Smeti +Name[sr]=Смеће +Name[sr@Latn]=Smeće +Name[sv]=Skräp +Name[ta]=கà¯à®ªà¯à®ªà¯ˆ +Name[te]=చెతà±à°¤ à°¬à±à°Ÿà±à°Ÿ +Name[tg]=Ðхлотдон +Name[th]=ถังขยะ +Name[tr]=Çöp +Name[tt]=Çüplek +Name[uk]=Смітник +Name[uz]=Chiqindilar qutisi +Name[uz@cyrillic]=Чиқиндилар қутиÑи +Name[ven]=Tshikha +Name[vi]=Thùng rác +Name[wa]=Batch +Name[xh]=Inkukumo +Name[zh_CN]=回收站 +Name[zh_TW]=資æºå›žæ”¶æ¡¶ +Name[zu]=Izibi +Icon=trashcan_empty +X-KDE-Library=trash_panelapplet diff --git a/kicker/applets/trash/trashapplet.h b/kicker/applets/trash/trashapplet.h new file mode 100644 index 000000000..bc9662af4 --- /dev/null +++ b/kicker/applets/trash/trashapplet.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TRASHAPPLET_H +#define TRASHAPPLET_H + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <kpanelapplet.h> +#include <qstring.h> +#include <kurl.h> +#include <kdirlister.h> + +#include "trashbutton.h" + +class TrashApplet : public KPanelApplet +{ +Q_OBJECT + +public: + TrashApplet(const QString& configFile, Type t = Normal, int actions = 0, + QWidget *parent = 0, const char *name = 0); + ~TrashApplet(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + void about(); + +protected: + void resizeEvent(QResizeEvent *e); + void positionChange(Position p); + +protected slots: + void slotClear(); + void slotCompleted(); + void slotDeleteItem(KFileItem *); + +private: + KDirLister *mpDirLister; + TrashButton *mButton; + int mCount; +}; + +#endif diff --git a/kicker/applets/trash/trashbutton.cpp b/kicker/applets/trash/trashbutton.cpp new file mode 100644 index 000000000..e6934a983 --- /dev/null +++ b/kicker/applets/trash/trashbutton.cpp @@ -0,0 +1,154 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "trashbutton.h" + +#include <qpopupmenu.h> +#include <qtooltip.h> + +#include <klocale.h> +#include <krun.h> +#include <kpopupmenu.h> + +#include <kio/netaccess.h> + +#include <konq_operations.h> +#include <konq_popupmenu.h> + +TrashButton::TrashButton(QWidget *parent) + : PanelPopupButton(parent), mActions(this, this), + mFileItem(KFileItem::Unknown, KFileItem::Unknown, "trash:/") +{ + KIO::UDSEntry entry; + KIO::NetAccess::stat("trash:/", entry, 0L); + mFileItem.assign(KFileItem(entry, "trash:/")); + + KAction *a = KStdAction::paste(this, SLOT(slotPaste()), + &mActions, "paste"); + a->setShortcut(0); + + move(0, 0); + resize(20, 20); + + setTitle(i18n("Trash")); + setIcon( "trashcan_empty" ); + + setAcceptDrops(true); + + // Activate this code only if we find a way to have both an + // action and a popup menu for the same kicker button + //connect(this, SIGNAL(clicked()), this, SLOT(slotClicked())); + + setPopup(new QPopupMenu()); +} + +TrashButton::~TrashButton() +{ +} + +void TrashButton::setItemCount(int count) +{ + if (count==0) + { + setIcon( "trashcan_empty" ); + QToolTip::add(this, i18n("Empty")); + } + else + { + setIcon( "trashcan_full" ); + QToolTip::add(this, i18n("One item", "%n items", count)); + } +} + +void TrashButton::initPopup() +{ + QPopupMenu *old_popup = popup(); + + KFileItemList items; + items.append(&mFileItem); + + KonqPopupMenu::KonqPopupFlags kpf = + KonqPopupMenu::ShowProperties + | KonqPopupMenu::ShowNewWindow; + + KParts::BrowserExtension::PopupFlags bef = + KParts::BrowserExtension::DefaultPopupItems; + + KonqPopupMenu *new_popup = new KonqPopupMenu(0L, items, + KURL("trash:/"), mActions, 0L, + this, kpf, bef); + KPopupTitle *title = new KPopupTitle(new_popup); + title->setTitle(i18n("Trash")); + + new_popup->insertItem(title, -1, 0); + + setPopup(new_popup); + + if (old_popup!=0L) delete old_popup; +} + +// Activate this code only if we find a way to have both an +// action and a popup menu for the same kicker button +/* +void TrashButton::slotClicked() +{ + mFileItem.run(); +} +*/ + +void TrashButton::slotPaste() +{ + KonqOperations::doPaste(this, mFileItem.url()); +} + +void TrashButton::dragEnterEvent(QDragEnterEvent* e) +{ + e->accept(true); +} + +void TrashButton::dropEvent(QDropEvent *e) +{ + KonqOperations::doDrop(0L, mFileItem.url(), e, this); +} + +QString TrashButton::tileName() +{ + return mFileItem.name(); +} + +void TrashButton::setPanelPosition(KPanelApplet::Position position) +{ + switch(position) + { + case KPanelApplet::pBottom: + setPopupDirection(KPanelApplet::Up); + break; + case KPanelApplet::pTop: + setPopupDirection(KPanelApplet::Down); + break; + case KPanelApplet::pRight: + setPopupDirection(KPanelApplet::Left); + break; + case KPanelApplet::pLeft: + setPopupDirection(KPanelApplet::Right); + break; + } +} + +#include "trashbutton.moc" diff --git a/kicker/applets/trash/trashbutton.h b/kicker/applets/trash/trashbutton.h new file mode 100644 index 000000000..7a5d8b59f --- /dev/null +++ b/kicker/applets/trash/trashbutton.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TRASHBUTTON_H +#define TRASHBUTTON_H + +#include <panelbutton.h> +#include <qpoint.h> +#include <qstring.h> +#include <qpixmap.h> +#include <qcursor.h> +#include <qtimer.h> +#include <kfileitem.h> +#include <kpanelapplet.h> +#include <kactioncollection.h> + +class TrashButton : public PanelPopupButton +{ +Q_OBJECT + +public: + TrashButton(QWidget *parent); + ~TrashButton(); + void setItemCount(int count); + void setPanelPosition(KPanelApplet::Position position); + +protected: + QString tileName(); + void initPopup(); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + +protected slots: + // Activate this code only if we find a way to have both an + // action and a popup menu for the same kicker button + //void slotClicked(); + void slotPaste(); + +private: + KActionCollection mActions; + KFileItem mFileItem; +}; + +#endif diff --git a/kicker/data/Makefile.am b/kicker/data/Makefile.am new file mode 100644 index 000000000..41d9598ed --- /dev/null +++ b/kicker/data/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = icons tiles app_start_anim wallpaper kmenu_side diff --git a/kicker/data/app_start_anim/Makefile.am b/kicker/data/app_start_anim/Makefile.am new file mode 100644 index 000000000..b8e31f0ff --- /dev/null +++ b/kicker/data/app_start_anim/Makefile.am @@ -0,0 +1,7 @@ + +kicker_appstart_pics_data_DATA = disk1.png disk2.png disk3.png disk4.png disk5.png disk6.png disk7.png disk8.png disk9.png disk10.png + +kicker_appstart_pics_datadir = $(kde_datadir)/kicker/pics/ + +EXTRA_DIST = $(kicker_appstart_pics_data_DATA) + diff --git a/kicker/data/app_start_anim/disk1.png b/kicker/data/app_start_anim/disk1.png Binary files differnew file mode 100644 index 000000000..37262272e --- /dev/null +++ b/kicker/data/app_start_anim/disk1.png diff --git a/kicker/data/app_start_anim/disk10.png b/kicker/data/app_start_anim/disk10.png Binary files differnew file mode 100644 index 000000000..6f5c65d54 --- /dev/null +++ b/kicker/data/app_start_anim/disk10.png diff --git a/kicker/data/app_start_anim/disk2.png b/kicker/data/app_start_anim/disk2.png Binary files differnew file mode 100644 index 000000000..cac143984 --- /dev/null +++ b/kicker/data/app_start_anim/disk2.png diff --git a/kicker/data/app_start_anim/disk3.png b/kicker/data/app_start_anim/disk3.png Binary files differnew file mode 100644 index 000000000..7cfc09c84 --- /dev/null +++ b/kicker/data/app_start_anim/disk3.png diff --git a/kicker/data/app_start_anim/disk4.png b/kicker/data/app_start_anim/disk4.png Binary files differnew file mode 100644 index 000000000..0de1cf4e7 --- /dev/null +++ b/kicker/data/app_start_anim/disk4.png diff --git a/kicker/data/app_start_anim/disk5.png b/kicker/data/app_start_anim/disk5.png Binary files differnew file mode 100644 index 000000000..62e26f497 --- /dev/null +++ b/kicker/data/app_start_anim/disk5.png diff --git a/kicker/data/app_start_anim/disk6.png b/kicker/data/app_start_anim/disk6.png Binary files differnew file mode 100644 index 000000000..1bd210ffc --- /dev/null +++ b/kicker/data/app_start_anim/disk6.png diff --git a/kicker/data/app_start_anim/disk7.png b/kicker/data/app_start_anim/disk7.png Binary files differnew file mode 100644 index 000000000..a992322a4 --- /dev/null +++ b/kicker/data/app_start_anim/disk7.png diff --git a/kicker/data/app_start_anim/disk8.png b/kicker/data/app_start_anim/disk8.png Binary files differnew file mode 100644 index 000000000..b9c86a0b8 --- /dev/null +++ b/kicker/data/app_start_anim/disk8.png diff --git a/kicker/data/app_start_anim/disk9.png b/kicker/data/app_start_anim/disk9.png Binary files differnew file mode 100644 index 000000000..6bbbb2258 --- /dev/null +++ b/kicker/data/app_start_anim/disk9.png diff --git a/kicker/data/icons/Makefile.am b/kicker/data/icons/Makefile.am new file mode 100644 index 000000000..4bc51ce73 --- /dev/null +++ b/kicker/data/icons/Makefile.am @@ -0,0 +1,3 @@ +KDE_ICON = kdisknav package_favourite panel window_list kmenu kicker + +SUBDIRS = actions diff --git a/kicker/data/icons/actions/Makefile.am b/kicker/data/icons/actions/Makefile.am new file mode 100644 index 000000000..f8fd92330 --- /dev/null +++ b/kicker/data/icons/actions/Makefile.am @@ -0,0 +1,3 @@ +kickericonsdir = $(kde_datadir)/kicker/icons +kickericons_ICON = AUTO + diff --git a/kicker/data/icons/actions/cr16-action-modified.png b/kicker/data/icons/actions/cr16-action-modified.png Binary files differnew file mode 100644 index 000000000..41b3f4367 --- /dev/null +++ b/kicker/data/icons/actions/cr16-action-modified.png diff --git a/kicker/data/icons/actions/lo16-action-modified.png b/kicker/data/icons/actions/lo16-action-modified.png Binary files differnew file mode 100644 index 000000000..63c705f00 --- /dev/null +++ b/kicker/data/icons/actions/lo16-action-modified.png diff --git a/kicker/data/icons/cr16-app-kdisknav.png b/kicker/data/icons/cr16-app-kdisknav.png Binary files differnew file mode 100644 index 000000000..3ba8a1416 --- /dev/null +++ b/kicker/data/icons/cr16-app-kdisknav.png diff --git a/kicker/data/icons/cr16-app-kicker.png b/kicker/data/icons/cr16-app-kicker.png Binary files differnew file mode 100644 index 000000000..e66dd216a --- /dev/null +++ b/kicker/data/icons/cr16-app-kicker.png diff --git a/kicker/data/icons/cr16-app-panel.png b/kicker/data/icons/cr16-app-panel.png Binary files differnew file mode 100644 index 000000000..e66dd216a --- /dev/null +++ b/kicker/data/icons/cr16-app-panel.png diff --git a/kicker/data/icons/cr16-app-window_list.png b/kicker/data/icons/cr16-app-window_list.png Binary files differnew file mode 100644 index 000000000..d8afab4b2 --- /dev/null +++ b/kicker/data/icons/cr16-app-window_list.png diff --git a/kicker/data/icons/cr32-app-kdisknav.png b/kicker/data/icons/cr32-app-kdisknav.png Binary files differnew file mode 100644 index 000000000..370de627f --- /dev/null +++ b/kicker/data/icons/cr32-app-kdisknav.png diff --git a/kicker/data/icons/cr32-app-window_list.png b/kicker/data/icons/cr32-app-window_list.png Binary files differnew file mode 100644 index 000000000..f8d64d1df --- /dev/null +++ b/kicker/data/icons/cr32-app-window_list.png diff --git a/kicker/data/icons/cr48-app-kdisknav.png b/kicker/data/icons/cr48-app-kdisknav.png Binary files differnew file mode 100644 index 000000000..fbc259e95 --- /dev/null +++ b/kicker/data/icons/cr48-app-kdisknav.png diff --git a/kicker/data/icons/cr48-app-window_list.png b/kicker/data/icons/cr48-app-window_list.png Binary files differnew file mode 100644 index 000000000..ca164a12a --- /dev/null +++ b/kicker/data/icons/cr48-app-window_list.png diff --git a/kicker/data/kmenu_side/Makefile.am b/kicker/data/kmenu_side/Makefile.am new file mode 100644 index 000000000..ee19c9a20 --- /dev/null +++ b/kicker/data/kmenu_side/Makefile.am @@ -0,0 +1,6 @@ +kicker_kmenuside_pics_data_DATA = kside.png kside_tile.png + +kicker_kmenuside_pics_datadir = $(kde_datadir)/kicker/pics/ + +EXTRA_DIST = $(kicker_kmenuside_pics_data_DATA) + diff --git a/kicker/data/kmenu_side/kside.png b/kicker/data/kmenu_side/kside.png Binary files differnew file mode 100644 index 000000000..d3ad79075 --- /dev/null +++ b/kicker/data/kmenu_side/kside.png diff --git a/kicker/data/kmenu_side/kside_tile.png b/kicker/data/kmenu_side/kside_tile.png Binary files differnew file mode 100644 index 000000000..e552e47cc --- /dev/null +++ b/kicker/data/kmenu_side/kside_tile.png diff --git a/kicker/data/tiles/KDE_button_large_down.png b/kicker/data/tiles/KDE_button_large_down.png Binary files differnew file mode 100644 index 000000000..726095c45 --- /dev/null +++ b/kicker/data/tiles/KDE_button_large_down.png diff --git a/kicker/data/tiles/KDE_button_large_up.png b/kicker/data/tiles/KDE_button_large_up.png Binary files differnew file mode 100644 index 000000000..83a540f85 --- /dev/null +++ b/kicker/data/tiles/KDE_button_large_up.png diff --git a/kicker/data/tiles/KDE_button_normal_down.png b/kicker/data/tiles/KDE_button_normal_down.png Binary files differnew file mode 100644 index 000000000..35a848bf7 --- /dev/null +++ b/kicker/data/tiles/KDE_button_normal_down.png diff --git a/kicker/data/tiles/KDE_button_normal_up.png b/kicker/data/tiles/KDE_button_normal_up.png Binary files differnew file mode 100644 index 000000000..304940fb1 --- /dev/null +++ b/kicker/data/tiles/KDE_button_normal_up.png diff --git a/kicker/data/tiles/KDE_button_tiny_down.png b/kicker/data/tiles/KDE_button_tiny_down.png Binary files differnew file mode 100644 index 000000000..356d4498b --- /dev/null +++ b/kicker/data/tiles/KDE_button_tiny_down.png diff --git a/kicker/data/tiles/KDE_button_tiny_up.png b/kicker/data/tiles/KDE_button_tiny_up.png Binary files differnew file mode 100644 index 000000000..aec67c344 --- /dev/null +++ b/kicker/data/tiles/KDE_button_tiny_up.png diff --git a/kicker/data/tiles/Makefile.am b/kicker/data/tiles/Makefile.am new file mode 100644 index 000000000..446a22b19 --- /dev/null +++ b/kicker/data/tiles/Makefile.am @@ -0,0 +1,57 @@ + +kicker_ktiles_data_DATA = \ +red_wood_normal_down.png red_wood_normal_up.png \ +red_wood_tiny_down.png red_wood_tiny_up.png \ +blue_wood_large_down.png solid_blue_large_down.png \ +blue_wood_large_up.png solid_blue_large_up.png \ +blue_wood_normal_down.png solid_blue_normal_down.png \ +blue_wood_normal_up.png solid_blue_normal_up.png \ +blue_wood_tiny_down.png solid_blue_tiny_down.png \ +blue_wood_tiny_up.png solid_blue_tiny_up.png \ +green_wood_large_down.png solid_gray_large_down.png \ +green_wood_large_up.png solid_gray_large_up.png \ +green_wood_normal_down.png solid_gray_normal_down.png \ +green_wood_normal_up.png solid_gray_normal_up.png \ +green_wood_tiny_down.png solid_gray_tiny_down.png \ +green_wood_tiny_up.png solid_gray_tiny_up.png \ +KDE_button_large_down.png solid_green_large_down.png \ +KDE_button_large_up.png solid_green_large_up.png \ +KDE_button_normal_down.png solid_green_normal_down.png \ +KDE_button_normal_up.png solid_green_normal_up.png \ +KDE_button_tiny_down.png solid_green_tiny_down.png \ +KDE_button_tiny_up.png solid_green_tiny_up.png \ +light_green_large_down.png solid_orange_large_down.png \ +light_green_large_up.png solid_orange_large_up.png \ +light_green_normal_down.png solid_orange_normal_down.png \ +light_green_normal_up.png solid_orange_normal_up.png \ +light_green_tiny_down.png solid_orange_tiny_down.png \ +light_green_tiny_up.png solid_orange_tiny_up.png \ +light_gray_large_down.png solid_pastel_large_down.png \ +light_gray_large_up.png solid_pastel_large_up.png \ +light_gray_normal_up.png solid_pastel_normal_down.png \ +light_gray_tiny_down.png solid_pastel_normal_up.png \ +light_gray_tiny_up.png solid_pastel_tiny_down.png \ +light_pastel_large_down.png solid_pastel_tiny_up.png \ +light_pastel_large_up.png solid_purple_large_down.png \ +light_pastel_normal_up.png solid_purple_large_up.png \ +light_pastel_tiny_down.png solid_purple_normal_down.png \ +light_pastel_tiny_up.png solid_purple_normal_up.png \ +light_purple_large_down.png solid_purple_tiny_down.png \ +light_purple_large_up.png solid_purple_tiny_up.png \ +light_purple_normal_down.png solid_red_large_down.png \ +light_purple_normal_up.png solid_red_large_up.png \ +light_purple_tiny_down.png solid_red_normal_down.png \ +light_purple_tiny_up.png solid_red_normal_up.png \ +nuts_and_bolts_large_down.png solid_red_tiny_down.png \ +nuts_and_bolts_large_up.png solid_red_tiny_up.png \ +nuts_and_bolts_normal_down.png solid_tigereye_large_down.png \ +nuts_and_bolts_normal_up.png solid_tigereye_large_up.png \ +nuts_and_bolts_tiny_down.png solid_tigereye_normal_down.png \ +nuts_and_bolts_tiny_up.png solid_tigereye_normal_up.png \ +red_wood_large_down.png solid_tigereye_tiny_down.png \ +red_wood_large_up.png solid_tigereye_tiny_up.png + +kicker_ktiles_datadir = $(kde_datadir)/kicker/tiles + +EXTRA_DIST = $(kicker_ktiles_data_DATA) + diff --git a/kicker/data/tiles/blue_wood_large_down.png b/kicker/data/tiles/blue_wood_large_down.png Binary files differnew file mode 100644 index 000000000..576ad41e6 --- /dev/null +++ b/kicker/data/tiles/blue_wood_large_down.png diff --git a/kicker/data/tiles/blue_wood_large_up.png b/kicker/data/tiles/blue_wood_large_up.png Binary files differnew file mode 100644 index 000000000..f82f9f291 --- /dev/null +++ b/kicker/data/tiles/blue_wood_large_up.png diff --git a/kicker/data/tiles/blue_wood_normal_down.png b/kicker/data/tiles/blue_wood_normal_down.png Binary files differnew file mode 100644 index 000000000..8ba8e91cf --- /dev/null +++ b/kicker/data/tiles/blue_wood_normal_down.png diff --git a/kicker/data/tiles/blue_wood_normal_up.png b/kicker/data/tiles/blue_wood_normal_up.png Binary files differnew file mode 100644 index 000000000..9ba633c5f --- /dev/null +++ b/kicker/data/tiles/blue_wood_normal_up.png diff --git a/kicker/data/tiles/blue_wood_tiny_down.png b/kicker/data/tiles/blue_wood_tiny_down.png Binary files differnew file mode 100644 index 000000000..0a034c005 --- /dev/null +++ b/kicker/data/tiles/blue_wood_tiny_down.png diff --git a/kicker/data/tiles/blue_wood_tiny_up.png b/kicker/data/tiles/blue_wood_tiny_up.png Binary files differnew file mode 100644 index 000000000..37bafb97f --- /dev/null +++ b/kicker/data/tiles/blue_wood_tiny_up.png diff --git a/kicker/data/tiles/green_wood_large_down.png b/kicker/data/tiles/green_wood_large_down.png Binary files differnew file mode 100644 index 000000000..0601d563a --- /dev/null +++ b/kicker/data/tiles/green_wood_large_down.png diff --git a/kicker/data/tiles/green_wood_large_up.png b/kicker/data/tiles/green_wood_large_up.png Binary files differnew file mode 100644 index 000000000..f48f6a256 --- /dev/null +++ b/kicker/data/tiles/green_wood_large_up.png diff --git a/kicker/data/tiles/green_wood_normal_down.png b/kicker/data/tiles/green_wood_normal_down.png Binary files differnew file mode 100644 index 000000000..10163ed80 --- /dev/null +++ b/kicker/data/tiles/green_wood_normal_down.png diff --git a/kicker/data/tiles/green_wood_normal_up.png b/kicker/data/tiles/green_wood_normal_up.png Binary files differnew file mode 100644 index 000000000..479a3544c --- /dev/null +++ b/kicker/data/tiles/green_wood_normal_up.png diff --git a/kicker/data/tiles/green_wood_tiny_down.png b/kicker/data/tiles/green_wood_tiny_down.png Binary files differnew file mode 100644 index 000000000..aa026aaed --- /dev/null +++ b/kicker/data/tiles/green_wood_tiny_down.png diff --git a/kicker/data/tiles/green_wood_tiny_up.png b/kicker/data/tiles/green_wood_tiny_up.png Binary files differnew file mode 100644 index 000000000..ff6d6885a --- /dev/null +++ b/kicker/data/tiles/green_wood_tiny_up.png diff --git a/kicker/data/tiles/light_gray_large_down.png b/kicker/data/tiles/light_gray_large_down.png Binary files differnew file mode 100644 index 000000000..20c159645 --- /dev/null +++ b/kicker/data/tiles/light_gray_large_down.png diff --git a/kicker/data/tiles/light_gray_large_up.png b/kicker/data/tiles/light_gray_large_up.png Binary files differnew file mode 100644 index 000000000..88f4055be --- /dev/null +++ b/kicker/data/tiles/light_gray_large_up.png diff --git a/kicker/data/tiles/light_gray_normal_up.png b/kicker/data/tiles/light_gray_normal_up.png Binary files differnew file mode 100644 index 000000000..220ba6ccc --- /dev/null +++ b/kicker/data/tiles/light_gray_normal_up.png diff --git a/kicker/data/tiles/light_gray_tiny_down.png b/kicker/data/tiles/light_gray_tiny_down.png Binary files differnew file mode 100644 index 000000000..e462814e5 --- /dev/null +++ b/kicker/data/tiles/light_gray_tiny_down.png diff --git a/kicker/data/tiles/light_gray_tiny_up.png b/kicker/data/tiles/light_gray_tiny_up.png Binary files differnew file mode 100644 index 000000000..39a2b7017 --- /dev/null +++ b/kicker/data/tiles/light_gray_tiny_up.png diff --git a/kicker/data/tiles/light_green_large_down.png b/kicker/data/tiles/light_green_large_down.png Binary files differnew file mode 100644 index 000000000..e5c556b9e --- /dev/null +++ b/kicker/data/tiles/light_green_large_down.png diff --git a/kicker/data/tiles/light_green_large_up.png b/kicker/data/tiles/light_green_large_up.png Binary files differnew file mode 100644 index 000000000..20c45b134 --- /dev/null +++ b/kicker/data/tiles/light_green_large_up.png diff --git a/kicker/data/tiles/light_green_normal_down.png b/kicker/data/tiles/light_green_normal_down.png Binary files differnew file mode 100644 index 000000000..d630cf91e --- /dev/null +++ b/kicker/data/tiles/light_green_normal_down.png diff --git a/kicker/data/tiles/light_green_normal_up.png b/kicker/data/tiles/light_green_normal_up.png Binary files differnew file mode 100644 index 000000000..51b1f0690 --- /dev/null +++ b/kicker/data/tiles/light_green_normal_up.png diff --git a/kicker/data/tiles/light_green_tiny_down.png b/kicker/data/tiles/light_green_tiny_down.png Binary files differnew file mode 100644 index 000000000..56689d8ea --- /dev/null +++ b/kicker/data/tiles/light_green_tiny_down.png diff --git a/kicker/data/tiles/light_green_tiny_up.png b/kicker/data/tiles/light_green_tiny_up.png Binary files differnew file mode 100644 index 000000000..016f3b516 --- /dev/null +++ b/kicker/data/tiles/light_green_tiny_up.png diff --git a/kicker/data/tiles/light_pastel_large_down.png b/kicker/data/tiles/light_pastel_large_down.png Binary files differnew file mode 100644 index 000000000..8b14d717e --- /dev/null +++ b/kicker/data/tiles/light_pastel_large_down.png diff --git a/kicker/data/tiles/light_pastel_large_up.png b/kicker/data/tiles/light_pastel_large_up.png Binary files differnew file mode 100644 index 000000000..b920125df --- /dev/null +++ b/kicker/data/tiles/light_pastel_large_up.png diff --git a/kicker/data/tiles/light_pastel_normal_up.png b/kicker/data/tiles/light_pastel_normal_up.png Binary files differnew file mode 100644 index 000000000..ad6864a9a --- /dev/null +++ b/kicker/data/tiles/light_pastel_normal_up.png diff --git a/kicker/data/tiles/light_pastel_tiny_down.png b/kicker/data/tiles/light_pastel_tiny_down.png Binary files differnew file mode 100644 index 000000000..85af54c59 --- /dev/null +++ b/kicker/data/tiles/light_pastel_tiny_down.png diff --git a/kicker/data/tiles/light_pastel_tiny_up.png b/kicker/data/tiles/light_pastel_tiny_up.png Binary files differnew file mode 100644 index 000000000..9267620f3 --- /dev/null +++ b/kicker/data/tiles/light_pastel_tiny_up.png diff --git a/kicker/data/tiles/light_purple_large_down.png b/kicker/data/tiles/light_purple_large_down.png Binary files differnew file mode 100644 index 000000000..0246b87c4 --- /dev/null +++ b/kicker/data/tiles/light_purple_large_down.png diff --git a/kicker/data/tiles/light_purple_large_up.png b/kicker/data/tiles/light_purple_large_up.png Binary files differnew file mode 100644 index 000000000..4ef4b9746 --- /dev/null +++ b/kicker/data/tiles/light_purple_large_up.png diff --git a/kicker/data/tiles/light_purple_normal_down.png b/kicker/data/tiles/light_purple_normal_down.png Binary files differnew file mode 100644 index 000000000..f504992ab --- /dev/null +++ b/kicker/data/tiles/light_purple_normal_down.png diff --git a/kicker/data/tiles/light_purple_normal_up.png b/kicker/data/tiles/light_purple_normal_up.png Binary files differnew file mode 100644 index 000000000..4e2d8c179 --- /dev/null +++ b/kicker/data/tiles/light_purple_normal_up.png diff --git a/kicker/data/tiles/light_purple_tiny_down.png b/kicker/data/tiles/light_purple_tiny_down.png Binary files differnew file mode 100644 index 000000000..8a44988d4 --- /dev/null +++ b/kicker/data/tiles/light_purple_tiny_down.png diff --git a/kicker/data/tiles/light_purple_tiny_up.png b/kicker/data/tiles/light_purple_tiny_up.png Binary files differnew file mode 100644 index 000000000..9a8af02cc --- /dev/null +++ b/kicker/data/tiles/light_purple_tiny_up.png diff --git a/kicker/data/tiles/nuts_and_bolts_large_down.png b/kicker/data/tiles/nuts_and_bolts_large_down.png Binary files differnew file mode 100644 index 000000000..120a63d78 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_large_down.png diff --git a/kicker/data/tiles/nuts_and_bolts_large_up.png b/kicker/data/tiles/nuts_and_bolts_large_up.png Binary files differnew file mode 100644 index 000000000..42713ed07 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_large_up.png diff --git a/kicker/data/tiles/nuts_and_bolts_normal_down.png b/kicker/data/tiles/nuts_and_bolts_normal_down.png Binary files differnew file mode 100644 index 000000000..9a51c3a35 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_normal_down.png diff --git a/kicker/data/tiles/nuts_and_bolts_normal_up.png b/kicker/data/tiles/nuts_and_bolts_normal_up.png Binary files differnew file mode 100644 index 000000000..f966efcb9 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_normal_up.png diff --git a/kicker/data/tiles/nuts_and_bolts_tiny_down.png b/kicker/data/tiles/nuts_and_bolts_tiny_down.png Binary files differnew file mode 100644 index 000000000..97a990cb9 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_tiny_down.png diff --git a/kicker/data/tiles/nuts_and_bolts_tiny_up.png b/kicker/data/tiles/nuts_and_bolts_tiny_up.png Binary files differnew file mode 100644 index 000000000..63e962c02 --- /dev/null +++ b/kicker/data/tiles/nuts_and_bolts_tiny_up.png diff --git a/kicker/data/tiles/red_wood_large_down.png b/kicker/data/tiles/red_wood_large_down.png Binary files differnew file mode 100644 index 000000000..c066f1d94 --- /dev/null +++ b/kicker/data/tiles/red_wood_large_down.png diff --git a/kicker/data/tiles/red_wood_large_up.png b/kicker/data/tiles/red_wood_large_up.png Binary files differnew file mode 100644 index 000000000..646bb9c54 --- /dev/null +++ b/kicker/data/tiles/red_wood_large_up.png diff --git a/kicker/data/tiles/red_wood_normal_down.png b/kicker/data/tiles/red_wood_normal_down.png Binary files differnew file mode 100644 index 000000000..6091a488a --- /dev/null +++ b/kicker/data/tiles/red_wood_normal_down.png diff --git a/kicker/data/tiles/red_wood_normal_up.png b/kicker/data/tiles/red_wood_normal_up.png Binary files differnew file mode 100644 index 000000000..805f19a1d --- /dev/null +++ b/kicker/data/tiles/red_wood_normal_up.png diff --git a/kicker/data/tiles/red_wood_tiny_down.png b/kicker/data/tiles/red_wood_tiny_down.png Binary files differnew file mode 100644 index 000000000..6a2b31ee0 --- /dev/null +++ b/kicker/data/tiles/red_wood_tiny_down.png diff --git a/kicker/data/tiles/red_wood_tiny_up.png b/kicker/data/tiles/red_wood_tiny_up.png Binary files differnew file mode 100644 index 000000000..c2eb24b41 --- /dev/null +++ b/kicker/data/tiles/red_wood_tiny_up.png diff --git a/kicker/data/tiles/solid_blue_large_down.png b/kicker/data/tiles/solid_blue_large_down.png Binary files differnew file mode 100644 index 000000000..81f4f5391 --- /dev/null +++ b/kicker/data/tiles/solid_blue_large_down.png diff --git a/kicker/data/tiles/solid_blue_large_up.png b/kicker/data/tiles/solid_blue_large_up.png Binary files differnew file mode 100644 index 000000000..b815150cb --- /dev/null +++ b/kicker/data/tiles/solid_blue_large_up.png diff --git a/kicker/data/tiles/solid_blue_normal_down.png b/kicker/data/tiles/solid_blue_normal_down.png Binary files differnew file mode 100644 index 000000000..8fe6caea0 --- /dev/null +++ b/kicker/data/tiles/solid_blue_normal_down.png diff --git a/kicker/data/tiles/solid_blue_normal_up.png b/kicker/data/tiles/solid_blue_normal_up.png Binary files differnew file mode 100644 index 000000000..54dce1c53 --- /dev/null +++ b/kicker/data/tiles/solid_blue_normal_up.png diff --git a/kicker/data/tiles/solid_blue_tiny_down.png b/kicker/data/tiles/solid_blue_tiny_down.png Binary files differnew file mode 100644 index 000000000..c4a7559e8 --- /dev/null +++ b/kicker/data/tiles/solid_blue_tiny_down.png diff --git a/kicker/data/tiles/solid_blue_tiny_up.png b/kicker/data/tiles/solid_blue_tiny_up.png Binary files differnew file mode 100644 index 000000000..c6ad68fb2 --- /dev/null +++ b/kicker/data/tiles/solid_blue_tiny_up.png diff --git a/kicker/data/tiles/solid_gray_large_down.png b/kicker/data/tiles/solid_gray_large_down.png Binary files differnew file mode 100644 index 000000000..b90ea5edf --- /dev/null +++ b/kicker/data/tiles/solid_gray_large_down.png diff --git a/kicker/data/tiles/solid_gray_large_up.png b/kicker/data/tiles/solid_gray_large_up.png Binary files differnew file mode 100644 index 000000000..221c70060 --- /dev/null +++ b/kicker/data/tiles/solid_gray_large_up.png diff --git a/kicker/data/tiles/solid_gray_normal_down.png b/kicker/data/tiles/solid_gray_normal_down.png Binary files differnew file mode 100644 index 000000000..80418d7dd --- /dev/null +++ b/kicker/data/tiles/solid_gray_normal_down.png diff --git a/kicker/data/tiles/solid_gray_normal_up.png b/kicker/data/tiles/solid_gray_normal_up.png Binary files differnew file mode 100644 index 000000000..ecd4809f2 --- /dev/null +++ b/kicker/data/tiles/solid_gray_normal_up.png diff --git a/kicker/data/tiles/solid_gray_tiny_down.png b/kicker/data/tiles/solid_gray_tiny_down.png Binary files differnew file mode 100644 index 000000000..a230fd0b8 --- /dev/null +++ b/kicker/data/tiles/solid_gray_tiny_down.png diff --git a/kicker/data/tiles/solid_gray_tiny_up.png b/kicker/data/tiles/solid_gray_tiny_up.png Binary files differnew file mode 100644 index 000000000..24896cc7d --- /dev/null +++ b/kicker/data/tiles/solid_gray_tiny_up.png diff --git a/kicker/data/tiles/solid_green_large_down.png b/kicker/data/tiles/solid_green_large_down.png Binary files differnew file mode 100644 index 000000000..d5797dc47 --- /dev/null +++ b/kicker/data/tiles/solid_green_large_down.png diff --git a/kicker/data/tiles/solid_green_large_up.png b/kicker/data/tiles/solid_green_large_up.png Binary files differnew file mode 100644 index 000000000..09075cfb8 --- /dev/null +++ b/kicker/data/tiles/solid_green_large_up.png diff --git a/kicker/data/tiles/solid_green_normal_down.png b/kicker/data/tiles/solid_green_normal_down.png Binary files differnew file mode 100644 index 000000000..7a216a5de --- /dev/null +++ b/kicker/data/tiles/solid_green_normal_down.png diff --git a/kicker/data/tiles/solid_green_normal_up.png b/kicker/data/tiles/solid_green_normal_up.png Binary files differnew file mode 100644 index 000000000..c77e95c43 --- /dev/null +++ b/kicker/data/tiles/solid_green_normal_up.png diff --git a/kicker/data/tiles/solid_green_tiny_down.png b/kicker/data/tiles/solid_green_tiny_down.png Binary files differnew file mode 100644 index 000000000..6d3807e5b --- /dev/null +++ b/kicker/data/tiles/solid_green_tiny_down.png diff --git a/kicker/data/tiles/solid_green_tiny_up.png b/kicker/data/tiles/solid_green_tiny_up.png Binary files differnew file mode 100644 index 000000000..98245a2c5 --- /dev/null +++ b/kicker/data/tiles/solid_green_tiny_up.png diff --git a/kicker/data/tiles/solid_orange_large_down.png b/kicker/data/tiles/solid_orange_large_down.png Binary files differnew file mode 100644 index 000000000..00ee670da --- /dev/null +++ b/kicker/data/tiles/solid_orange_large_down.png diff --git a/kicker/data/tiles/solid_orange_large_up.png b/kicker/data/tiles/solid_orange_large_up.png Binary files differnew file mode 100644 index 000000000..a301c985e --- /dev/null +++ b/kicker/data/tiles/solid_orange_large_up.png diff --git a/kicker/data/tiles/solid_orange_normal_down.png b/kicker/data/tiles/solid_orange_normal_down.png Binary files differnew file mode 100644 index 000000000..447d425d0 --- /dev/null +++ b/kicker/data/tiles/solid_orange_normal_down.png diff --git a/kicker/data/tiles/solid_orange_normal_up.png b/kicker/data/tiles/solid_orange_normal_up.png Binary files differnew file mode 100644 index 000000000..666395837 --- /dev/null +++ b/kicker/data/tiles/solid_orange_normal_up.png diff --git a/kicker/data/tiles/solid_orange_tiny_down.png b/kicker/data/tiles/solid_orange_tiny_down.png Binary files differnew file mode 100644 index 000000000..be5e4b1ec --- /dev/null +++ b/kicker/data/tiles/solid_orange_tiny_down.png diff --git a/kicker/data/tiles/solid_orange_tiny_up.png b/kicker/data/tiles/solid_orange_tiny_up.png Binary files differnew file mode 100644 index 000000000..4b3217397 --- /dev/null +++ b/kicker/data/tiles/solid_orange_tiny_up.png diff --git a/kicker/data/tiles/solid_pastel_large_down.png b/kicker/data/tiles/solid_pastel_large_down.png Binary files differnew file mode 100644 index 000000000..fde6462e8 --- /dev/null +++ b/kicker/data/tiles/solid_pastel_large_down.png diff --git a/kicker/data/tiles/solid_pastel_large_up.png b/kicker/data/tiles/solid_pastel_large_up.png Binary files differnew file mode 100644 index 000000000..191522e59 --- /dev/null +++ b/kicker/data/tiles/solid_pastel_large_up.png diff --git a/kicker/data/tiles/solid_pastel_normal_down.png b/kicker/data/tiles/solid_pastel_normal_down.png Binary files differnew file mode 100644 index 000000000..04f0b70d5 --- /dev/null +++ b/kicker/data/tiles/solid_pastel_normal_down.png diff --git a/kicker/data/tiles/solid_pastel_normal_up.png b/kicker/data/tiles/solid_pastel_normal_up.png Binary files differnew file mode 100644 index 000000000..c1cd9d1d9 --- /dev/null +++ b/kicker/data/tiles/solid_pastel_normal_up.png diff --git a/kicker/data/tiles/solid_pastel_tiny_down.png b/kicker/data/tiles/solid_pastel_tiny_down.png Binary files differnew file mode 100644 index 000000000..5ac0212cc --- /dev/null +++ b/kicker/data/tiles/solid_pastel_tiny_down.png diff --git a/kicker/data/tiles/solid_pastel_tiny_up.png b/kicker/data/tiles/solid_pastel_tiny_up.png Binary files differnew file mode 100644 index 000000000..52078b2b5 --- /dev/null +++ b/kicker/data/tiles/solid_pastel_tiny_up.png diff --git a/kicker/data/tiles/solid_purple_large_down.png b/kicker/data/tiles/solid_purple_large_down.png Binary files differnew file mode 100644 index 000000000..af85fb076 --- /dev/null +++ b/kicker/data/tiles/solid_purple_large_down.png diff --git a/kicker/data/tiles/solid_purple_large_up.png b/kicker/data/tiles/solid_purple_large_up.png Binary files differnew file mode 100644 index 000000000..12146c4cb --- /dev/null +++ b/kicker/data/tiles/solid_purple_large_up.png diff --git a/kicker/data/tiles/solid_purple_normal_down.png b/kicker/data/tiles/solid_purple_normal_down.png Binary files differnew file mode 100644 index 000000000..4406a3eff --- /dev/null +++ b/kicker/data/tiles/solid_purple_normal_down.png diff --git a/kicker/data/tiles/solid_purple_normal_up.png b/kicker/data/tiles/solid_purple_normal_up.png Binary files differnew file mode 100644 index 000000000..b1fc8da6b --- /dev/null +++ b/kicker/data/tiles/solid_purple_normal_up.png diff --git a/kicker/data/tiles/solid_purple_tiny_down.png b/kicker/data/tiles/solid_purple_tiny_down.png Binary files differnew file mode 100644 index 000000000..6badb34c1 --- /dev/null +++ b/kicker/data/tiles/solid_purple_tiny_down.png diff --git a/kicker/data/tiles/solid_purple_tiny_up.png b/kicker/data/tiles/solid_purple_tiny_up.png Binary files differnew file mode 100644 index 000000000..ce3dcfb05 --- /dev/null +++ b/kicker/data/tiles/solid_purple_tiny_up.png diff --git a/kicker/data/tiles/solid_red_large_down.png b/kicker/data/tiles/solid_red_large_down.png Binary files differnew file mode 100644 index 000000000..2ed284974 --- /dev/null +++ b/kicker/data/tiles/solid_red_large_down.png diff --git a/kicker/data/tiles/solid_red_large_up.png b/kicker/data/tiles/solid_red_large_up.png Binary files differnew file mode 100644 index 000000000..35f60bb23 --- /dev/null +++ b/kicker/data/tiles/solid_red_large_up.png diff --git a/kicker/data/tiles/solid_red_normal_down.png b/kicker/data/tiles/solid_red_normal_down.png Binary files differnew file mode 100644 index 000000000..1d1069c31 --- /dev/null +++ b/kicker/data/tiles/solid_red_normal_down.png diff --git a/kicker/data/tiles/solid_red_normal_up.png b/kicker/data/tiles/solid_red_normal_up.png Binary files differnew file mode 100644 index 000000000..87e08e59d --- /dev/null +++ b/kicker/data/tiles/solid_red_normal_up.png diff --git a/kicker/data/tiles/solid_red_tiny_down.png b/kicker/data/tiles/solid_red_tiny_down.png Binary files differnew file mode 100644 index 000000000..722e872bc --- /dev/null +++ b/kicker/data/tiles/solid_red_tiny_down.png diff --git a/kicker/data/tiles/solid_red_tiny_up.png b/kicker/data/tiles/solid_red_tiny_up.png Binary files differnew file mode 100644 index 000000000..82e086f58 --- /dev/null +++ b/kicker/data/tiles/solid_red_tiny_up.png diff --git a/kicker/data/tiles/solid_tigereye_large_down.png b/kicker/data/tiles/solid_tigereye_large_down.png Binary files differnew file mode 100644 index 000000000..118e6f85a --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_large_down.png diff --git a/kicker/data/tiles/solid_tigereye_large_up.png b/kicker/data/tiles/solid_tigereye_large_up.png Binary files differnew file mode 100644 index 000000000..e36984860 --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_large_up.png diff --git a/kicker/data/tiles/solid_tigereye_normal_down.png b/kicker/data/tiles/solid_tigereye_normal_down.png Binary files differnew file mode 100644 index 000000000..dc0f7ab14 --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_normal_down.png diff --git a/kicker/data/tiles/solid_tigereye_normal_up.png b/kicker/data/tiles/solid_tigereye_normal_up.png Binary files differnew file mode 100644 index 000000000..9f691df5a --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_normal_up.png diff --git a/kicker/data/tiles/solid_tigereye_tiny_down.png b/kicker/data/tiles/solid_tigereye_tiny_down.png Binary files differnew file mode 100644 index 000000000..0b5e242c8 --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_tiny_down.png diff --git a/kicker/data/tiles/solid_tigereye_tiny_up.png b/kicker/data/tiles/solid_tigereye_tiny_up.png Binary files differnew file mode 100644 index 000000000..f086cc329 --- /dev/null +++ b/kicker/data/tiles/solid_tigereye_tiny_up.png diff --git a/kicker/data/wallpaper/Makefile.am b/kicker/data/wallpaper/Makefile.am new file mode 100644 index 000000000..1ef71c18c --- /dev/null +++ b/kicker/data/wallpaper/Makefile.am @@ -0,0 +1,7 @@ + +kicker_wallpaper_data_DATA = default.png deck_plate.png green_line.png rail.png + +kicker_wallpaper_datadir = $(kde_datadir)/kicker/wallpapers + +EXTRA_DIST = $(kicker_wallpaper_data_DATA) + diff --git a/kicker/data/wallpaper/deck_plate.png b/kicker/data/wallpaper/deck_plate.png Binary files differnew file mode 100644 index 000000000..f79be9c12 --- /dev/null +++ b/kicker/data/wallpaper/deck_plate.png diff --git a/kicker/data/wallpaper/default.png b/kicker/data/wallpaper/default.png Binary files differnew file mode 100644 index 000000000..0c9c1810c --- /dev/null +++ b/kicker/data/wallpaper/default.png diff --git a/kicker/data/wallpaper/green_line.png b/kicker/data/wallpaper/green_line.png Binary files differnew file mode 100644 index 000000000..43a34599c --- /dev/null +++ b/kicker/data/wallpaper/green_line.png diff --git a/kicker/data/wallpaper/rail.png b/kicker/data/wallpaper/rail.png Binary files differnew file mode 100644 index 000000000..6b558cdba --- /dev/null +++ b/kicker/data/wallpaper/rail.png diff --git a/kicker/extensions/Makefile.am b/kicker/extensions/Makefile.am new file mode 100644 index 000000000..bf9475c3f --- /dev/null +++ b/kicker/extensions/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = dockbar taskbar kasbar sidebar diff --git a/kicker/extensions/dockbar/Makefile.am b/kicker/extensions/dockbar/Makefile.am new file mode 100644 index 000000000..6d2f20546 --- /dev/null +++ b/kicker/extensions/dockbar/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = dockbar_panelextension.la + +dockbar_panelextension_la_SOURCES = dockcontainer.cpp dockbarextension.cpp +dockbar_panelextension_la_METASOURCES = AUTO +dockbar_panelextension_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +dockbar_panelextension_la_LIBADD = $(LIB_KDEUI) + +noinst_HEADERS = dockcontainer.h dockbarextension.h + +lnkdir = $(kde_datadir)/kicker/extensions +lnk_DATA = dockbarextension.desktop + +EXTRA_DIST = $(lnk_DATA) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/dockbarextension.pot diff --git a/kicker/extensions/dockbar/dockbarextension.cpp b/kicker/extensions/dockbar/dockbarextension.cpp new file mode 100644 index 000000000..71b583f35 --- /dev/null +++ b/kicker/extensions/dockbar/dockbarextension.cpp @@ -0,0 +1,423 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#undef Bool // For enable-final +#include <klocale.h> +#include <kwinmodule.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kprocess.h> +#include <kshell.h> +#include <kwin.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <kglobal.h> + +#include "dockbarextension.h" +#include "dockbarextension.moc" + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +extern "C" +{ + KDE_EXPORT KPanelExtension* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("dockbarextension"); + return new DockBarExtension(configFile, KPanelExtension::Normal, + 0, parent, "dockbarextension"); + } +} + +DockBarExtension::DockBarExtension(const QString& configFile, Type type, + int actions, QWidget *parent, const char *name) + : KPanelExtension(configFile, type, actions, parent, name) +{ + dragging_container = 0; + kwin_module = new KWinModule(this); + connect( kwin_module, SIGNAL( windowAdded(WId) ), SLOT( windowAdded(WId) ) ); + setMinimumSize(DockContainer::sz(), DockContainer::sz()); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + loadContainerConfig(); +} + +DockBarExtension::~DockBarExtension() +{ + // kill nicely the applets + for (DockContainer::Vector::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + (*it)->kill(); + } + + if (dragging_container) delete dragging_container; +} + +QSize DockBarExtension::sizeHint(Position p, QSize) const +{ + if (p == Left || p == Right) + return QSize(DockContainer::sz(), DockContainer::sz() * containers.count()); + else + return QSize(DockContainer::sz() * containers.count(), DockContainer::sz()); +} + +void DockBarExtension::resizeEvent(QResizeEvent*) +{ + layoutContainers(); +} + + +void DockBarExtension::windowAdded(WId win) +{ + // try to read WM_COMMAND + int argc; + char **argv; + QString command; + if (XGetCommand(qt_xdisplay(), win, &argv, &argc)) { + command = KShell::joinArgs(argv, argc); + XFreeStringList(argv); + } + + // try to read wm hints + WId resIconwin = 0; + XWMHints *wmhints = XGetWMHints(qt_xdisplay(), win); + if (0 != wmhints) { // we managed to read wm hints + // read IconWindowHint + bool is_valid = false; + /* a good dockapp set the icon hint and the state hint, + if it uses its icon, the window initial state must be "withdrawn" + if not, then the initial state must be "normal" + this filters the problematic Eterm whose initial state is "normal" + and which has an iconwin. + */ + if ((wmhints->flags & IconWindowHint) && + (wmhints->flags & StateHint)) { + resIconwin = wmhints->icon_window; + is_valid = (resIconwin && wmhints->initial_state == 0) || + (resIconwin == 0 && wmhints->initial_state == 1); + + /* an alternative is a window who does not have an icon, + but whose initial state is set to "withdrawn". This has been + added for wmxmms... I hope it won't swallow to much windows :-/ + */ + } else if ((wmhints->flags & IconWindowHint) == 0 && + (wmhints->flags & StateHint)) { + is_valid = (wmhints->initial_state == 0); + } + XFree(wmhints); + if (!is_valid) + return; // we won't swallow this one + } + else + return; + + // The following if statement was at one point commented out, + // without a comment as to why. This caused problems like + // Eterm windows getting swallowed whole. So, perhaps now I'll + // get bug reports about whatever commenting it out was supposed + // to fix. + if (resIconwin == 0) + resIconwin = win; + + // try to read class hint + XClassHint hint; + QString resClass, resName; + if (XGetClassHint(qt_xdisplay(), win, &hint)) { + resName = hint.res_name; + resClass = hint.res_class; + } + else { + kdDebug() << "Could not read XClassHint of window " << win << endl; + return; + } + /* withdrawing the window prevents kwin from managing the window, + which causes the double-launch bug (one instance from the kwin + session, and one from the dockbar) bug when kde is restarted */ + if (resIconwin != win) { + XWithdrawWindow( qt_xdisplay(), win, qt_xscreen() ); + while( KWin::windowInfo(win, NET::XAWMState).mappingState() != NET::Withdrawn ); + } + + // add a container + embedWindow(resIconwin, command, resName, resClass); + saveContainerConfig(); +} + +void DockBarExtension::layoutContainers() +{ + int i = 0; + for (DockContainer::Vector::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + if (orientation() == Horizontal) + (*it)->move(DockContainer::sz() * i, 0); + else + (*it)->move(0, DockContainer::sz() * i); + i++; + } +} + +void DockBarExtension::embedWindow(WId win, QString command, QString resName, QString resClass) +{ + if (win == 0) return; + DockContainer* container = 0; + bool ncmd = false; + + for (DockContainer::Vector::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + DockContainer* c = *it; + if (c->embeddedWinId() == 0 && + c->resName() == resName && + c->resClass() == resClass && + (command.isNull() || c->command() == command)) + { + container = c; + break; + } + } + + if (container == 0) { + QString cmd = command.isNull() ? resClass : command; + if (KStandardDirs::findExe(KShell::splitArgs(cmd).front()).isEmpty()) + ncmd = true; + container = new DockContainer(cmd, this, resName, resClass); + addContainer(container); + } + + container->embed(win); + layoutContainers(); + emit updateLayout(); + if (ncmd) + container->askNewCommand(); + } + +void DockBarExtension::addContainer(DockContainer* c, int pos) +{ + if (pos == -1) + { + containers.append(c); + } + else + { + DockContainer::Vector::iterator it = containers.begin(); + + for (int i = 0; i < pos && it != containers.end(); ++i) + { + ++it; + } + ++it; + + containers.insert(it, c); + } + connect(c, SIGNAL(embeddedWindowDestroyed(DockContainer*)), + SLOT(embeddedWindowDestroyed(DockContainer*))); + connect(c, SIGNAL(settingsChanged(DockContainer*)), + SLOT(settingsChanged(DockContainer*))); + c->resize(DockContainer::sz(), DockContainer::sz()); + c->show(); +} + +void DockBarExtension::removeContainer(DockContainer* c) +{ + DockContainer::Vector::iterator it = qFind(containers.begin(), containers.end(), c); + + if (it == containers.end()) + { + return; + } + + containers.erase(it); + delete c; + layoutContainers(); +} + +void DockBarExtension::embeddedWindowDestroyed(DockContainer* c) +{ + removeContainer(c); + saveContainerConfig(); + emit updateLayout(); +} + +void DockBarExtension::settingsChanged(DockContainer *) +{ + saveContainerConfig(); +} + +void DockBarExtension::saveContainerConfig() +{ + QStringList applet_list; + KConfig *conf = config(); + unsigned count = 0; + + for (DockContainer::Vector::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + DockContainer* c = *it; + if (!c->command().isEmpty()) + { + QString applet_gid = QString("Applet_%1").arg(QString::number(count)); + applet_list.append(applet_gid); + conf->setGroup(applet_gid); + conf->writePathEntry("Command", c->command()); + conf->writePathEntry("resName", c->resName()); + conf->writeEntry("resClass", c->resClass()); + ++count; + } + } + conf->setGroup("General"); + conf->writeEntry("Applets", applet_list); + conf->deleteEntry("Commands"); // cleanup old config + conf->sync(); +} + +void DockBarExtension::loadContainerConfig() +{ + KConfig *conf = config(); + conf->setGroup("General"); + QStringList applets = conf->readListEntry("Applets"); + + QStringList fail_list; + for (QStringList::Iterator it = applets.begin(); it != applets.end(); ++it) { + if (!conf->hasGroup(*it)) continue; + conf->setGroup(*it); + QString cmd = conf->readPathEntry("Command"); + QString resName = conf->readPathEntry("resName"); + QString resClass = conf->readEntry("resClass"); + if (cmd.isEmpty() || resName.isEmpty() || resClass.isEmpty()) continue; + + DockContainer* c = new DockContainer(cmd, this, resName, resClass ); + addContainer(c); + + KProcess proc; + proc << KShell::splitArgs( cmd ); + if (!proc.start(KProcess::DontCare)) { + fail_list.append(cmd); + removeContainer(c); + } + } + if (!fail_list.isEmpty()) + KMessageBox::queuedMessageBox(0, KMessageBox::Information, i18n("The following dockbar applets could not be started: %1").arg(fail_list.join(", ")), i18n("kicker: information"), 0); + saveContainerConfig(); +} + +int DockBarExtension::findContainerAtPoint(const QPoint& p) +{ + int i = 0; + for (DockContainer::Vector::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it, ++i) + { + if ((*it)->geometry().contains(p)) + { + return i; + } + } + + return -1; +} + +void DockBarExtension::mousePressEvent(QMouseEvent *e ) { + if (e->button() == LeftButton) { + // Store the position of the mouse clic. + mclic_pos = e->pos(); + } else if (e->button() == RightButton) { + int pos = findContainerAtPoint(e->pos()); + if (pos != -1) containers.at(pos)->popupMenu(e->globalPos()); + } +} + +void DockBarExtension::mouseReleaseEvent(QMouseEvent *e ) { + if (e->button() != LeftButton) return; + if (dragging_container) { + releaseMouse(); + original_container->embed(dragging_container->embeddedWinId()); + delete dragging_container; dragging_container = 0; + layoutContainers(); + saveContainerConfig(); + } +} + +void DockBarExtension::mouseMoveEvent(QMouseEvent *e) { + if (! (e->state() & LeftButton) ) return; + if (dragging_container == 0) { + // Check whether the user has moved far enough. + int delay = QApplication::startDragDistance(); + if ( (mclic_pos - e->pos()).manhattanLength() > delay ) { + int pos = findContainerAtPoint(e->pos()); + original_container = 0; + if (pos > -1) { + original_container = containers.at(pos); + mclic_dock_pos = e->pos() - original_container->pos(); + dragged_container_original_pos = pos; + dragging_container = new DockContainer(original_container->command(), 0, original_container->resName(), original_container->resClass(), true); + dragging_container->show(); + dragging_container->embed(original_container->embeddedWinId()); + grabMouse(); + } + } + } + if (dragging_container) { + dragging_container->move(e->globalPos() - mclic_dock_pos); + + // change layout of other containers + QPoint dragpos(dragging_container->pos()), + barpos(mapToGlobal(pos())); + int pdrag1,pdrag2,psz; + pdrag1 = dragpos.x() - barpos.x() + DockContainer::sz()/2; + pdrag2 = dragpos.y() - barpos.y() + DockContainer::sz()/2; + if (orientation() == Vertical) { + int tmp = pdrag1; pdrag1 = pdrag2; pdrag2 = tmp; + psz = height(); + } else psz = width(); + if (pdrag2 >= 0 && pdrag2 < DockContainer::sz() && pdrag1 >= 0 && pdrag1 < psz) + pdrag1 /= DockContainer::sz(); + else + pdrag1 = dragged_container_original_pos; + + + DockContainer::Vector::iterator it = qFind(containers.begin(), containers.end(), original_container); + + if (it == containers.end()) + { + return; + } + + DockContainer::Vector::iterator target = containers.begin(); + for (int i = 0; i < pdrag1 && target != containers.end(); ++i) + { + ++target; + } + + containers.erase(it); + containers.insert(target, original_container); + layoutContainers(); + } +} diff --git a/kicker/extensions/dockbar/dockbarextension.desktop b/kicker/extensions/dockbar/dockbarextension.desktop new file mode 100644 index 000000000..53dff4bb0 --- /dev/null +++ b/kicker/extensions/dockbar/dockbarextension.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Name=Dock Application Bar +Name[af]=Vasmeer Program Balk +Name[az]=Proqram ÇubuÄŸunu Yapışdır +Name[be]=Ðплет ÑƒÐ±ÑƒÐ´Ð¾ÑžÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð°Ñž +Name[bg]=Допълнителен панел +Name[bn]=ডক অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨ বার +Name[bs]=Traka za dokiranje aplikacija +Name[ca]=Barra per ancorar aplicacions +Name[cs]=LiÅ¡ta pro dokovánà aplikacà +Name[csb]=Lëstew przërzeszaniô programów +Name[cy]=Docio'r Bar Cymhwysiad +Name[da]=Dok programlinje +Name[de]=Programm-Andockleiste +Name[el]=ΓÏαμμή Ï€ÏοσαÏτημÎνων εφαÏμογών +Name[eo]=Aplikaĵostrio +Name[es]=Barra para anclar aplicaciones +Name[et]=Dokitavate rakenduste riba +Name[eu]=Aplikazioak ainguratzeko barra +Name[fa]=میله کاربرد پیوند +Name[fi]=Upotettava ohjelmapalkki +Name[fr]=Barre de stockage des applications +Name[fy]=Ekstra systeemfak +Name[gl]=Acoplar Barra de Aplicación +Name[he]=מעגן ×™×™×©×•×ž×™× +Name[hi]=अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤— पटà¥à¤Ÿà¥€ डॉक करें +Name[hr]=Usidravanje trake aplikacija +Name[hu]=Alkalmazásdokkoló +Name[id]=Aplikasi Dock bar +Name[is]=Kvà fyrir forrit +Name[it]=Barra per le applicazioni Dock +Name[ja]=ドックアプリケーションãƒãƒ¼ +Name[kk]=Қолданбаларды тіркеу панелі +Name[km]=របារ​កម្មវិធី​ចូលផែ +Name[ko]=KDE ì‘ìš© 프로그램 +Name[lo]=à»àº–ບພັàºà»àºàºšàºžàºµà»€àº„ຊັ້ນ +Name[lt]=Pritvirtintų programų juosta +Name[lv]=Dokot AplikÄciju Joslu +Name[mk]=Лента за вкотвување на апликации +Name[mn]=Програм-шигтгÑÑ… Ñамбар +Name[ms]=Bar Aplikasi Dok +Name[mt]=Waħħal il-bar tal-programmi +Name[nb]=Festet programlinje +Name[nds]=Andockbalken +Name[ne]=डक अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—पटà¥à¤Ÿà¥€ +Name[nl]=Extra systeemvak +Name[nn]=Dokka programlinje +Name[nso]=Bar ya Tshomiso ya Dock +Name[pa]=ਡੋਕ ਕਾਰਜ ਪੱਟੀ +Name[pl]=Pasek dokowania programów +Name[pt]=Barra de Aplicações Acopláveis +Name[pt_BR]=Barra de aplicativos integrados +Name[ro]=Bară de docare aplicaÈ›ii +Name[ru]=Панель Ð´Ð»Ñ Ð²ÑÑ‚Ñ€Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹ +Name[rw]=Umurongo Porogaramu Bikomatanye +Name[se]=Vuojuhuvvon prográmmaid holga +Name[sk]=Panel na dokovanie aplikácià +Name[sl]=Vrstica za zasidranje programov +Name[sr]=Трака за приÑтајање програма +Name[sr@Latn]=Traka za pristajanje programa +Name[sv]=Programdocka +Name[ta]=டாக௠பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ படà¯à®Ÿà®¿ +Name[tg]=Ðавори барномаи обзор +Name[th]=à¹à¸–บพัà¸à¹à¸à¸žà¸žà¸¥à¸´à¹€à¸„ชัน +Name[tr]=Uygulama çubuÄŸunu gizle +Name[tt]=Yazılım Utırtu Taqtası +Name[uk]=Док-панель Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼ +Name[vi]=Bến Ä‘á»— Thanh ChÆ°Æ¡ng trình +Name[wa]=BÃ¥r di wÃ¥rdaedje des programes +Name[xh]=Ibar Yesicelo ye Dock +Name[zh_CN]=åœé 应用程åºæ +Name[zh_TW]=嵌入程å¼å·¥å…·åˆ— +Name[zu]=Ibha Yomyaleli we-Dock +Comment=Dock application bar extension. +Comment[af]=Vasmeer program balk uitbreidings +Comment[az]=Proqram çubuÄŸu uzantısını gizlÉ™t. +Comment[be]=ПашырÑнне Ð´Ð»Ñ ÑžÐ±ÑƒÐ´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ð°Ñž у панÑль. +Comment[bg]=Разширение на ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð¿Ð°Ð½ÐµÐ» +Comment[bn]=ডক অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨ বার à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨ +Comment[bs]=ProÅ¡irenje za dokiranje aplikacija +Comment[ca]=Una extensió de la barra per ancorar aplicacions. +Comment[cs]=RozÅ¡ÃÅ™enà liÅ¡ty pro dokovánà aplikacÃ. +Comment[csb]=Rozszérzenié do przërzeszaniô programów. +Comment[cy]=Docio estyniad y bar cymhwysiad +Comment[da]=Udvidelse - dok programlinje. +Comment[de]=Eine Andockleiste für Programme +Comment[el]=ΕπÎκταση γÏαμμής Ï€ÏοσαÏτημÎνων εφαÏμογών. +Comment[eo]=Aplikaĵostria aldono +Comment[es]=Extensión Barra para anclar aplicaciones. +Comment[et]=Paneeli laiendus dokitavate rakenduste hoidmiseks +Comment[eu]=Aplikazioak ainguratzeko barraren hedapena +Comment[fa]=پسوند میله کاربرد پیوند. +Comment[fi]=Upota ohjelmapalkkilaajennus +Comment[fr]=Stockage des applications dans une barre. +Comment[fy]=In balke wêryn tapassingen hun byldkaike kinne pleatse +Comment[gl]=Extensión de acoplamento de barras de aplicación +Comment[he]=הרחבת מעגן ×™×™×©×•×ž×™× +Comment[hi]=अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤— पटà¥à¤Ÿà¥€ विसà¥à¤¤à¤¾à¤° डॉक करें +Comment[hr]=ProÅ¡irenje za usidravanje aplikacija +Comment[hu]=Alkalmazásdokkoló kiterjesztés. +Comment[id]=Panel dock ektensi untuk aplikasi +Comment[is]=ÚtvÃkkun kvÃar fyrir Ãsett forrit. +Comment[it]=Estensione per la barra delle applicazioni Dock. +Comment[ja]=アプリケーション用ã®ãƒ‰ãƒƒã‚¯ãƒ‘ãƒãƒ« +Comment[kk]=Қолданбаларды тіркеу үшін панель. +Comment[km]=ផ្នែក​បន្ážáŸ‚ម​របារ​កម្មវិធី​ចូលផែ ។ +Comment[lo]=ສ່ວນຂະຫàºàº²àºà»€àºžàºµà»‰àº™àº•àº·à»ˆàº¡àºžàº²à»€àº™àº¥à»àº–ລພັàºà»àºàº¥àºžàºµà»€àº„ຊັ້ນ +Comment[lt]=Pritvirtintų programų juostos plÄ—tinys. +Comment[lv]=Doko aplikÄciju joslas paplaÅ¡inÄjumu. +Comment[mk]=ЕкÑтензија за вкотвување на апликации. +Comment[mn]=Програмын шигтгÑÑ Ñамбар өргөтгөл +Comment[ms]=Lanjutan bar aplikasi dok. +Comment[mt]=Estensjoni biex twaħħal il-bar tal-programmi. +Comment[nb]=Festepanel for programmer +Comment[nds]=Andockbalken för Programmen +Comment[ne]=डक अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—पटà¥à¤Ÿà¥€ विसà¥à¤¤à¤¾à¤° +Comment[nl]=Een balk waarin toepassingen hun pictogram kunnen plaatsen +Comment[nn]=Dokkingspanel for program +Comment[nso]=Koketso ya bar ya tshomiso ya dock. +Comment[pa]=ਡੋਕ ਕਾਰਜ ਪੱਟੀ ਵਧਾਰਾ ਹੈ। +Comment[pl]=Rozszerzenie do dokowania programów. +Comment[pt]=Uma extensão de barra de aplicações acopláveis. +Comment[pt_BR]=Extensão da barra de aplicativos embutidos. +Comment[ro]=Extensie bară de docare aplicaÈ›ii. +Comment[ru]=РаÑширение панели Ð´Ð»Ñ Ð²ÑÑ‚Ñ€Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹. +Comment[rw]=Iyagura ry'umurongo w'ikomatanya porogaramu +Comment[se]=Prográmmaid vuojuhanpanela +Comment[sk]=RozÅ¡Ãrenie pre dokovacà panel aplikácià +Comment[sl]=RazÅ¡iritev za sidriÅ¡Äe programov. +Comment[sr]=Проширење траке за приÑтајање програма. +Comment[sr@Latn]=ProÅ¡irenje trake za pristajanje programa. +Comment[sv]=Bygger ut med en programdocka +Comment[ta]=டாக௠பயனà¯à®ªà®¾à®Ÿà¯ படà¯à®Ÿà®¿ விரிவாகà¯à®•à®®à¯ +Comment[tg]=Кушодкунии панел барои бино кунӣ. +Comment[th]=ส่วนขยายเพิ่มเติมพาเนล à¹à¸–บพัà¸à¹à¸à¸žà¸žà¸¥à¸´à¹€à¸„ชัน +Comment[tr]=Uygulama çubuÄŸu uzantısını gizle. +Comment[tt]=Yazılım utırtuçı taqta östämäse. +Comment[uk]=Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾Ðº-панелі Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼. +Comment[vi]=Bến Ä‘á»— các thanh chÆ°Æ¡ng trình mở rá»™ng +Comment[wa]=Module di bÃ¥r di wÃ¥rdaedje des programes +Comment[xh]=Ulwandiso lwe bar yesicelo se Dock. +Comment[zh_CN]=åœé 应用程åºæ 扩展。 +Comment[zh_TW]=嵌入延伸程å¼å·¥å…·åˆ— +Comment[zu]=Isandiso sebha Yomyaleli we-Dock + +Icon=dockbar +X-KDE-Library=dockbar_panelextension +X-KDE-UniqueApplet=true diff --git a/kicker/extensions/dockbar/dockbarextension.h b/kicker/extensions/dockbar/dockbarextension.h new file mode 100644 index 000000000..0003ec6fa --- /dev/null +++ b/kicker/extensions/dockbar/dockbarextension.h @@ -0,0 +1,73 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __dockbarextension_h__ +#define __dockbarextension_h__ + +#include <qvaluevector.h> +#include <kpanelextension.h> +#include "dockcontainer.h" + +class KWinModule; + +class DockBarExtension : public KPanelExtension +{ + Q_OBJECT + +public: + DockBarExtension(const QString& configFile, Type t = Normal, + int actions = 0, QWidget *parent = 0, const char *name = 0); + + virtual ~DockBarExtension(); + + QSize sizeHint(Position, QSize maxSize) const; + Position preferedPosition() const { return Right; } + +protected slots: + void windowAdded(WId); + void embeddedWindowDestroyed(DockContainer*); + void settingsChanged(DockContainer*); + +protected: + void resizeEvent(QResizeEvent*); + void embedWindow(WId win, QString command, QString resName, QString resClass); + void addContainer(DockContainer*, int pos=-1); + void removeContainer(DockContainer*); + void saveContainerConfig(); + void loadContainerConfig(); + void layoutContainers(); + int findContainerAtPoint(const QPoint&); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); +private: + KWinModule* kwin_module; + DockContainer::Vector containers; + + // handle the dragging of applets + DockContainer *dragging_container, *original_container; + QPoint mclic_pos, mclic_dock_pos; + int dragged_container_original_pos; +}; + +#endif diff --git a/kicker/extensions/dockbar/dockcontainer.cpp b/kicker/extensions/dockbar/dockcontainer.cpp new file mode 100644 index 000000000..f2117346d --- /dev/null +++ b/kicker/extensions/dockbar/dockcontainer.cpp @@ -0,0 +1,198 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qwidget.h> +#include <qtooltip.h> +#include <kwin.h> +#include <qvalidator.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kdebug.h> + +#include "dockcontainer.h" +#include "dockcontainer.moc" + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + + +DockContainer::DockContainer( QString command, QWidget *parent, + QString resname, QString resclass, bool undocked_style ) + : QFrame( parent, resname.ascii(), + undocked_style ? WStyle_Customize | + WStyle_StaysOnTop | WStyle_Tool | + WStyle_NoBorder | WX11BypassWM : 0 ), + _embeddedWinId(0), + _command(command), + _resName(resname), + _resClass(resclass) +{ + XSelectInput( qt_xdisplay(), winId(), + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | + KeymapStateMask | + ButtonMotionMask | + PointerMotionMask | + EnterWindowMask | LeaveWindowMask | + FocusChangeMask | + ExposureMask | + StructureNotifyMask | + SubstructureRedirectMask | + SubstructureNotifyMask ); + if (!undocked_style) { + setFrameStyle(StyledPanel | Raised); + setLineWidth(border()); + QToolTip::add(this, command); + } else { + setFrameStyle(StyledPanel | Plain); + setLineWidth(1); + } + resize(sz(),sz()); +} + +void DockContainer::embed( WId id ) +{ + if( id == _embeddedWinId || id == 0) + return; + QRect geom = KWin::windowInfo(id,NET::WMKDEFrameStrut).frameGeometry(); + + // does the same as KWM::prepareForSwallowing() + XWithdrawWindow( qt_xdisplay(), id, qt_xscreen() ); + while( KWin::windowInfo(id, NET::XAWMState).mappingState() != NET::Withdrawn ); + + XReparentWindow( qt_xdisplay(), id, winId(), 0, 0 ); + + // resize if window is bigger than frame + if( (geom.width() > width()) || + (geom.height() > height()) ) + XResizeWindow( qt_xdisplay(), id, width(), height() ); + else + XMoveWindow(qt_xdisplay(), id, + (sz() - geom.width())/2 - border(), + (sz() - geom.height())/2 - border()); + XMapWindow( qt_xdisplay(), id ); + XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() ); + + _embeddedWinId = id; +} + +void DockContainer::unembed() +{ + if( _embeddedWinId ) + XReparentWindow( qt_xdisplay(), _embeddedWinId, qt_xrootwin(), 0, 0 ); +} + +void DockContainer::kill() +{ + if ( _embeddedWinId ) { + XKillClient( qt_xdisplay(), _embeddedWinId ); + _embeddedWinId = 0; // in case the window does not exist anymore.. + } + else emit embeddedWindowDestroyed(this); /* enable killing of empty windows.. */ +} + +bool DockContainer::x11Event( XEvent *e ) +{ + switch( e->type ) { + case DestroyNotify: + if( e->xdestroywindow.window == _embeddedWinId || _embeddedWinId == 0) { + _embeddedWinId = 0; + emit embeddedWindowDestroyed(this); + } + break; + case UnmapNotify: + if ( e->xunmap.window == _embeddedWinId ) { + kdDebug() << "Unmap Notify !!! I hate smart dockapps as wmpinboard " << command() << endl; + _embeddedWinId = 0; + } + break; + case ReparentNotify: + if( _embeddedWinId && + (e->xreparent.window == _embeddedWinId) && + (e->xreparent.parent != winId()) ) { + _embeddedWinId = 0; + } + else if( e->xreparent.parent == winId() ) { + _embeddedWinId = e->xreparent.window; + embed( _embeddedWinId ); + } + break; + } + + return false; +} + +void DockContainer::askNewCommand(bool bad_command) +{ + bool ok; + QString title( i18n("Enter Command Line for Applet %1.%2").arg(resName()).arg(resClass()) ); + QString description( i18n("This applet does not behave correctly and the dockbar was unable to " + "find the command line necessary to launch it the next time KDE starts up") ); + QString cmd; + + /* + I was not able to figure out why valgrind complains inside the getText call.. + (invalid read of size 1 in Xmb.. functions) + */ + if (bad_command) { + cmd = KInputDialog::getText( title, description, + command(), &ok, this ); + } else { + cmd = KInputDialog::getText( title, QString::null, + command(), &ok, this ); + } + if (ok) { _command = cmd; emit settingsChanged(this); } +} + +void DockContainer::popupMenu(QPoint p) +{ + int r; + { + KPopupMenu pm(this); + pm.insertItem( i18n("Kill This Applet"), 0); + pm.insertItem( i18n("Change Command"), 1); + r = pm.exec(p); + /* pm is destroyed now .. if it is destroyed later, + there is a risk that kill() double-frees it */ + } + switch (r) { + case 0: { + kill(); + } break; + case 1: { + askNewCommand(false); + } break; + } +} + +int& DockContainer::sz() { + static int _sz = 66; + return _sz; +} + +int& DockContainer::border() { + static int _border = 1; + return _border; +} diff --git a/kicker/extensions/dockbar/dockcontainer.h b/kicker/extensions/dockbar/dockcontainer.h new file mode 100644 index 000000000..bc9962290 --- /dev/null +++ b/kicker/extensions/dockbar/dockcontainer.h @@ -0,0 +1,90 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __dockcontainer_h__ +#define __dockcontainer_h__ + +#include <qframe.h> +#include <qvaluevector.h> + +class DockContainer : public QFrame +{ + Q_OBJECT + +public: + typedef QValueVector<DockContainer*> Vector; + + DockContainer( QString command, QWidget *parent, + QString resname, + QString resclass, + bool undocked_style=false); + + void embed(WId); + void unembed(); + void kill(); + + WId embeddedWinId() const; + QString command() const; + QString resClass() const; + QString resName() const; + void askNewCommand(bool bad_command=true); + void popupMenu(QPoint p); + static int& sz(); + static int& border(); +signals: + void embeddedWindowDestroyed(DockContainer*); + void settingsChanged(DockContainer*); + +protected: + bool x11Event( XEvent * ); + +private: + WId _embeddedWinId; + QString _command; + QString _resName, _resClass; +}; + + +inline WId DockContainer::embeddedWinId() const +{ + return _embeddedWinId; +} + +inline QString DockContainer::command() const +{ + return _command; +} + +inline QString DockContainer::resClass() const +{ + return _resClass; +} + +inline QString DockContainer::resName() const +{ + return _resName; +} + + +#endif + diff --git a/kicker/extensions/kasbar/ChangeLog b/kicker/extensions/kasbar/ChangeLog new file mode 100644 index 000000000..09408fc4a --- /dev/null +++ b/kicker/extensions/kasbar/ChangeLog @@ -0,0 +1,954 @@ +2004-11-20 Saturday 23:27 rich + + * - Ensure the LCD used by the clock is deleted in a timely manner. + + - Lazy creation of the data picker popup of the clock item. + + - Save orientation and direction between sessions properly (the + direction is now the primary record). + +2004-11-20 Saturday 21:18 rich + + * - Update changelog + +2004-11-20 Saturday 21:17 rich + + * - Fixed a warning from KImageEffect about the image being invalid + when we draw the load gradient and the load is 0. + +2004-11-20 Saturday 20:05 rich + + * - Added support for filling the bar from either end. + +2004-11-20 Saturday 02:34 rich + + * - Middle click now rotates the bar. + + - Improved the about dialog. + + - Made masking of the containing toplevel optional. + + - Fixed positioning of the clock display in small mode. + +2004-11-19 Friday 23:21 rich + + * - The standalone app now remembers its position properly. + +2004-11-19 Friday 22:30 rich + + * - Increase version and update changelog. + +2004-11-19 Friday 22:29 rich + + * - Moved item bg gradients into KasResources. + + - More work on improving the painting. This is currently a bit + broken as it is waiting for me to abandon using KRootPixmap. + +2004-11-17 Wednesday 17:56 mueller + + * fix export's + +2004-11-14 Sunday 20:52 binner + + * CVS_SILENT i18n style guide fixes + +2004-11-13 Saturday 02:37 rich + + * - Totally reworked the way showing and hiding popups works. + + - Added a command line tool that provides a standalone kasbar. + + - Added a system load meter item. + + - Improved config dialog. + +2004-10-23 Saturday 19:04 wgreven + + * Fix for unsermake. + +2004-10-23 Saturday 13:42 wgreven + + * Sync with HEAD. + +2004-10-23 Saturday 04:19 rich + + * + - Totally reworked the way showing and hiding of popups works. + Things should be a lot more sane now as the popups are reused. + + - Added a command line tool that provides a standalone kasbar. + + - Improved the demo in the about dialog. + +2004-10-03 Sunday 01:26 rich + + * - Move the startup animation frames into KasResources so they are + shared by all items. Changed the QPtrList to a QValueVector for + more efficient lookups and implicit sharing. + + - Improved the way animations are triggered to support custom + animations. + + - Added a new clock item type. + +2004-09-13 Monday 12:08 coles + + * + + CVS_SILENT + + behaviour -> behavior. + +2004-09-12 Sunday 02:43 rich + + * - Items store their position. This allows much more efficient + painting. + +2004-09-12 Sunday 01:21 rich + + * - Remove floating bars if the extension that they are supposed to + live in is removed. + +2004-09-12 Sunday 00:24 rich + + * - Update changelog + +2004-09-12 Sunday 00:24 rich + + * - Support for only showing minimized applications like the old + OLWM. + + - Improvements to the context menu. + + - Optionally don't show the frames for inactive items (great if + you want the floating mode to blend into your desktop). + + - Refactored code for drawing state icons. + +2004-09-05 Sunday 00:47 rich + + * - Moved most of the config writing code into KasTasker. + +2004-09-04 Saturday 02:57 rich + + * - Update changelog + +2004-09-04 Saturday 02:56 rich + + * - Began making startup items work like other types of item. + + - Fixed a regression that broke all the grouping code. + +2004-09-04 Saturday 01:42 rich + + * - You can now disable the frame around inactive boxes. + + - Startup items now spin around their own center. + +2004-09-03 Friday 22:32 rich + + * - Added support for the XShape extension, the unused space is now + masked so that when you have a non-rectangular bar (by using + the 'Boxes per line' setting) the unused space is truly unused. + To make this better, I need to make it so that the box is + always populated from the screen edge outwards. + +2004-08-29 Sunday 00:27 rich + + * Update changelog + +2004-08-29 Sunday 00:27 rich + + * - Added ability to rotate the bar when it is floating. + + - Added a context menu item to attach and detach the bar. + + - Improved repaint performance. + + - Increased version number. + +2004-08-21 Saturday 02:22 rich + + * - Completed support for embedding the thumbnails of tasks in the + icon boxes instead of only showing them in the tooltip. If the + app changes its WM icon then this is overlayed on the box as + before. + + - Fixed popup display. + +2004-08-20 Friday 23:18 rich + + * - Merge the kasbar3 code into head: + + - Better grouping facilities + - Cleaner code + - More efficient + - Send any window to the system tray + - Attention required indicator + - Partial support for more sizes: huge, enourmous and custom + sizes + - Better organisation of the preferences dialog + - More control over the appearance of the bar + - 'Floating' mode + - Group windows on inactive desktops + +2004-08-07 Saturday 04:10 rich + + * - Moved almost all of the functionality of KasGroupPopup into + KasPopup in preparation for the removal of the custom class for + group popups. + + - Removed the KasGroupPopup class. The functionality it contained + is now all supported by the KasPopup base-class. + +2004-08-07 Saturday 03:39 rich + + * - Ensure the test program reads the current config file properly. + +2004-08-07 Saturday 03:34 rich + + * - Improved the handling of inactive desktop grouping. + + - Fixed a problem with popups not being deleted when their + associated item was invalidated. + +2004-08-07 Saturday 03:00 rich + + * - Ensure that grouping windows on inactive desktops updates + correctly when the current desktop changes. + +2004-08-07 Saturday 02:35 rich + + * - Added kasgrouper class and updated changelog. + +2004-08-07 Saturday 02:34 rich + + * - Reworked the configuration dialog to move the 'insanely + detailed' options into an advanced page. I also added a + graphical way to configure some of the color options that + previously required hacking the config file to access. + + - Made the color of the 'attention required' state icon + configurable. + +2004-08-07 Saturday 00:00 rich + + * - Emit signals for mouse handling and use them for controlling + the popup. + + - Split grouping out into a separate class. + +2004-08-06 Friday 00:51 rich + + * - Fix breakage of the preferences dialog. + +2004-08-06 Friday 00:19 rich + + * - Added an 'ungroup' action to the context menu for group items. + + - Added a 'Refresh' action to kasbar menu. + +2004-08-05 Thursday 23:30 rich + + * - Updated copyrights and added info about the features to docs.h. + +2004-08-05 Thursday 23:26 rich + + * - Reworked the popup handling code to massively improve control + over the lifetime of the popup. This has simplified a bunch of + things and made more advanced popup handling possible. + +2004-08-01 Sunday 02:55 rich + + * - KasItem is now responsible for drawing the main icon of the + boxes. + + - KasItem now provides a demo childbar as the default + implementation of createPopup(). This means that you now get a + nice popup when you move the mouse over the item in the about + dialog. + +2004-08-01 Sunday 01:45 rich + + * - Began moving support for child bars to the kasbar base class + rather than confining it to KasTasker. + + - New constructor for childbars in KasBar. + - Reworked code for updating child to match parents resources. + - Moved child bar creation to a factory method in KasBar. + +2004-08-01 Sunday 00:24 rich + + * - Added support for the 'demands attention' task property. + + - Centralised the code that creates the kasbar menu. + + - Modified icon is now accessed via the resource object. + + - Singleton icons are no longer stored as pointers. + +2004-07-25 Sunday 01:15 rich + + * - Fix a problem with the usage of the RMB menu from taskmanger, + passing a widget as an argument to a bool variable is not + what's supposed to happen. + + - Fixed menu for group items. + + CCMAIL: 48825-done@bugs.kde.org + +2004-07-25 Sunday 00:58 rich + + * - Fixed menu handling to support the show all flag properly, and + added group menus. + +2004-07-25 Sunday 00:20 rich + + * - Started pulling ui resources into a standalone class + KasResources. Child bars inherit their parents resources by + default. + + - Added a hack to prototype the idea of embedding the thumbnails + in the icon box. + + - Support for custom sizes (incomplete). + + - Improvements to the configuration dialog. + + - Ability to group windows on inactive desktops (still buggy). + +2004-07-24 Saturday 00:10 rich + + * - Added the ability to send a window to the system tray. + + - Broke transparency in preparation for the new implementation. + + - Started the 'group windows on inactive desktops' option. + +2004-07-18 Sunday 00:31 rich + + * The work I've been doing to get kasbar ready for the 3.3 release + has encouraged me to add few new features and do a bit of + redesign. This code is not ready to be released, so I'm keeping + it the newly created kasbar3_branch. + +2004-07-10 Saturday 20:38 binner + + * CVS_SILENT i18n style guide fixes + +2004-07-10 Saturday 01:57 rich + + * - Fixed the progress indicator code. You can now get a progress + bar in the label of a task (replacing the broken pie chart + code). + +2004-06-29 Tuesday 01:19 wheeler + + * CVS_SILENT Oops. Didn't mean for this to go in. + +2004-06-29 Tuesday 01:16 wheeler + + * Disable the tint color and amount boxes if tinting is disabled. + +2004-06-27 Sunday 17:18 binner + + * CVS_SILENT i18n style guide fixes + +2004-06-27 Sunday 01:10 rich + + * - Added the ability to choose the colors used for the item + labels. + + CCMAIL: 60520-done@bugs.kde.org + +2004-06-26 Saturday 23:49 rich + + * - Don't show the desktop number if there's only one desktop. + + CCMAIL: 60520@bugs.kde.org + +2004-06-26 Saturday 02:12 rich + + * - Fixed clearing of unused space when the used part of the bar is + not rectangular. The fix could be improved, but it removes the + essential problem. + + CCMAIL: 47078-done@bugs.kde.org + +2004-06-26 Saturday 01:48 rich + + * - Fix popup handling. + + CCMAIL: 68305-done@kde.org + +2004-06-26 Saturday 00:28 rich + + * - Fix test program for kwin changes. + +2004-06-26 Saturday 00:10 rich + + * - Fix task properties dialog to use the new name of the + visibleiconname Task property. + +2004-06-25 Friday 23:43 rich + + * - Fixed about dialog to take account of the fact the cvs id was + removed. + + - Fixed the size and wrapping of the license text in the about + dialog. + +2004-06-25 Friday 23:10 rich + + * Updated the changelog, it was 2 years out of date + +2004-02-24 Tuesday 19:14 mcamen + + * Fix compilation. The remove-id-tag-commit was not correct for + these files. + +2004-02-24 Tuesday 11:30 englich + + * + Remove all CVS Id tags from kdebase, if I haven't missed one. + + Of course, this will multifold break compile as well as a dozen + of people will now object that they actually wanted the Id tags. + +2004-01-05 Monday 21:38 adridg + + * Add dual-license GPL/BSD to files as instructed by Rich Moore. + +2003-12-20 Saturday 15:14 kossebau + + * hiding a few symbols :) + +2003-11-20 Thursday 16:12 mlaurent + + * Clean commit as requested by David. When we use + K_EXPORT_KICKER_MENUEXT it's automatic => don't use + removeCatalogue otherwise use removeCatalogue. + +2003-10-27 Monday 19:12 bwalter + + * CVS_SILENT Changed the "check popup" delay. + +2003-10-23 Thursday 21:41 bwalter + + * Use topLevelWidget() instead of parent()->parent()... + +2003-10-22 Wednesday 22:15 bwalter + + * Better than a singleShot timer to make popups disappear but not + always enough. + +2003-10-21 Tuesday 10:45 bwalter + + * Fix the annoying problem of tooltips which sometimes never + disappear. + +2003-10-06 Monday 23:27 rich + + * Fix vertical mode + +2003-10-06 Monday 20:11 rich + + * Fix problem with maxBoxes fix. + +2003-10-04 Saturday 21:36 rich + + * - Split the 'max boxes' concept into two so we can handle things + properly. The original max boxes remains, and refers to the + user specified limit on the number of boxes per line. In + addition there is now a 'boxes per line' concept which stores + the number of boxes that will actually fit. This change cleans + up the configuration handling and also means that kasbar can obey + the size limits placed on it. + + - Take notice of the size limits passed to the widget. This means + the size limits for extension that were added in 3.1 will now + work properly. + + - Disable updates when refreshing the entire task list. This + removes lots of flicker when changing desktops when you don't + show all the tasks. + + - Improved the resize handling code so that can handle changes in + the item size cleanly. + + - Updated copyright dates. + +2003-09-30 Tuesday 22:25 rich + + * - More improvements to bg repainting (much more efficient). + + - Fixed startup animation problem #39582 + + - Fixed erase problem introduced by the repaint changes in my + last commit. + + CCMAIL: 39582-done@bugs.kde.org + +2003-09-30 Tuesday 19:18 rich + + * - Removed duplicated config loading code from the extension + class. + + - Removed redundant reload of configuration info. + + - Reworked painting - Double buffering is now handled by KasBar + not the items. - Items now longer force an immediate repaint, + they use update instead. - Fixes #53735 + + CCMAIL: 53735-done@bugs.kde.org + +2003-09-29 Monday 12:24 lunakl + + * Another attempt to get (_NET_)WM_(ICON_)NAME right. + +2003-08-07 Thursday 19:51 lunakl + + * Rewrite handling of _NET_WM_ICON_NAME. This together with the + recent KApplication change should hopefully make taskbar again + display what it's supposed to display. Please yell if something + is still wrong. + +2003-07-31 Thursday 10:31 lunakl + + * Proper handling of _NET_WM_ICON_NAME - it has nothing to do with + what's usually meant by icons in KDE, but it's the text to be + shown in iconic representations of a window, such as taskbar + entries. + +2003-07-19 Saturday 22:35 deller + + * do not use hardcoded fontnames + +2003-05-17 Saturday 10:20 coolo + + * fixing quite some compiler warnings + +2003-03-29 Saturday 20:29 binner + + * Fixed a layout problem and solution for "only drawing last icon + from a group". + +2003-02-09 Sunday 09:51 mfranz + + * fix typo + +2002-12-29 Sunday 17:10 mueller + + * use $(KDE_PLUGIN) + +2002-10-27 Sunday 16:05 mlaurent + + * Fix a part of crash. But kastaskbar crash again when we call + "show preference" or "about" when we call it into taskbarpopup. + Because taskitem was deleted when we hide popup => so when we + close dialogbox, kicker crash. I don't know how to fix it. But + it crashs again... + +2002-10-27 Sunday 15:50 mlaurent + + * Remove some if( blabla) delete blabla => delete blabla; + +2002-10-27 Sunday 14:46 mlaurent + + * Fix display properties dialogbox when we call it from + kasgroupitem + +2002-10-27 Sunday 13:53 mlaurent + + * Fix crash when we call showPreference on item in kasgroupgroup => + config pointer was null. + +2002-10-27 Sunday 12:48 mlaurent + + * Fix crash when we taskbar was re-create after change config. + +2002-09-18 Wednesday 17:13 binner + + * CVS_SILENT Style guide fix, use "cvslastchange" or X-WebCVS + header line to view + +2002-09-03 Tuesday 16:42 ettrich + + * patch from Benoit Walter <benoit.walter@esstin.uhp-nancy.fr> as + discussed on kde-core-devel + +2002-08-31 Saturday 10:44 pfeiffer + + * another font-patch from CCMAIL: Luciano Montanaro + <mikelima@virgilio.it> + +2002-08-30 Friday 11:45 mkretz + + * This took me 2 hours to find... + + - KConfigGroupSaver( conf, "Appearance" ); + + KConfigGroupSaver saver( conf, "Appearance" ); + + Finally the size is restored correctly. + +2002-08-30 Friday 10:37 pfeiffer + + * use KGlobal::taskbarFont(), patch by CCMAIL: Luciano Montanaro + <mikelima@virgilio.it> + +2002-08-29 Thursday 17:38 mueller + + * remove outdated #ifdef's + +2002-08-13 Tuesday 09:05 binner + + * CVS_SILENT Style guide fix, use "cvslastchange" or X-WebCVS + header line to view + +2002-08-09 Friday 23:57 rich + + * - Fixed repaint problem with startup items + +2002-07-29 Monday 22:03 coolo + + * this fixes compilation for me +void KasTasker::readConfig() +{ + + readConfig(this->conf); +} + +2002-07-27 Saturday 04:26 rich + + * Added kasbar actions to item menus to fix reported ui bug + +2002-07-03 Wednesday 11:03 binner + + * CVS_SILENT Style guide fixes + +2002-06-10 Monday 03:29 rich + + * - Simplify drawing code - Ensure popup doesn't obscure menu - Fix + bug when window changes desktop - Task properties dialog + +2002-05-25 Saturday 14:18 coolo + + * CVS_SILENT ignoring unsermake generated files + +2002-05-14 Tuesday 10:31 gioele + + * kapp.h -> kapplication.h + +2002-04-23 Tuesday 14:02 binner + + * CVS_SILENT Capitalisation fixes. + +2002-04-12 Friday 22:36 rich + + * - kdoc fixes + +2002-03-11 Monday 00:23 rich + + * Use all the frames in the startup animation (cleaner fix) + +2002-03-11 Monday 00:10 rich + + * Use all the frames in the statup animation + +2002-03-08 Friday 15:08 lukas + + * grrr, I fixed that before 2.2.2 and it's back :( + + + KGlobal::locale()->insertCatalogue("kasbarextension"); + +2002-02-26 Tuesday 17:04 elter + + * - install extensions into kde's module subdir + +2002-02-24 Sunday 21:44 rich + + * Added change log file + +2002-02-24 Sunday 21:41 rich + + * - Version++ - Fixed redraw errors when there are no tasks - Now + makes use of the KRootPixmap improvements in KDE 3. - All + drawing is now double buffered, so the flicker problems of the + past should be solved. - Changed many methods to remove + coordinate params. - KasItems are now given a translated + qpainter. - Added a change log (generated from the cvs log by + cvs2cl). - Removed old RMB menu code (we use the more reliable + stuff in the taskmanager lib instead). + + ---------------------------------------------------------------------- + +2002-01-20 Sunday 18:15 wgreven + + * Initialize dragTimer to null. + +2001-12-29 Saturday 17:18 mueller + + * CVSSILENT: fixincludes + +2001-12-11 Tuesday 02:09 firebaugh + + * Clean up task menu code. Kill memory leaks. Add new items to RMB + menu for grouped tasks. + +2001-11-29 Thursday 19:34 rich + + * version++, update homepage + +2001-11-29 Thursday 19:23 rich + + * Switch to taskmanager task popup menu instead of kwin (avoids + some problems) + +2001-11-25 Sunday 02:03 rich + + * - Updated todo list - Only showing the group popups for 4 ms was + a bit daft - Moved config load code + +2001-11-25 Sunday 01:43 rich + + * - Reduced flicker - kasbar widget now supports widget flags - + Version++ - Task grouping popups now auto-hide - Added standalone + version for testing (maybe a user-level feature in future). + +2001-11-11 Sunday 17:26 rich + + * Work the same way as the std taskbar + +2001-10-07 Sunday 01:46 mueller + + * whoopsie + +2001-09-26 Wednesday 18:37 mueller + + * fixes for QT_NO_COMPAT + +2001-09-01 Saturday 22:31 rich + + * Fix popup window for Qt 3 widget flags better + +2001-09-01 Saturday 22:23 rich + + * Fix popup window for Qt 3 widget flags + +2001-09-01 Saturday 00:55 rich + + * - QList->QPtrList - Improved classdocs build target + +2001-08-27 Monday 18:41 lukas + + * make it show translated + +2001-07-17 Tuesday 19:59 rich + + * Added some extra guards around KRootPixmap calls and readded the + repaint I removed earlier + +2001-07-17 Tuesday 17:03 rich + + * Remove redundant repaint + +2001-07-17 Tuesday 16:47 rich + + * Get rid of the warning reported by Dirk + +2001-06-04 Monday 22:09 rich + + * Minor fixes + +2001-06-04 Monday 19:55 rich + + * Do not refresh on desktop switch if we show all tasks + +2001-05-24 Thursday 02:01 rich + + * UI fix for small mode + +2001-05-22 Tuesday 05:03 waba + + * Get rid of compiler warnings. Make it compile with + --enable-final. + +2001-05-22 Tuesday 02:22 rich + + * Use shared idmatching code + transparency fix + +2001-05-21 Monday 21:59 rich + + * Added support for task grouping (optional) + +2001-05-21 Monday 02:09 mhunter + + * Spelling and grammar corrections + +2001-05-15 Tuesday 04:37 rich + + * Moved the icon handling code out of Kasbar and into the Task + class. Task now provides an API for icon loading that allows + access to different icon sizes and uses KIconLoader where needed. + +2001-05-15 Tuesday 01:19 rich + + * Improved icon support in task manager api Fixed flicker in kasbar + startup items Kasbar large mode handles dynamically changing + icons nicely + +2001-05-14 Monday 21:37 rich + + * Still standardising the method names + +2001-05-14 Monday 17:56 rich + + * Changed taskmanager api to follow standard naming conventions + +2001-05-14 Monday 16:38 rich + + * Better icon handling in Large mode Fixed config handling of + MaxBoxes + +2001-05-14 Monday 03:26 rich + + * Minor tweaks + +2001-05-14 Monday 02:52 rich + + * More thumbnail improvements + +2001-05-14 Monday 00:40 rich + + * Added new about dialog Fixed some flicker problems Improved + thumbnail heuristics Improved transparent mode repaints + +2001-04-27 Friday 19:07 rich + + * Fixed modified indicator + +2001-04-27 Friday 18:00 rich + + * You can vary the size of Kasbar! + +2001-04-26 Thursday 22:50 rich + + * Fix transparency bug + +2001-04-26 Thursday 22:15 rich + + * UI fixes + +2001-04-26 Thursday 21:08 rich + + * Improvements to extension support + +2001-04-26 Thursday 00:05 rich + + * Fixed whatsthis + +2001-04-25 Wednesday 23:56 rich + + * Added whatsthis help + +2001-04-25 Wednesday 20:23 rich + + * Nicer config dialog + +2001-04-25 Wednesday 19:38 rich + + * Version number++ + +2001-04-25 Wednesday 18:35 rich + + * Now you turn off thumbnails and a minor memory leak was fixed + +2001-04-19 Thursday 01:27 rich + + * All the preferences are now working except for disabling + thumbnails. + +2001-04-18 Wednesday 00:01 rich + + * More work on the config dialog + +2001-04-16 Monday 14:07 rich + + * Forgot to commit this + +2001-04-16 Monday 14:05 rich + + * Added config handling (partial so far) Changed + X-KDE-UniqueExtension to X-KDE-UniqueApplet (the former is + correct according to the docs but doesn't work). + +2001-04-10 Tuesday 21:13 rich + + * Fixed startup crash + +2001-03-31 Saturday 11:50 elter + + * - fixed extension size hint - fixed compiler warning + +2001-03-20 Tuesday 02:15 rich + + * * About dialog now shows a version number. * Changed modified + icon from blue to black. * Much improved thumbnailing - now + feels nice and responsive. + +2001-03-18 Sunday 17:43 rich + + * Added about dlg and publish icon geometries + +2001-03-18 Sunday 16:20 rich + + * Fixed crash in mouse move event + +2001-03-16 Friday 03:37 rich + + * - Added task switch on drag over - Tidied up access to TasTasker + - Made gradient code more efficient - Added window menu support + +2001-03-06 Tuesday 23:34 rich + + * More efficient startup items + +2001-03-06 Tuesday 22:29 porten + + * friend class + +2001-03-06 Tuesday 12:32 faure + + * ran includemocs to get this to compile (am_edit was trying to + compile a .moc.cpp into a .moc ... there's still something fishy + in am_edit...) + +2001-03-06 Tuesday 02:05 rich + + * First public release of the Kasbar TNG code + + Kasbar now: - Use the new taskmanager API - Supports the startup + notifier - Supports thumbnails - Supports transparency ... + +2000-12-17 Sunday 12:00 elter + + * Fixed totally broken kasbar sizeHint. + +2000-12-17 Sunday 11:53 elter + + * - correct initial positioning of extensions - bugfixes + +2000-11-14 Tuesday 21:46 rich + + * Added: - Transparency support - Show this-desktop-only mode + + Fixed: - Icon sizing issue caused by the move to 34x34 icons - + Unique flag in .desktop file + +2000-11-12 Sunday 20:21 rich + + * - Tidied up the code - Steps towards startup notifier - Better + left click behaviour - Window menu support using DCOP (needs KWin + update I am committing in a moment) - Minor bug fixes + +2000-11-12 Sunday 01:14 rich + + * Ported kasbar to kicker entensions framework + diff --git a/kicker/extensions/kasbar/DESIGN b/kicker/extensions/kasbar/DESIGN new file mode 100644 index 000000000..6d2de25e6 --- /dev/null +++ b/kicker/extensions/kasbar/DESIGN @@ -0,0 +1,42 @@ +KasBar TNG Design +================= + +In order to support both the various features people asked for when I +discussed Kasbar on dot.kde.org without ending up with a completely +unmaintainable application, I've decided to rewrite the code. It's a +fairly small application, so this isn't a big deal. The task management +side of things (interacting with the window manager etc.) is now handled +via the standard TaskManager API provided by kicker. + +The division of labour between the classes is like this: + +* KasBar, KasItem, KasPopup + + These classes implement the KasBar widget. KasBar provides the + layout and smart redraws while the KasItem class is an abstract + interface for the items forming the bars contents. The KasPopup + class provides a self positioning widget that should be subclassed + to provide useful information. + + These classes are usable standalone. + +* KasTasker, KasTaskItem, KasTaskPopup + + These classes provide the glue linking the task management and + karbar modules together. + +* KasGroupItem, KasGroupPopup + + These class provide a container item for a group of tasks, and popup + window that shows them in a KasTasker widget. + +* KasBarExtension + + This class handles integration with kicker and configuration info. + +* KasPrefsDlg + + This is the configuration dialog. It acts directly on the kastasker + widget to provide immediate feedback of the effects of configuration + changes. Any changes being previewed are reverted if the user cancels + the dialog because the configuration is reloaded. diff --git a/kicker/extensions/kasbar/Doxyfile b/kicker/extensions/kasbar/Doxyfile new file mode 100644 index 000000000..8c82cae8b --- /dev/null +++ b/kicker/extensions/kasbar/Doxyfile @@ -0,0 +1,1101 @@ +# Doxyfile 1.3.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = classdocs + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . ../../taskmanager + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs + +FILE_PATTERNS = *.h *.cpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = *moc* + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# colloborations diagrams in a style similiar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/kicker/extensions/kasbar/Makefile.am b/kicker/extensions/kasbar/Makefile.am new file mode 100644 index 000000000..f7e4ce14c --- /dev/null +++ b/kicker/extensions/kasbar/Makefile.am @@ -0,0 +1,55 @@ +INCLUDES = -I$(srcdir)/../../taskmanager $(all_includes) +METASOURCES = AUTO + +# +# Library implementing the core functionality +# +lib_LTLIBRARIES = libkasbar.la + +libkasbar_la_SOURCES = kasbar.cpp kasitem.cpp \ + kastaskitem.cpp kastasker.cpp kaspopup.cpp \ + kastaskpopup.cpp kasstartupitem.cpp \ + kasaboutdlg.cpp kasprefsdlg.cpp kasclockitem.cpp \ + kasgroupitem.cpp kasresources.cpp kasgrouper.cpp \ + kasloaditem.cpp + +libkasbar_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined +libkasbar_la_LIBADD = $(LIB_KDEUI) ../../taskmanager/libtaskmanager.la + +# +# Panel Extension +# +kde_module_LTLIBRARIES = kasbar_panelextension.la + +kasbar_panelextension_la_SOURCES = kasbarextension.cpp +kasbar_panelextension_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +kasbar_panelextension_la_LIBADD = libkasbar.la + +noinst_HEADERS = kasbar.h kasitem.h kasbarextension.h \ + kastaskitem.h kastasker.h kaspopup.h kasstartupitem.h \ + kasaboutdlg.h kasprefsdlg.h version.h kasclockitem.cpp \ + kasgroupitem.h kasresources.h kasgrouper.h kasloaditem.cpp + +lnkdir = $(kde_datadir)/kicker/extensions +lnk_DATA = kasbarextension.desktop + +EXTRA_DIST = $(lnk_DATA) + +bin_PROGRAMS = kasbar +kasbar_SOURCES = kasbarapp.cpp +kasbar_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kasbar_LDADD = libkasbar.la \ + $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) + + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/kasbarextension.pot + +srcdoc: + $(kde_bindir)/kdoc -a -p -d classdocs -n 'Kasbar2' ../../taskmanager/*.h *.h -lqt -lkdecore -lkdeui + +.PHONY: changes +changes: + cvs2cl.pl --window 3600 -w --hide-filenames -I '.desktop' + +KDE_OPTIONS = nofinal diff --git a/kicker/extensions/kasbar/TODO b/kicker/extensions/kasbar/TODO new file mode 100644 index 000000000..3b35b775f --- /dev/null +++ b/kicker/extensions/kasbar/TODO @@ -0,0 +1,29 @@ +- Don't show systray option if already has one +- Close detached bar when container dies + + +Bug Fixes +========= + +- Turn the rest of the 'magic numbers' into named constants + +- Ensure the boxes load from the screen edges outwards (not done + currently correctly right now) + +New Features +============ + +- Task listing profiles + +- Add double buffered updates + +- Allow more control over task grouping + +Mostly Done +=========== + +- Move the generic code from Kasbar and the default taskbar to + libtaskmanager + + + diff --git a/kicker/extensions/kasbar/configure.in.in b/kicker/extensions/kasbar/configure.in.in new file mode 100644 index 000000000..9d5ec223c --- /dev/null +++ b/kicker/extensions/kasbar/configure.in.in @@ -0,0 +1 @@ +AC_CHECK_HEADERS(sys/loadavg.h) diff --git a/kicker/extensions/kasbar/docs.h b/kicker/extensions/kasbar/docs.h new file mode 100644 index 000000000..6a9aa5849 --- /dev/null +++ b/kicker/extensions/kasbar/docs.h @@ -0,0 +1,69 @@ +/** + * @mainpage Kasbar 3NG + * + * @section intro Introduction + * + * This is the 3rd generation of kasbar. + * + * @section completed Completed Features + * + * <ul> + * <li>Added the ability to detach the bar from the screen edge and drag it around. + * <li>Added support for the 'demands attention' NET WM property. + * <li>Many internal code clean-ups. + * <li>Centralised the drawing code and graphical resource management. + * <li>Added a 'Send To System Tray' command to the window menu. + * <li>Added the ability to group windows on inactive desktops. + * <li>Improved the painting code. + * <li>Added an 'ungroup' action to the context menu for group items. + * <li>Added a 'Refresh' action to kasbar menu. + * <li>Added a 'Quit' action to kasbar menu when running as a standalone app. + * <li>Support for embedding the preview in the box instead of an icon. + * </ul> + * + * @section inprogress In Progress + * + * <ul> + * <li>Support for new size modes. + * </ul> + * + * @section todo Todo + * + * <ul> + * <li>Support for custom grouping. + * </ul> + */ + + + +class QObject +{ +}; + +class QWidget : public QObject +{ +}; + +class QDialog : public QWidget +{ +}; + +class QFrame : public QWidget +{ +}; + +class QHBox : public QFrame +{ +}; + +class QLCDNumber : public QFrame +{ +}; + +class KDialogBase : public QDialog +{ +}; + +class KPanelExtension : public QWidget +{ +}; diff --git a/kicker/extensions/kasbar/kasaboutdlg.cpp b/kicker/extensions/kasbar/kasaboutdlg.cpp new file mode 100644 index 000000000..73d20d94b --- /dev/null +++ b/kicker/extensions/kasbar/kasaboutdlg.cpp @@ -0,0 +1,264 @@ +/* kasaboutdlg.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + +#include <qcheckbox.h> +#include <qgrid.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <kdeversion.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <ktextbrowser.h> + +#ifdef USE_KSPY +#include <kspy.h> +#endif + +#include "kasbar.h" +#include "kasitem.h" +#include "kaspopup.h" + +#include "kasclockitem.h" +#include "kasloaditem.h" + +#include "kasaboutdlg.h" +#include "version.h" + +#define Icon(x) KGlobal::iconLoader()->loadIcon( x, KIcon::NoGroup, KIcon::SizeMedium ) +#define LargeIcon(x) KGlobal::iconLoader()->loadIcon( x, KIcon::NoGroup, KIcon::SizeLarge ) + +KasAboutDialog::KasAboutDialog( QWidget *parent ) + : KDialogBase( KDialogBase::IconList, i18n("About Kasbar"), + KDialogBase::Ok, + KDialogBase::Ok, + parent, "kasbarAboutDialog", false ) +{ +#ifdef USE_KSPY + KSpy::invoke(); +#endif + + addInfoPage(); + addAuthorsPage(); + addBSDPage(); + addGPLPage(); + + addDemoBar(); + + resize( 760, 450 ); +} + +KasAboutDialog::~KasAboutDialog() +{ + +} + +void KasAboutDialog::addDemoBar() +{ + QHBox *box = new QHBox( this ); + + box->setLineWidth(2); + box->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + + box->setSpacing( spacingHint() ); + box->setMargin( marginHint() ); + + KasBar *bar = new KasBar( Horizontal, box ); + bar->setItemSize( KasBar::Large ); + bar->setMasked( false ); + + KasItem *ci = new KasItem( bar ); + ci->setIcon( LargeIcon( "icons" ) ); + bar->append( ci ); + + KasPopup *pop = new KasPopup( ci ); + ci->setPopup( pop ); + ci->setCustomPopup( true ); + connect( ci, SIGNAL(leftButtonClicked(QMouseEvent *)), ci, SLOT(togglePopup()) ); + + KasBar *groupbar = bar->createChildBar( ( bar->orientation() == Horizontal ) ? Vertical : Horizontal, pop ); + KasItem *i = 0; + + KasClockItem *clk = new KasClockItem( groupbar ); + groupbar->append( clk ); + + i = new KasLoadItem( groupbar ); + groupbar->append( i ); + + groupbar->addTestItems(); + + pop->resize( groupbar->size() ); + + bar->setFixedSize( bar->itemExtent(), bar->itemExtent() ); + addWidgetBelowList( box ); +} + +void KasAboutDialog::addInfoPage() +{ + QVBox *aboutPage = addVBoxPage( i18n("About"), i18n("About Kasbar"), Icon( "appearance" ) ); + aboutPage->setSpacing( spacingHint() ); + + new QLabel( i18n( "<qt><body>" + "<h2>Kasbar Version: %1</h2>" + "<b>KDE Version:</b> %2" + "</body></qt>" ) + .arg( VERSION_STRING ).arg( KDE_VERSION_STRING ), + aboutPage ); + + KTextBrowser *text5 = new KTextBrowser( aboutPage ); + text5->setText( i18n( "<html><body>" + "<p>Kasbar TNG began as a port of the original Kasbar applet to " + "the (then new) extension API, but ended up as a complete " + "rewrite because of the range of features needed by different " + "groups of users. In the process of the rewrite all the standard " + "features provided by the default taskbar were added, along with " + "some more original ones such as thumbnails." + "</p>" + "<p>" + "You can find information about the latest developments in Kasbar at " + "<a href=\"%3\">%4</a>, the Kasbar homepage." + "</p>" + "</body></html>" ) + .arg( HOMEPAGE_URL ).arg( HOMEPAGE_URL ) ); + + text5->setWordWrap( QTextEdit::WidgetWidth ); +} + +void KasAboutDialog::addAuthorsPage() +{ + QVBox *authorsPage = addVBoxPage( i18n("Authors"), + i18n("Kasbar Authors"), + Icon( "kuser" ) ); + + KTextBrowser *text = new KTextBrowser( authorsPage ); + text->setText( i18n( + "<html>" + + "<b>Richard Moore</b> <a href=\"mailto:rich@kde.org\">rich@kde.org</a><br>" + "<b>Homepage:</b> <a href=\"http://xmelegance.org/\">http://xmelegance.org/</a>" + + "<p>Developer and maintainer of the Kasbar TNG code.</p>" + + "<hr/>" + + "<b>Daniel M. Duley (Mosfet)</b> <a href=\"mailto:mosfet@kde.org\">mosfet@kde.org</a><br>" + "<b>Homepage:</b> <a href=\"http://www.mosfet.org/\">http://www.mosfet.org/</a>" + + "<p>Mosfet wrote the original Kasbar applet on which this " + "extension is based. There is little of the original code " + "remaining, but the basic look in opaque mode is almost " + "identical to this first implementation.</p>" + + "</html>" ) ); + + text->setWordWrap( QTextEdit::WidgetWidth ); +} + +void KasAboutDialog::addBSDPage() +{ + QVBox *bsdLicense = addVBoxPage( i18n("BSD License"), QString::null, Icon( "filefind" ) ); + + new QLabel( i18n( "Kasbar may be used under the terms of either the BSD license, " + "or the GNU Public License." ), bsdLicense ); + + KTextBrowser *text2 = new KTextBrowser( bsdLicense ); + text2->setText( "Some text of unsurpassed tediousness goes here." ); + text2->setWordWrap( QTextEdit::NoWrap ); + + QString bsdFile = locate("data", "LICENSES/BSD"); + if ( !bsdFile.isEmpty() ) { + QString result; + QFile file( bsdFile ); + + if ( file.open( IO_ReadOnly ) ) + { + QTextStream str(&file); + result += str.read(); + } + + text2->setText( result ); + } +} + +void KasAboutDialog::addGPLPage() +{ + QVBox *gplPage = addVBoxPage( i18n("GPL License"), QString::null, Icon( "filefind" ) ); + + new QLabel( i18n( "Kasbar may be used under the terms of either the BSD license, " + "or the GNU Public License." ), gplPage ); + + KTextBrowser *text3 = new KTextBrowser( gplPage ); + text3->setText( "Some more text of unsurpassed tediousness goes here." ); + text3->setWordWrap( QTextEdit::NoWrap ); + + QString gplFile = locate("data", "LICENSES/GPL_V2"); + if ( !gplFile.isEmpty() ) { + QString result; + QFile file( gplFile ); + + if ( file.open( IO_ReadOnly ) ) + { + QTextStream str(&file); + result += str.read(); + } + + text3->setText( result ); + } +} + +#include "kasaboutdlg.moc" diff --git a/kicker/extensions/kasbar/kasaboutdlg.h b/kicker/extensions/kasbar/kasaboutdlg.h new file mode 100644 index 000000000..c217ead79 --- /dev/null +++ b/kicker/extensions/kasbar/kasaboutdlg.h @@ -0,0 +1,86 @@ +/* kasaboutdlg.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASABOUTDLG_H +#define KASABOUTDLG_H + +#include <kdialogbase.h> + +class KasBar; + +/** + * About dialog for KasBar + */ +class KasAboutDialog : public KDialogBase +{ + Q_OBJECT + +public: + KasAboutDialog( QWidget *parent=0 ); + ~KasAboutDialog(); + + void addAuthorsPage(); + void addAdvancedPage(); + void addInfoPage(); + void addBSDPage(); + void addGPLPage(); + void addDemoBar(); + +private: + KasBar *bar; +}; + +#endif // KASABOUTDLG_H + diff --git a/kicker/extensions/kasbar/kasbar.cpp b/kicker/extensions/kasbar/kasbar.cpp new file mode 100644 index 000000000..8210190c8 --- /dev/null +++ b/kicker/extensions/kasbar/kasbar.cpp @@ -0,0 +1,728 @@ +/* kasbar.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <math.h> + +#include <qbitmap.h> +#include <qcursor.h> +#include <qpainter.h> +#include <qmemarray.h> +#include <qtimer.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <krootpixmap.h> +#include <kpixmapio.h> +#include <kiconloader.h> + +#include "kasitem.h" + +#include "kasbar.h" +#include "kasbar.moc" + +static const int SMALL_EXTENT = 36; +static const int MEDIUM_EXTENT = 52; +static const int LARGE_EXTENT = 68; +static const int HUGE_EXTENT = 84; +static const int ENORMOUS_EXTENT = 148; + +KasBar::KasBar( Orientation o, QWidget *parent, const char *name, WFlags f ) + : QWidget( parent, name, f ), + master_(0), + orient( o ), + direction_( o == Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom ), + itemUnderMouse_( 0 ), + boxesPerLine_(10), // Temp value + inDrag( false ), + detached( false ), + maxBoxes_( 100 ), // Temp value + itemSize_( Medium ), + itemExtent_( MEDIUM_EXTENT ), + paintInactiveFrame_( true ), + transparent_( false ), + rootPix( 0 ), + enableTint_( false ), + tintAmount_( 0.1 ), + tintColour_( colorGroup().mid() ), + useMask_( true ), + res(0) +{ + setBackgroundMode( NoBackground ); + items.setAutoDelete( true ); + setMouseTracking( true ); + setMaxBoxes( 0 ); + + connect( this, SIGNAL( configChanged() ), SLOT( repaint() ) ); +} + +KasBar::KasBar( Orientation o, KasBar *master, QWidget *parent, const char *name, WFlags f ) + : QWidget( parent, name, f ), + master_(master), + orient( o ), + direction_( o == Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom ), + itemUnderMouse_( 0 ), + boxesPerLine_(10), // Temp value + inDrag( false ), + detached( false ), + maxBoxes_( 100 ), // Temp value + itemSize_( Medium ), + itemExtent_( MEDIUM_EXTENT ), + paintInactiveFrame_( true ), + transparent_( false ), + rootPix( 0 ), + enableTint_( false ), + tintAmount_( 0.1 ), + tintColour_( colorGroup().mid() ), + useMask_( true ), + res(0) +{ + setBackgroundMode( NoBackground ); + items.setAutoDelete( true ); + setMouseTracking( true ); + setMaxBoxes( 0 ); + connect( master_, SIGNAL( configChanged() ), SLOT( repaint() ) ); +} + +KasBar::~KasBar() +{ + delete res; +} + +KasResources *KasBar::resources() +{ + if ( res ) + return res; + + if ( isTopLevel() ) { + res = new KasResources( this ); + connect( res, SIGNAL( changed() ), SIGNAL( configChanged() ) ); + connect( this, SIGNAL( itemSizeChanged(int) ), res, SLOT( itemSizeChanged() ) ); + return res; + } + + return master_->resources(); +} + +KasBar *KasBar::createChildBar( Orientation o, QWidget *parent, const char *name ) +{ + KasBar *child = new KasBar( o, this, parent, name ); + child->rereadMaster(); + return child; +} + +void KasBar::setItemSize( int size ) +{ + switch( size ) { + case Small: + setItemExtent( SMALL_EXTENT ); + break; + case Medium: + setItemExtent( MEDIUM_EXTENT ); + break; + case Large: + setItemExtent( LARGE_EXTENT ); + break; + case Huge: + setItemExtent( HUGE_EXTENT ); + break; + case Enormous: + setItemExtent( ENORMOUS_EXTENT ); + break; + default: + break; + } +} + +void KasBar::setItemExtent( int size ) +{ + if ( size == itemExtent_ ) + return; + + itemExtent_ = size; + + if ( size < MEDIUM_EXTENT ) + itemSize_ = Small; + else if ( size < LARGE_EXTENT ) + itemSize_ = Medium; + else if ( size < HUGE_EXTENT ) + itemSize_ = Large; + else if ( size < ENORMOUS_EXTENT ) + itemSize_ = Huge; + else + itemSize_ = Enormous; + + emit itemSizeChanged( itemSize_ ); + emit configChanged(); + + updateLayout(); +} + +void KasBar::setTransparent( bool enable ) +{ + if ( transparent_ == enable ) + return; + + transparent_ = enable; + + if ( transparent_ ) { + kdDebug(1345) << "KasBar: Enabling transparency" << endl; + + rootPix = new KRootPixmap( this ); + connect( rootPix, SIGNAL( backgroundUpdated(const QPixmap &) ), + this, SLOT( setBackground(const QPixmap &) ) ); + + rootPix->setCustomPainting( true ); + + if ( enableTint_ ) + rootPix->setFadeEffect( tintAmount_, tintColour_ ); + + rootPix->start(); + } + else { + kdDebug(1345) << "KasBar: Disabling transparency" << endl; + + rootPix->stop(); + delete rootPix; + rootPix = 0; + } + + emit configChanged(); +} + +void KasBar::setTint( bool enable ) +{ + if ( enableTint_ == enable ) + return; + + enableTint_ = enable; + + if ( transparent_ && rootPix ) { + if ( enableTint_ ) { + rootPix->setFadeEffect( tintAmount_, tintColour_ ); + } + else { + rootPix->setFadeEffect( 0.0, tintColour_ ); + } + + emit configChanged(); + repaint( true ); + } +} + +void KasBar::setTint( double amount, QColor color ) +{ + tintAmount_ = amount; + tintColour_ = color; + + if ( transparent_ && enableTint_ ) { + rootPix->setFadeEffect( tintAmount_, tintColour_ ); + emit configChanged(); + + if ( rootPix->isAvailable() ) + rootPix->repaint( true ); + } +} + +void KasBar::setTintColor( const QColor &c ) +{ + setTint( tintAmount_, c ); +} + +void KasBar::setTintAmount( int percent ) +{ + double amt = (double) percent / 100.0; + setTint( amt, tintColour_ ); +} + +void KasBar::setMaxBoxes( int count ) +{ + if ( count == maxBoxes_ ) + return; + + if ( count == 0 ) + count = 15; // XXX Hacked + + maxBoxes_ = count; + emit configChanged(); + setBoxesPerLine( count ); +} + +void KasBar::setBoxesPerLine( int count ) +{ + boxesPerLine_ = QMIN( count, maxBoxes_ ); + updateLayout(); +} + +void KasBar::setDetachedPosition( const QPoint &pos ) +{ + if ( detachedPos == pos ) + return; + + detachedPos = pos; + emit detachedPositionChanged( pos ); +} + +void KasBar::setDirection( Direction dir ) +{ + if ( direction_ == dir ) + return; + + if ( ( dir == QBoxLayout::LeftToRight ) || ( dir == QBoxLayout::RightToLeft ) ) + orient = Horizontal; + else + orient = Vertical; + + direction_ = dir; + emit directionChanged(); + updateLayout(); +} + +void KasBar::setOrientation( Orientation o ) +{ + if ( orient == o ) + return; + + if ( o == Horizontal ) + setDirection( QBoxLayout::LeftToRight ); + else + setDirection( QBoxLayout::TopToBottom ); +} + +void KasBar::toggleOrientation() +{ + switch( direction_ ) { + case QBoxLayout::LeftToRight: + setDirection( QBoxLayout::RightToLeft ); + break; + case QBoxLayout::RightToLeft: + setDirection( QBoxLayout::TopToBottom ); + break; + case QBoxLayout::TopToBottom: + setDirection( QBoxLayout::BottomToTop ); + break; + case QBoxLayout::BottomToTop: + setDirection( QBoxLayout::LeftToRight ); + break; + default: + kdWarning() << "toggleOrientation got an odd direction: " << (uint) direction_ << endl; + setDirection( QBoxLayout::LeftToRight ); + break; + } +} + +void KasBar::toggleDetached() +{ + setDetached( !detached ); +} + +void KasBar::setDetached( bool detach ) +{ + if ( detached == detach ) + return; + + detached = detach; + updateLayout(); + emit detachedChanged( detached ); +} + +QSize KasBar::sizeHint( Orientation o, QSize sz ) +{ + if ( o == Horizontal ) + setBoxesPerLine( sz.width() / itemExtent() ); + else + setBoxesPerLine( sz.height() / itemExtent() ); + + unsigned int r=0, c=0; + if( items.count() > (unsigned int) boxesPerLine_ ) { + r = items.count()/boxesPerLine_; + c = boxesPerLine_; + } + else { + r = 1; + c = items.count(); + } + + if( r*c < items.count() ) // remainders + ++r; + + QSize s; + if( o == Horizontal ) { + s.setWidth( c*itemExtent() ); + s.setHeight( r*itemExtent() ); + } + else { + s.setWidth( r*itemExtent() ); + s.setHeight( c*itemExtent() ); + } + + return s; +} + +void KasBar::updateLayout() +{ +// kdDebug(1345) << "KasBar: updateLayout(), count is " << items.count() << endl; + if ( !isUpdatesEnabled() ) + return; + bool updates = isUpdatesEnabled(); + setUpdatesEnabled( false ); + +// This is for testing a rectangular layout +// boxesPerLine_ = (uint) ceil(sqrt( items.count() )); + + // Work out the number of rows and columns + unsigned int r=0, c=0; + if( items.count() > (unsigned int) boxesPerLine_ ) { + r = items.count()/boxesPerLine_; + c = boxesPerLine_; + } + else{ + r = 1; + c = items.count(); + } + + if( r*c < items.count() ) // remainders + ++r; + + QSize sz; + if ( orient == Horizontal ) + sz = QSize( c * itemExtent(), r * itemExtent() ); + else + sz = QSize( r * itemExtent(), c * itemExtent() ); + + if ( sz != size() ) { + resize( sz ); + } + + setUpdatesEnabled( updates ); + + QWidget *top = topLevelWidget(); + QRegion mask; + + KasItem *i; + if ( orient == Horizontal ) { + for ( i = items.first(); i; i = items.next() ) { + int x = (items.at() % c) * itemExtent(); + + if ( direction_ == QBoxLayout::RightToLeft ) + x = width() - x - itemExtent(); + + i->setPos( x, (items.at() / c) * itemExtent() ); + i->update(); + mask = mask.unite( QRegion( QRect( i->pos(), QSize(itemExtent(),itemExtent()) ) ) ); + } + } + else { + for ( i = items.first(); i; i = items.next() ) { + int y = (items.at() / r) * itemExtent(); + + if ( direction_ == QBoxLayout::BottomToTop ) + y = height() - y - itemExtent(); + + i->setPos( (items.at() % r) * itemExtent(), y ); + i->update(); + mask = mask.unite( QRegion( QRect( i->pos(), QSize(itemExtent(),itemExtent()) ) ) ); + } + } + + if ( useMask_ ) + top->setMask( mask ); + else + top->clearMask(); + update(); +} + +void KasBar::rereadMaster() +{ + if ( !master_ ) + return; + + setItemSize( master_->itemSize() ); + setTint( master_->hasTint() ); + setTintColor( master_->tintColor() ); + setTintAmount( master_->tintAmount() ); +} + +void KasBar::append( KasItem *i ) +{ + if ( !i ) + return; + + items.append( i ); + updateLayout(); +} + +void KasBar::insert( int index, KasItem *i ) +{ + if ( (!i) || (index < 0) ) + return; + + items.insert( index, i ); + updateLayout(); +} + +void KasBar::remove( KasItem *i ) +{ + items.remove( i ); + + if ( i == itemUnderMouse_ ) + itemUnderMouse_ = 0; + updateLayout(); +} + +void KasBar::clear() +{ + items.clear(); + itemUnderMouse_ = 0; + updateLayout(); +} + +void KasBar::mousePressEvent(QMouseEvent *ev) +{ + KasItem *i = itemAt( ev->pos() ); + if ( i ) + i->mousePressEvent( ev ); + + pressPos = ev->globalPos(); +} + +void KasBar::mouseReleaseEvent(QMouseEvent *ev) +{ + if ( !inDrag ) { + KasItem *i = itemAt( ev->pos() ); + if ( i ) + i->mouseReleaseEvent( ev ); + } + else if ( detached ) { + setDetachedPosition( pos() ); + emit configChanged(); + } + + pressPos = QPoint(); + inDrag = false; +} + +void KasBar::updateMouseOver() +{ + updateMouseOver( mapFromGlobal( QCursor::pos() ) ); +} + +void KasBar::updateMouseOver( QPoint pos ) +{ + KasItem *i = itemAt(pos); + + if ( i == itemUnderMouse_ ) + return; + + if ( itemUnderMouse_ ) + itemUnderMouse_->mouseLeave(); + if ( i ) + i->mouseEnter(); + if ( i && itemUnderMouse_ ) + itemUnderMouse_->hidePopup(); + + itemUnderMouse_ = i; +} + +void KasBar::mouseMoveEvent(QMouseEvent *ev) +{ + if ( detached && (!pressPos.isNull()) ) { + QPoint moved = ev->globalPos() - pressPos; + + if ( !inDrag ) { + if ( moved.manhattanLength() > 6 ) { + inDrag = true; + emit dragStarted(); + } + } + + if ( inDrag ) { + if ( itemUnderMouse_ ) + itemUnderMouse_->hidePopup(); + + move( pos() + moved ); + pressPos = ev->globalPos(); + } + } + else { + updateMouseOver( ev->pos() ); + } +} + +void KasBar::dragMoveEvent ( QDragMoveEvent *ev ) +{ + KasItem *i = itemAt( ev->pos() ); + if ( itemUnderMouse_ != i ) { + if ( itemUnderMouse_ ) + itemUnderMouse_->dragLeave(); + if ( i ) + i->dragEnter(); + itemUnderMouse_ = i; + } +} + +void KasBar::paintEvent(QPaintEvent *ev) +{ + QPainter q( this ); + q.drawPixmap( ev->rect().topLeft(), offscreen, ev->rect() ); +} + +void KasBar::resizeEvent(QResizeEvent *ev) +{ + offscreen.resize( ev->size() ); + QPainter p( &offscreen ); + paintBackground( &p, QRect(QPoint(0,0),size()) ); + QWidget::resizeEvent(ev); + emit layoutChanged(); +} + + +QPoint KasBar::itemPos( KasItem *i ) +{ + return i->pos(); +} + +void KasBar::updateItem( KasItem *i ) +{ + if ( !i ) + return; + if ( !isShown() ) + return; + + QPainter p( &offscreen ); + QPoint pos = i->pos(); + + paintBackground( &p, QRect( pos, QSize( itemExtent(), itemExtent() ) ) ); + i->paint( &p, pos.x(), pos.y() ); + update( QRect( pos, QSize( itemExtent(), itemExtent() ) ) ); +} + +void KasBar::repaintItem(KasItem *i, bool erase ) +{ + if ( !i ) + return; + if ( !isShown() ) + return; + + QPainter p( &offscreen ); + QPoint pos = i->pos(); + + paintBackground( &p, QRect( pos, QSize( itemExtent(), itemExtent() ) ) ); + i->paint( &p, pos.x(), pos.y() ); + repaint( QRect( pos, QSize( itemExtent(), itemExtent() ) ), transparent_ || erase ); +} + +KasItem* KasBar::itemAt(const QPoint &p) +{ + KasItem *i; + QRect cr; + + for (i = items.first(); i; i = items.next()) { + cr.setTopLeft( i->pos() ); + cr.setSize( QSize( itemExtent(), itemExtent() ) ); + + if(cr.contains(p)) + return i; + } + + return 0; +} + +void KasBar::setBackground( const QPixmap &newBg ) +{ + bg = newBg; + + QPainter p( &offscreen ); + paintBackground( &p, QRect(QPoint(0,0),size()) ); + + updateLayout(); +} + +void KasBar::setMasked( bool mask ) +{ + if ( useMask_ == mask ) + return; + + useMask_ = mask; +} + +void KasBar::setPaintInactiveFrames( bool enable ) +{ + paintInactiveFrame_ = enable; + update(); +} + +void KasBar::paintBackground( QPainter *p, const QRect &r ) +{ + // If we're transparent + if ( transparent_ ) { + if ( !bg.isNull() ) { + p->drawPixmap( r.topLeft(), bg, r ); + return; + } + } +} + +void KasBar::addTestItems() +{ + KasItem *i = new KasItem( this ); + insert( 0, i ); + i->setText( "Animated" ); + i->setIcon( KGlobal::iconLoader()->loadIcon( "icons", KIcon::NoGroup, KIcon::SizeMedium ) ); + i->setAnimation( resources()->startupAnimation() ); + QTimer *aniTimer = new QTimer( i ); + connect( aniTimer, SIGNAL( timeout() ), i, SLOT( advanceAnimation() ) ); + aniTimer->start( 100 ); + i->setShowAnimation( true ); + + updateLayout(); +} diff --git a/kicker/extensions/kasbar/kasbar.h b/kicker/extensions/kasbar/kasbar.h new file mode 100644 index 000000000..297291d4f --- /dev/null +++ b/kicker/extensions/kasbar/kasbar.h @@ -0,0 +1,318 @@ +// -*- c++ -*- + +/* kasbar.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + + +#ifndef __KASBAR_H +#define __KASBAR_H + +#include <qwidget.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <qlayout.h> + +#include "kasresources.h" + +class KRootPixmap; + +class KasItem; +class KasResources; + +typedef QPtrList<KasItem> KasItemList; + + +/** + * The main view for KasBar. + */ +class KDE_EXPORT KasBar : public QWidget +{ + Q_OBJECT + Q_PROPERTY( int maxBoxes READ maxBoxes ) + Q_PROPERTY( uint boxesPerLine READ boxesPerLine ) + Q_PROPERTY( Direction direction READ direction ) + Q_PROPERTY( Orientation orientation READ orientation ) + Q_PROPERTY( bool masked READ isMasked ) + Q_ENUMS( Direction ) + + friend class KasItem; +public: + KasBar( Orientation o, QWidget *parent=0, const char *name=0, WFlags f=0 ); + KasBar( Orientation o, KasBar *master, + QWidget* parent=0, const char* name=0, WFlags f=0 ); + + virtual ~KasBar(); + + typedef QBoxLayout::Direction Direction; + + /** Returns true iff this is a top-level bar. This is unrelated to it being a top-level widget. */ + bool isTopLevel() const { return !master_; } + + /** Returns the bar from which this bar inherits its settings (or 0 if this is the top-level bar). */ + KasBar *master() const { return master_; } + + /** Creates a child bar of the kasbar. The child will inherit the appearance options. */ + virtual KasBar *createChildBar( Orientation o, QWidget *parent, const char *name=0 ); + + /** Factory method that returns the singleton resources object. */ + virtual KasResources *resources(); + + /** Returns true iff we have a resources object. */ + bool hasResources() const { return (res ? true : false); } + + // + // Item management + // + void append( KasItem *i ); + void insert( int index, KasItem *i ); + void remove( KasItem *i ); + void clear(); + KasItem *take( KasItem *i ) { return items.take( indexOf(i) ); } + KasItem *itemAt( uint i ) { return items.at( i ); } + int indexOf( KasItem *i ) { return items.find( i ); } + + KasItemList *itemList() { return &items; } + + // + // Layout options. + // + + /** The possible item sizes. */ + enum ItemSize { Enormous, Huge, Large, Medium, Small, Custom }; + + int itemSize() const { return itemSize_; } + int itemExtent() const { return itemExtent_; } + + /** The number of items in the bar. */ + unsigned int itemCount() const { return items.count(); } + + int maxBoxes() const { return maxBoxes_; } + uint boxesPerLine() const { return boxesPerLine_; } + + void setOrientation( Orientation o ); + Orientation orientation() const { return orient; } + + void setDirection( Direction dir ); + Direction direction() const { return direction_; } + + bool isDetached() const { return detached; } + QPoint detachedPosition() const { return detachedPos; } + + bool isDrag() const { return inDrag; } + + QSize sizeHint( Orientation, QSize max ); + + // + // Look and feel options + // + + bool isMasked() const { return useMask_; } + + /** Is transparency enabled? */ + bool isTransparent() const { return transparent_; } + + /** Is tinting enabled? */ + bool hasTint() const { return enableTint_; } + + /** Sets the amount and color of the tint. */ + void setTint( double amount, QColor color ); + + /** Sets the amount of tinting. */ + void setTintAmount( double amount ) { setTint( amount, tintColour_ ); } + + /** Get the amount of tinting. */ + double tintAmount() const { return tintAmount_; } + + /** Get the color of the tint. */ + QColor tintColor() const { return tintColour_; } + + /** Returns true iff we will paint frames around inactive items. */ + bool paintInactiveFrames() const { return paintInactiveFrame_; } + + // + // Utilities + // + + void updateItem( KasItem *i ); + + /** Redraws the specified item. */ + void repaintItem(KasItem *i, bool erase = true ); + + /** Returns the item at p or 0. */ + KasItem* itemAt(const QPoint &p); + + /** Get the position of the specified item. */ + QPoint itemPos( KasItem *i ); + + /** The item under the mouse pointer (or 0). */ + KasItem *itemUnderMouse() const { return itemUnderMouse_; } + +public slots: + // + // Layout slots + // + void setMaxBoxes( int count ); + void setBoxesPerLine( int count ); + + void setItemSize( int size ); + void setItemExtent( int size ); + void setDetachedPosition( const QPoint &pos ); + + virtual void updateLayout(); + + void updateMouseOver(); + void updateMouseOver( QPoint pos ); + + /** Enable or disable tinting. */ + void setTint( bool enable ); + + /** Enable or disable transparency. */ + void setTransparent( bool enable ); + + /** Set the color of the tint. */ + void setTintColor( const QColor &c ); + + /** Set the strength of the tint (as a percentage). */ + void setTintAmount( int percent ); + + void setBackground( const QPixmap &pix ); + + void setMasked( bool mask ); + + void setPaintInactiveFrames( bool enable ); + + void toggleOrientation(); + void toggleDetached(); + void setDetached( bool detach ); + + /** Rereads the configuration of the master Kasbar. */ + virtual void rereadMaster(); + + virtual void addTestItems(); + +signals: + + void detachedChanged( bool ); + void detachedPositionChanged( const QPoint & ); + void dragStarted(); + + void directionChanged(); + + /** Emitted when kasbar wants to resize. This happens when a new window is added. */ + void layoutChanged(); + + /** Emitted when the item size is changed. */ + void itemSizeChanged( int ); + + void configChanged(); + +protected: + KRootPixmap *rootPixmap() const { return rootPix; } + + /** Displays the popup menus, hides/shows windows. */ + void mousePressEvent(QMouseEvent *ev); + + /** Displays the popup menus, hides/shows windows. */ + void mouseReleaseEvent(QMouseEvent *ev); + + /** Overridden to implement the mouse-over highlight effect. */ + void mouseMoveEvent(QMouseEvent *ev); + + /** Overridden to implement the drag-over task switching. */ + void dragMoveEvent(QDragMoveEvent *ev); + + /** Paints the background of the item to the painter. */ + void paintBackground( QPainter *p, const QRect &r ); + + /** Calls the paint methods for the items in the rectangle specified by the event. */ + void paintEvent(QPaintEvent *ev); + + /** Forces the widget to re-layout it's contents. */ + void resizeEvent(QResizeEvent *ev); + +private: + // Core data + QPixmap offscreen; + KasBar *master_; + KasItemList items; + Orientation orient; + Direction direction_; + KasItem *itemUnderMouse_; + uint boxesPerLine_; + QPoint pressPos; + bool inDrag; + bool detached; + int maxBoxes_; + int itemSize_; + int itemExtent_; + QPoint detachedPos; + bool paintInactiveFrame_; + + // Implements pseudo-transparency + bool transparent_; + KPixmap bg; + KRootPixmap *rootPix; + bool enableTint_; + double tintAmount_; + QColor tintColour_; + bool useMask_; + + // Look and feel resources + KasResources *res; +}; + + + +#endif diff --git a/kicker/extensions/kasbar/kasbarapp.cpp b/kicker/extensions/kasbar/kasbarapp.cpp new file mode 100644 index 000000000..6c006af16 --- /dev/null +++ b/kicker/extensions/kasbar/kasbarapp.cpp @@ -0,0 +1,125 @@ +/* test_kasbar.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <dcopclient.h> +#include <kwin.h> +#include <kglobal.h> +#include <klocale.h> + +#include "kasitem.h" +#include "kastasker.h" +#include "kasclockitem.h" +#include "kasloaditem.h" + +#include "version.h" + +static KCmdLineOptions options[] = +{ + { "test", "Test the basic kasbar code", 0 }, + KCmdLineLastOption +}; + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "kasbar", "KasBar", I18N_NOOP( "An alternative task manager" ), VERSION_STRING ); + KCmdLineArgs::addCmdLineOptions( options ); + KGlobal::locale()->setMainCatalogue( "kasbarextension" ); + KApplication app; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + kdDebug(1345) << "Kasbar starting..." << endl; + + int wflags = Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_DialogBorder | Qt::WStyle_StaysOnTop; + KasBar *kasbar; + KConfig conf( "kasbarrc" ); + + if ( args->isSet("test") ) { + kasbar = new KasBar( Qt::Vertical, 0, "testkas", wflags ); + kasbar->setItemSize( KasBar::Large ); + kasbar->append( new KasClockItem(kasbar) ); + kasbar->append( new KasItem(kasbar) ); + kasbar->append( new KasLoadItem(kasbar) ); + kasbar->append( new KasItem(kasbar) ); + kasbar->addTestItems(); + } + else { + KasTasker *kastasker = new KasTasker( Qt::Vertical, 0, "testkas", wflags ); + kastasker->setConfig( &conf ); + kastasker->setStandAlone( true ); + kasbar = kastasker; + + kastasker->readConfig(); + kastasker->move( kastasker->detachedPosition() ); + kastasker->connect( kastasker->resources(), SIGNAL(changed()), SLOT(readConfig()) ); + kastasker->refreshAll(); + } + + kdDebug(1345) << "Kasbar about to show" << endl; + app.setMainWidget( kasbar ); + kasbar->show(); + + kasbar->setDetached( true ); + KWin::setOnAllDesktops( kasbar->winId(), true ); + kdDebug() << "kasbar: Window id is " << kasbar->winId() << endl; + + KApplication::kApplication()->dcopClient()->registerAs( "kasbar" ); + + app.connect( &app, SIGNAL( lastWindowClosed() ), SLOT(quit()) ); + + return app.exec(); +} + diff --git a/kicker/extensions/kasbar/kasbarextension.cpp b/kicker/extensions/kasbar/kasbarextension.cpp new file mode 100644 index 000000000..9b1e2435e --- /dev/null +++ b/kicker/extensions/kasbar/kasbarextension.cpp @@ -0,0 +1,189 @@ +/* kasbarextension.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qlayout.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kconfig.h> + +#include <kmessagebox.h> + +#include "kastasker.h" +#include "kasprefsdlg.h" +#include "kasaboutdlg.h" + +#include "version.h" + +#include "kasbarextension.h" +#include "kasbarextension.moc" + +extern "C" +{ + KDE_EXPORT KPanelExtension *init( QWidget *parent, const QString& configFile ) + { + KGlobal::locale()->insertCatalogue("kasbarextension"); + return new KasBarExtension( configFile, + KPanelExtension::Normal, + KPanelExtension::About | KPanelExtension::Preferences, + parent, "kasbarextension"); + } +} + +KasBarExtension::KasBarExtension( const QString& configFile, + Type type, + int actions, + QWidget *parent, const char *name ) + : KPanelExtension( configFile, type, actions, parent, name ), + detached_( false ) +{ + kdDebug(1345) << "KasBarExtension: Created '" << name << "', '" << configFile << "'" << endl; +// KApplication::kApplication()->dcopClient()->registerAs( "kasbar" ); + +// setBackgroundMode( NoBackground ); + kasbar = new KasTasker( orientation(), this, name ); + + connect( kasbar, SIGNAL( layoutChanged() ), this, SIGNAL( updateLayout() ) ); + connect( kasbar, SIGNAL( detachedChanged(bool) ), this, SLOT( setDetached(bool) ) ); + + kasbar->setConfig( config() ); + kasbar->readConfig(); + kasbar->refreshAll(); +} + +KasBarExtension::~KasBarExtension() +{ + if ( detached_ && (!kasbar.isNull()) ) + kasbar->deleteLater(); + KGlobal::locale()->removeCatalogue("kasbarextension"); +} + +void KasBarExtension::setDetached( bool detach ) +{ + if ( detach == detached_ ) + return; + + detached_ = detach; + + if ( detach ) { + + int wflags = Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_DialogBorder | Qt::WStyle_StaysOnTop; + kasbar->reparent( 0, wflags, kasbar->detachedPosition(), true ); + updateGeometry(); + resize( detachedSize() ); + } + else { + kasbar->reparent( this, QPoint(0,0), true ); + kasbar->setOrientation( orientation() ); + + updateGeometry(); + resize( kasbar->size() ); + } + + emit updateLayout(); +} + +void KasBarExtension::showEvent( QShowEvent */*se*/ ) +{ + updateGeometry(); + resize( kasbar->size() ); + repaint( true ); +} + +QSize KasBarExtension::detachedSize() +{ + if ( orientation() == Vertical ) + return QSize( kasbar->itemExtent()/2, 0 ); + else + return QSize( 0, kasbar->itemExtent()/2 ); + +} + +QSize KasBarExtension::sizeHint(Position p, QSize maxSize ) const +{ + Orientation o = Horizontal; + + if ( p == Left || p == Right ) + o = Vertical; + + if ( detached_ ) { + if ( o == Vertical ) + return QSize( kasbar->itemExtent()/2, 0 ); + else + return QSize( 0, kasbar->itemExtent()/2 ); + } + + return kasbar->sizeHint( o, maxSize ); +} + +void KasBarExtension::positionChange( Position /* position */) +{ + kasbar->setOrientation( orientation() ); + kasbar->updateLayout(); + kasbar->refreshIconGeometry(); +} + +void KasBarExtension::about() +{ + kasbar->showAbout(); +} + +void KasBarExtension::preferences() +{ + kasbar->showPreferences(); +} + diff --git a/kicker/extensions/kasbar/kasbarextension.desktop b/kicker/extensions/kasbar/kasbarextension.desktop new file mode 100644 index 000000000..59497c00b --- /dev/null +++ b/kicker/extensions/kasbar/kasbarextension.desktop @@ -0,0 +1,109 @@ +[Desktop Entry] +Name=KasBar +Name[af]=Kasbar +Name[bg]=Ðлтернативен панел +Name[cs]=Kasbar +Name[csb]=Lëstew dzejaniów (Kasbar) +Name[de]=Kasbar +Name[eo]=Kasbaro +Name[fy]=Kasbar +Name[he]=שורת משימות חלופית +Name[hi]=कास-बार +Name[is]=Kasbar +Name[it]=Kasbar +Name[lo]=ຄາສບາຣ - K +Name[lv]=KasJosla +Name[mn]=Kasbar +Name[nb]=Kasbar +Name[ne]=कासबार +Name[nl]=Kasbar +Name[nso]=Bar ya Kas +Name[pa]=ਕਸ-ਬਾਰ +Name[pl]=Pasek zadaÅ„ (Kasbar) +Name[sv]=Kasbar +Name[te]=కాసౠబారౠ+Name[tg]=Ðавори Kas +Name[th]=คาสบาร์ +Name[zu]=I-KasBar + +Comment=An alternative taskbar panel applet. +Comment[af]='n Alternatiewe taakbalk paneel miniprogram. +Comment[az]=Alternatif bir vÉ™zifÉ™ çubuÄŸu programcığı. +Comment[be]=ÐльтÑÑ€Ð½Ð°Ñ‚Ñ‹ÑžÐ½Ð°Ñ Ð¿Ð°Ð½Ñль заданнÑÑž. +Comment[bg]=Ðлтернативен аплет за лентата ÑÑŠÑ Ð·Ð°Ð´Ð°Ñ‡Ð¸Ñ‚Ðµ +Comment[bn]=টাসà§à¦•à¦¬à¦¾à¦° পà§à¦¯à¦¾à¦¨à§‡à¦² অà§à¦¯à¦¾à¦ªà¦²à§‡à¦Ÿ-à¦à¦° à¦à¦•à¦Ÿà¦¿ বিকলà§à¦ª +Comment[br]=Arloadig barrenn poelladoù dazeilat evit ar bannell. +Comment[bs]=Panelski applet - alternativni taskbar +Comment[ca]=Un applet per al plafó alternatiu a la barra de tasques. +Comment[cs]=Applet s alternativnÃm pruhem úloh +Comment[csb]=Alternatiwnô lëstew dzejaniów dlô panelu. +Comment[cy]=Rhaglennig bar tasgau arall i'r panel +Comment[da]=Et alternativt opgavelinjepanelprogram. +Comment[de]=Eine alternative Fensterleiste +Comment[el]=Μία εναλλακτική μικÏοεφαÏμογή γÏαμμής εÏγασιών για τον πίνακα. +Comment[eo]=Alternativa taskostria panelaplikaĵeto +Comment[es]=Barra de tareas alternativa (miniaplicación del panel). +Comment[et]=Teistsugune paneelil töötav tegumiriba aplett +Comment[eu]=Ataza-barra alternatiboa (paneleko appleta) +Comment[fa]=یک برنامک تابلوی میله تکلی٠متÙاوت. +Comment[fi]=Vaihtoehtoinen ohjelmalistasovelma. +Comment[fr]=Une autre applet de barre des tâches +Comment[fy]=In alternative taakbalke panielapplet. +Comment[gl]=Unha applet de barra de tarefas alternativa para o painel +Comment[he]=יישומון שורת משימות חלופי עבור הלוח +Comment[hi]=à¤à¤• वैकलà¥à¤ªà¤¿à¤• कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ फलक à¤à¤ªà¤²à¥‡à¤Ÿ +Comment[hr]=Alternativni aplet trake zadataka +Comment[hu]=Egy feladatlista-alternatÃva panel-kisalkalmazásként. +Comment[id]=Aplet panel taskbar alternatif +Comment[is]=Annað verkspjald en það sjálfgefna. +Comment[it]=Applet alternativa per la barra delle applicazioni +Comment[ja]=代替ã®ã‚¿ã‚¹ã‚¯ãƒãƒ¼ãƒ‘ãƒãƒ«ã‚¢ãƒ—レット +Comment[ka]=áƒáƒšáƒ¢áƒ”რნáƒáƒ¢áƒ˜áƒ£áƒšáƒ˜ áƒáƒ›áƒáƒªáƒáƒœáƒáƒ—რპáƒáƒœáƒ”ლის áƒáƒžáƒšáƒ”ტი +Comment[kk]=ҚоÑымша тапÑырмалар панель апплеті. +Comment[km]=អាប់ភ្លáŸážâ€‹áž”ន្ទះ​របារ​ភារកិច្ច​ជំនួស ។ +Comment[lo]=à»àºàº¥à»àºžàº±àº”ຖາດຫນ້າຕ່າງງານà»àºšàºšàºàº·à»ˆàº™ +Comment[lt]=Alternatyvi užduoÄių pulto priemonÄ—. +Comment[lv]=AlternatÄ«vs uzdevumjoslas paneļa aplets. +Comment[mk]=Ðплет од панелот - алтернативна лента Ñо програми. +Comment[mn]=Хоёрдогч цонхны Ñамбар +Comment[ms]=Aplet panel 'taskbar' alternatif. +Comment[mt]=Applet alternattiva għall-panel tat-taskbar +Comment[nb]=En alternativ oppgavelinje som panelprogram. +Comment[nds]=En anner Lüttprogramm för den Paneel-Programmbalken +Comment[ne]=वैकलà¥à¤ªà¤¿à¤• कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ पà¥à¤¯à¤¾à¤¨à¤² à¤à¤ªà¥à¤²à¥‡à¤Ÿ +Comment[nl]=Een alternatieve taakbalk paneelapplet. +Comment[nn]=Ei alternativ oppgÃ¥velinje til panelet. +Comment[nso]=Applet yenngwe ya panel ya bar ya mosongwana. +Comment[oc]=Un aplet dèu plafon alternatiu de la barra de tasques. +Comment[pa]=ਇੱਕ ਬਦਲਵੀਂ ਕੰਮ-ਪੱਟੀ à¨à¨ªà¨²à¨¿à¨Ÿ +Comment[pl]=Alternatywny pasek zadaÅ„ dla panelu. +Comment[pt]=Uma barra de tarefas alternativa. +Comment[pt_BR]=Um mini-aplicativo de painel alternativo para a barra de tarefas. +Comment[ro]=O alternativă la miniaplicaÈ›ia bară de procese. +Comment[ru]=Ðплет альтернативной панели задач. +Comment[rw]=Apuleti y'umwanya w'umurongoibikorwa usimbura +Comment[se]=EavttolaÅ¡ bargoholga panelii +Comment[sk]=AlternatÃvny panel úloh +Comment[sl]=Vstavek za alternativno opravilno vrstico na pultu +Comment[sr]=Ðлтернативни аплет траке задатака за панел. +Comment[sr@Latn]=Alternativni aplet trake zadataka za panel. +Comment[sv]=Alternativt miniprogram till aktivitetsfältet +Comment[ta]=மாறà¯à®±à¯à®µà®´à®¿ பணிபடà¯à®Ÿà®¿ பலக சிறà¯à®¨à®¿à®°à®²à¯ +Comment[tg]=Барномаи Ñафҳаи маÑъалаҳои алтернативӣ +Comment[th]=à¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸•à¸–าดหน้าต่างงานà¹à¸šà¸šà¸à¸·à¹ˆà¸™ +Comment[tr]=Alternatif bir görev çubuÄŸu programcığı. +Comment[tt]=AlmaÅŸ yöktirä taqtasınıñ applete. +Comment[uk]=Ðльтернативний аплет Ñмужки задач. +Comment[ven]=Apulete phanele ine nanga shumisa yone ya bara ya mushumo. +Comment[vi]=Má»™t tiểu ứng dụng khác cÅ©ng có bảng Ä‘iểu khiển chứa thanh tác vụ. +Comment[wa]=Ene ôte aplikete di bÃ¥r des bouyes do scriftôr +Comment[xh]=I applet yeqela lenjongo ethile yebar yomsebenzi olandelelanayo. +Comment[zh_CN]=备选的任务æ é¢æ¿å°ç¨‹åºã€‚ +Comment[zh_TW]=å¯ä¾›é¸æ“‡çš„å¦å¤–一個工作列é¢æ¿å°ç¨‹å¼ã€‚ +Comment[zu]=Enye i-applet yewindi lemininingwane yebha yemisebenzi + +Icon=kasbar + +X-KDE-Library=kasbar_panelextension +X-KDE-UniqueApplet=true +X-KDE-PanelExt-Positions=Right,Left,Top,Bottom diff --git a/kicker/extensions/kasbar/kasbarextension.h b/kicker/extensions/kasbar/kasbarextension.h new file mode 100644 index 000000000..e85750d40 --- /dev/null +++ b/kicker/extensions/kasbar/kasbarextension.h @@ -0,0 +1,101 @@ +/* kasbarextension.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASBAREXTENSION_H +#define KASBAREXTENSION_H + +#include <qguardedptr.h> +#include <kpanelextension.h> + +class KasTasker; + +/** + * A KPanelExtension that displays a KasTasker widget. + */ +class KasBarExtension : public KPanelExtension +{ + Q_OBJECT + +public: + KasBarExtension( const QString& configFile, + Type t = Normal, + int actions = 0, + QWidget *parent = 0, const char *name = 0 ); + + virtual ~KasBarExtension(); + + QSize sizeHint( Position, QSize maxSize ) const; + Position preferedPosition() const { return Right; } + + virtual void positionChange( Position position ); + + bool isDetached() const { return detached_; } + QSize detachedSize(); + +public slots: + void setDetached( bool detach ); + +protected: + void showEvent( QShowEvent *se ); + virtual void about(); + virtual void preferences(); + +private: + QGuardedPtr<KasTasker> kasbar; + bool detached_; +}; + +#endif // KASBAREXTENSION_H + diff --git a/kicker/extensions/kasbar/kasclockitem.cpp b/kicker/extensions/kasbar/kasclockitem.cpp new file mode 100644 index 000000000..0292a93cb --- /dev/null +++ b/kicker/extensions/kasbar/kasclockitem.cpp @@ -0,0 +1,120 @@ +#include <qpainter.h> +#include <qbitmap.h> +#include <qdatetime.h> +#include <qdrawutil.h> +#include <qlcdnumber.h> +#include <qtimer.h> + +#include <kdatepicker.h> +#include <kglobal.h> +#include <kwin.h> +#include <kiconloader.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kpopupmenu.h> + +#include <taskmanager.h> + +#include "kaspopup.h" +#include "kastasker.h" + +#include "kasclockitem.h" +#include "kasclockitem.moc" + +class LCD : public QLCDNumber +{ +public: + LCD( QWidget *parent, const char *name=0 ) + : QLCDNumber(parent,name) {} + ~LCD() {} + + void draw( QPainter *p ) { drawContents(p); } +}; + +KasClockItem::KasClockItem( KasBar *parent ) + : KasItem( parent ) +{ + setCustomPopup( true ); + + QTimer *t = new QTimer( this ); + connect( t, SIGNAL( timeout() ), SLOT( updateTime() ) ); + t->start( 1000 ); + + lcd = new LCD( parent ); + lcd->hide(); + + lcd->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); + lcd->setBackgroundMode( NoBackground ); + lcd->setFrameStyle( QFrame::NoFrame ); + lcd->setSegmentStyle( QLCDNumber::Flat ); + lcd->setNumDigits( 5 ); + lcd->setAutoMask( true ); + updateTime(); + + connect( this, SIGNAL(leftButtonClicked(QMouseEvent *)), SLOT(togglePopup()) ); + connect( this, SIGNAL(rightButtonClicked(QMouseEvent *)), SLOT(showMenuAt(QMouseEvent *) ) ); +} + +KasClockItem::~KasClockItem() +{ + delete lcd; +} + +KasPopup *KasClockItem::createPopup() +{ + KasPopup *pop = new KasPopup( this ); + setPopup( pop ); + + (void) new KDatePicker( pop ); + pop->adjustSize(); + + return pop; +} + +void KasClockItem::updateTime() +{ + setText( KGlobal::locale()->formatDate( QDate::currentDate(), true /* shortFormat */ ) ); + lcd->display( KGlobal::locale()->formatTime( QTime::currentTime(), false /* includeSecs */, false /* isDuration */) ); + + update(); +} + +void KasClockItem::paint( QPainter *p ) +{ + KasItem::paint( p ); + + lcd->setGeometry( QRect( 0, 0, extent(), extent()-15 ) ); + + p->save(); + p->translate( 3, 15 ); + lcd->setPaletteForegroundColor( kasbar()->colorGroup().mid() ); + lcd->draw( p ); + p->restore(); + + p->save(); + p->translate( 1, 13 ); + lcd->setPaletteForegroundColor( resources()->activePenColor() ); + lcd->draw( p ); + p->restore(); +} + +void KasClockItem::showMenuAt( QMouseEvent *ev ) +{ + hidePopup(); + showMenuAt( ev->globalPos() ); +} + +void KasClockItem::showMenuAt( QPoint p ) +{ + mouseLeave(); + kasbar()->updateMouseOver(); + + KasTasker *bar = dynamic_cast<KasTasker *> (KasItem::kasbar()); + if ( !bar ) + return; + + KPopupMenu *menu = bar->contextMenu(); + menu->exec( p ); +} diff --git a/kicker/extensions/kasbar/kasclockitem.h b/kicker/extensions/kasbar/kasclockitem.h new file mode 100644 index 000000000..380901765 --- /dev/null +++ b/kicker/extensions/kasbar/kasclockitem.h @@ -0,0 +1,37 @@ +// -*- c++ -*- + + +#ifndef KASCLOCKITEM_H +#define KASCLOCKITEM_H + +#include "kasitem.h" + +/** + * An item that displays a clock. + */ +class KDE_EXPORT KasClockItem : public KasItem +{ + Q_OBJECT + +public: + KasClockItem( KasBar *parent ); + virtual ~KasClockItem(); + + void paint( QPainter *p ); + +public slots: + void updateTime(); + + void showMenuAt( QMouseEvent *ev ); + void showMenuAt( QPoint p ); + +protected: + /** Reimplemented from KasItem to create a date picker. */ + virtual KasPopup *createPopup(); + +private: + class LCD *lcd; +}; + +#endif // KASCLOCKITEM_H + diff --git a/kicker/extensions/kasbar/kasgrouper.cpp b/kicker/extensions/kasbar/kasgrouper.cpp new file mode 100644 index 000000000..44dcc57b5 --- /dev/null +++ b/kicker/extensions/kasbar/kasgrouper.cpp @@ -0,0 +1,156 @@ +/* kasgrouper.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#include <taskmanager.h> + +#include "kastasker.h" +#include "kasgroupitem.h" +#include "kastaskitem.h" + +#include "kasgrouper.h" + +KasGrouper::KasGrouper( KasTasker *bar ) + : kasbar( bar ) +{ +} + +KasGrouper::~KasGrouper() +{ +} + +KasItem *KasGrouper::maybeGroup( Task::Ptr t ) +{ + KasItem *item = 0; + + if ( kasbar->groupInactiveDesktops() ) + item = maybeAddToDesktopGroup( t ); + if ( item ) + return item; + + if ( kasbar->groupWindows() ) + item = maybeAddToGroup( t ); + if ( item ) + return item; + + return item; +} + +KasItem *KasGrouper::maybeAddToDesktopGroup( Task::Ptr t ) +{ + if ( t->isOnCurrentDesktop() ) + return 0; + + KasItem *item = 0; + for ( uint i = 0; i < kasbar->itemCount(); i++ ) { + KasItem *ei = kasbar->itemAt( i ); + + if ( ei->inherits( "KasTaskItem" ) ) { + KasTaskItem *eti = static_cast<KasTaskItem *> (ei); + if ( eti->task()->desktop() == t->desktop() ) { + KasGroupItem *egi = kasbar->convertToGroup( eti->task() ); + egi->setGroupType( KasGroupItem::GroupDesktop ); + egi->addTask( t ); + item = egi; + } + } + else if ( ei->inherits( "KasGroupItem" ) ) { + KasGroupItem *egi = static_cast<KasGroupItem *> (ei); + if ( egi->groupType() == KasGroupItem::GroupDesktop ) { + if ( egi->task(0)->desktop() == t->desktop() ) { + egi->addTask( t ); + item = egi; + } + } + } + } + + return item; +} + +KasItem *KasGrouper::maybeAddToGroup( Task::Ptr t ) +{ + KasItem *item = 0; + + QString taskClass = t->className().lower(); + + for ( uint i = 0; (!item) && (i < kasbar->itemCount()); i++ ) { + KasItem *ei = kasbar->itemAt( i ); + + if ( ei->inherits( "KasTaskItem" ) ) { + + KasTaskItem *eti = static_cast<KasTaskItem *> (ei); + + // NB This calls Task::className() not QObject::className() + QString currClass = eti->task()->className().lower(); + + if ( Task::idMatch( currClass, taskClass ) ) { + KasGroupItem *egi = kasbar->convertToGroup( eti->task() ); + egi->addTask( t ); + item = egi; + break; + } + } + else if ( ei->inherits( "KasGroupItem" ) ) { + KasGroupItem *egi = static_cast<KasGroupItem *> (ei); + + for ( int i = 0; i < egi->taskCount(); i++ ) { + + // NB This calls Task::className() not QObject::className() + QString currClass = egi->task( i )->className().lower(); + + if ( Task::idMatch( currClass, taskClass ) ) { + egi->addTask( t ); + item = egi; + break; + } + } + } + } + + return item; +} diff --git a/kicker/extensions/kasbar/kasgrouper.h b/kicker/extensions/kasbar/kasgrouper.h new file mode 100644 index 000000000..c5beab3a6 --- /dev/null +++ b/kicker/extensions/kasbar/kasgrouper.h @@ -0,0 +1,85 @@ +// -*- c++ -*- + +/* kasgrouper.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#ifndef KASGROUPER_H +#define KASGROUPER_H + +class KasTasker; +class KasItem; +class Task; + +/** + * Assigns items in the Kasbar to groups. + * + * @author Richard Moore, rich@kde.org + */ +class KasGrouper +{ +public: + KasGrouper( KasTasker *bar ); + virtual ~KasGrouper(); + + KasItem *maybeGroup( Task::Ptr t ); + + /** If the task should be part of an inactive desktop group then make it so. */ + KasItem *maybeAddToDesktopGroup( Task::Ptr t ); + + /** If the task should be part of a group then make it so. */ + KasItem *maybeAddToGroup( Task::Ptr t ); + +private: + KasTasker *kasbar; +}; + + +#endif // KASGROUPER_H + + diff --git a/kicker/extensions/kasbar/kasgroupitem.cpp b/kicker/extensions/kasbar/kasgroupitem.cpp new file mode 100644 index 000000000..a4435f7c2 --- /dev/null +++ b/kicker/extensions/kasbar/kasgroupitem.cpp @@ -0,0 +1,305 @@ +/* kasgroupitem.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qpainter.h> +#include <qbitmap.h> +#include <qtimer.h> +#include <qwmatrix.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kwin.h> +#include <kiconloader.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> +#include <kpopupmenu.h> +#include <klocale.h> + +#include <taskmanager.h> +#include <taskrmbmenu.h> + +#include "kastasker.h" +#include "kaspopup.h" + +#include "kasgroupitem.h" +#include "kasgroupitem.moc" + + +KasGroupItem::KasGroupItem( KasTasker *parent ) + : KasItem( parent ), items(), groupType_( GroupRelated ) + +{ + setCustomPopup( true ); + setGroupItem( true ); + setText( i18n("Group") ); + + connect( parent, SIGNAL( layoutChanged() ), this, SLOT( hidePopup() ) ); + connect( parent, SIGNAL( layoutChanged() ), this, SLOT( update() ) ); + connect( this, SIGNAL(leftButtonClicked(QMouseEvent *)), SLOT(togglePopup()) ); + connect( this, SIGNAL(rightButtonClicked(QMouseEvent *)), SLOT(showGroupMenuAt(QMouseEvent *) ) ); +} + +KasGroupItem::~KasGroupItem() +{ +} + +KasTasker *KasGroupItem::kasbar() const +{ + return static_cast<KasTasker *> (KasItem::kasbar()); +} + +void KasGroupItem::addTask( Task::Ptr t ) +{ + if (!t) + return; + + items.append( t ); + if ( items.count() == 1 ) { + setText( t->visibleName() ); + updateIcon(); + } + + connect( t, SIGNAL( changed(bool) ), this, SLOT( update() ) ); + update(); +} + +void KasGroupItem::removeTask( Task::Ptr t ) +{ + if ( !t ) + return; + + hidePopup(); + + for (Task::List::iterator it = items.begin(); it != items.end();) + { + if ((*it) == t) + { + it = items.erase(it); + } + else + { + ++it; + } + } + + updateIcon(); + + if ( items.count() == 1 ) + kasbar()->moveToMain( this, items.first() ); +} + +void KasGroupItem::updateIcon() +{ + QPixmap p; + bool usedIconLoader = false; + Task::Ptr t = items.first(); + if (!t) + p = KGlobal::iconLoader()->loadIcon( "kicker", + KIcon::NoGroup, + KIcon::SizeSmall ); + + int sizes[] = { KIcon::SizeEnormous, + KIcon::SizeHuge, + KIcon::SizeLarge, + KIcon::SizeMedium, + KIcon::SizeSmall }; + + p = t->bestIcon( sizes[kasbar()->itemSize()], usedIconLoader ); + + if ( p.isNull() ) + p = KGlobal::iconLoader()->loadIcon( "error", KIcon::NoGroup, KIcon::SizeSmall ); + + setIcon( p ); +} + +void KasGroupItem::paint( QPainter *p ) +{ + KasItem::paint( p ); + + // + // Item summary info + // + int modCount = 0; + for ( Task::List::iterator it = items.begin(); it != items.end() ; ++it ) { + if ( (*it)->isModified() ) + modCount++; + } + + KasResources *res = resources(); + + p->setPen( isShowingPopup() ? res->activePenColor() : res->inactivePenColor() ); + + if ( modCount ) { + QString modCountStr; + modCountStr.setNum( modCount ); + p->drawText( extent()-fontMetrics().width( modCountStr )-3, + 15+fontMetrics().ascent(), + modCountStr ); + + p->drawPixmap( extent()-12, 29, res->modifiedIcon() ); + } + + int microsPerCol; + switch( kasbar()->itemSize() ) { + default: + case KasBar::Small: + microsPerCol = 2; + break; + case KasBar::Medium: + microsPerCol = 4; + break; + case KasBar::Large: + microsPerCol = 7; + break; + case KasBar::Huge: + microsPerCol = 9; + break; + case KasBar::Enormous: + microsPerCol = 16; + break; + } + + int xpos = 3; + int ypos = 16; + + for ( int i = 0; ( i < (int) items.count() ) && ( i < microsPerCol ); i++ ) { + Task::Ptr t = items.at( i ); + + if( t->isIconified() ) + p->drawPixmap( xpos, ypos, res->microMinIcon() ); + else if ( t->isShaded() ) + p->drawPixmap( xpos, ypos, res->microShadeIcon() ); + else + p->drawPixmap( xpos, ypos, res->microMaxIcon() ); + + ypos += 7; + } + + if ( ((int) items.count() > microsPerCol) && ( kasbar()->itemSize() != KasBar::Small ) ) { + QString countStr; + countStr.setNum( items.count() ); + p->drawText( extent()-fontMetrics().width( countStr )-3, + extent()+fontMetrics().ascent()-16, + countStr ); + } +} + +void KasGroupItem::updatePopup() +{ + if ( bar ) { + bar->rereadMaster(); + + bar->clear(); + if ( items.count() ) { + for ( Task::List::iterator t = items.begin(); t != items.end(); ++t ) { + bar->addTask( *t ); + } + } + + bar->updateLayout(); + if ( popup() ) + popup()->resize( bar->size() ); + } +} + +KasPopup *KasGroupItem::createPopup() +{ + KasPopup *pop = new KasPopup( this ); + bar = kasbar()->createChildBar( ( kasbar()->orientation() == Horizontal ) ? Vertical : Horizontal, pop ); + + connect( pop, SIGNAL(shown()), SLOT(updatePopup()) ); + + return pop; + +// // Test code +// // +// // This generates cool looking fractal-like patterns if you keep unfolding the +// // groups! +// int pos = (int) this; +// if ( pos % 2 ) +// bar->append( new KasItem( bar ) ); +// if ( pos % 5 ) +// bar->append( new KasItem( bar ) ); +// bar->append( new KasGroupItem( bar ) ); +// if ( pos % 3 ) +// bar->append( new KasItem( bar ) ); +// if ( pos % 7 ) +// bar->append( new KasItem( bar ) ); +// //////////// +} + +void KasGroupItem::ungroup() +{ + kasbar()->moveToMain( this ); +} + +void KasGroupItem::showGroupMenuAt( QMouseEvent *ev ) +{ + showGroupMenuAt( ev->globalPos() ); +} + +void KasGroupItem::showGroupMenuAt( const QPoint &p ) +{ + TaskRMBMenu *tm = new TaskRMBMenu(items, true, kasbar()); + tm->insertItem( i18n("&Ungroup" ), this, SLOT( ungroup() ) ); + tm->insertSeparator(); + tm->insertItem( i18n("&Kasbar"), kasbar()->contextMenu() ); + + setLockPopup( true ); + tm->exec( p ); + delete tm; + setLockPopup( false ); +} + + + diff --git a/kicker/extensions/kasbar/kasgroupitem.h b/kicker/extensions/kasbar/kasgroupitem.h new file mode 100644 index 000000000..348fb2839 --- /dev/null +++ b/kicker/extensions/kasbar/kasgroupitem.h @@ -0,0 +1,124 @@ +// -*- c++ -*- + +/* kasgroupitem.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + + +#ifndef KASGROUPITEM_H +#define KASGROUPITEM_H + +#include <qpixmap.h> +#include <taskmanager.h> +#include "kasitem.h" + +class KasPopup; +class KasTasker; +class KPixmap; +class Task; + +/** + * A KasItem that holds a list of Tasks. + */ +class KasGroupItem : public KasItem +{ + Q_OBJECT + +public: + enum GroupType { + GroupRelated, GroupDesktop + }; + + KasGroupItem( KasTasker *parent/*, Group *group*/ ); + virtual ~KasGroupItem(); + + uint groupType() const { return groupType_; } + void setGroupType( uint type ) { groupType_ = type; } + + /** Reimplemented to paint the item. */ + virtual void paint( QPainter *p ); + + KasTasker *kasbar() const; + + Task::Ptr task( uint i ) { return items.at( i ); } + int taskCount() const { return items.count(); } + + QPixmap icon(); + +public slots: + void addTask( Task::Ptr t ); + void removeTask( Task::Ptr t ); + + void ungroup(); + + void showGroupMenuAt( QMouseEvent *ev ); + void showGroupMenuAt( const QPoint &p ); + + void updateIcon(); + + void updatePopup(); + +protected: + /** Reimplemented to create a KasGroupPopup. */ + virtual KasPopup *createPopup(); + +private: + QString title_; + Task::List items; + uint groupType_; + KasTasker *bar; +}; + +#endif // KASGROUPITEM_H + diff --git a/kicker/extensions/kasbar/kasitem.cpp b/kicker/extensions/kasbar/kasitem.cpp new file mode 100644 index 000000000..5cd8ef7f0 --- /dev/null +++ b/kicker/extensions/kasbar/kasitem.cpp @@ -0,0 +1,566 @@ +/* kasitem.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qcursor.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qregexp.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klocale.h> + +#include "kasitem.h" + +#include "kaspopup.h" +#include "kasitem.moc" + +/* XPM */ +static const char *tiny_arrow[]={ +"5 9 2 1", +". c None", +"# c #ffffff", +"....#", +"...##", +"..###", +".####", +"#####", +".####", +"..###", +"...##", +"....#"}; + +static const int KASITEM_CHECK_POPUP_DELAY = 500; + +KasItem::KasItem( KasBar *parent ) + : QObject( parent ), + kas( parent ), popupTimer( 0 ), dragTimer( 0 ), + title( i18n( "Kasbar" ) ), + mouseOver( false ), activated( false ), + customPopup( false ), lockPopup(false), groupItem( false ), + frame(true), modified(false), attention_(false), prog( -1 ), + anim(), aniFrame( 0 ), drawAnim( false ) +{ + connect( parent, SIGNAL( dragStarted() ), SLOT( hidePopup() ) ); + connect( this, SIGNAL( middleButtonClicked(QMouseEvent *) ), parent, SLOT( toggleOrientation() ) ); +} + +KasItem::~KasItem() +{ + delete (KasPopup *) pop; +} + +void KasItem::setActive( bool yesno ) +{ + if ( activated == yesno ) + return; + + activated = yesno; + update(); +} + +void KasItem::setText( const QString &text ) +{ + if ( title == text ) + return; + + title = text; + update(); +} + +void KasItem::setIcon( const QPixmap &p ) +{ + pix = p; + update(); +} + +void KasItem::setProgress( int percent ) +{ + if ( percent == prog ) + return; + + prog = percent; + update(); +} + +void KasItem::setShowFrame( bool yes ) +{ + if ( frame == yes ) + return; + + frame = yes; + update(); +} + +void KasItem::setModified( bool yes ) +{ + if ( modified == yes ) + return; + + modified = yes; + update(); +} + +void KasItem::setAttention( bool yes ) +{ + if ( attention_ == yes ) + return; + + attention_ = yes; + update(); +} + +void KasItem::mouseEnter() +{ + static const int POPUP_DELAY = 300; + + if ( (!customPopup) && (popupTimer == 0) ) { + popupTimer = new QTimer( this, "popupTimer" ); + connect( popupTimer, SIGNAL( timeout() ), SLOT( showPopup() ) ); + popupTimer->start( POPUP_DELAY, true ); + } + + mouseOver = true; + update(); +} + +void KasItem::mouseReleaseEvent( QMouseEvent *ev ) +{ + if ( ev->button() == LeftButton ) + emit leftButtonClicked( ev ); + else if ( ev->button() == RightButton ) + emit rightButtonClicked( ev ); + else if ( ev->button() == MidButton ) + emit middleButtonClicked( ev ); +} + +// Check periodically if the popup can be hidden (hack) +void KasItem::checkPopup() +{ + if ( pop.isNull() ) + return; + if ( !pop->isVisible() ) + return; + + QWidget *w = QApplication::widgetAt( QCursor::pos() ); + if ( !w ) { + if ( popupTimer ) { + delete popupTimer; + popupTimer = 0; + } + if ( (!customPopup) && (!lockPopup) ) + hidePopup(); + } + else { + QTimer::singleShot( KASITEM_CHECK_POPUP_DELAY, this, SLOT( checkPopup() ) ); + } +} + +void KasItem::dragEnter() +{ + static const int DRAG_SWITCH_DELAY = 1000; + + if ( dragTimer == 0 ) { + dragTimer = new QTimer( this, "dragTimer" ); + connect( dragTimer, SIGNAL( timeout() ), SLOT( dragOverAction() ) ); + dragTimer->start( DRAG_SWITCH_DELAY, true ); + } + + mouseOver = true; + update(); +} + +void KasItem::mouseLeave() +{ + if ( popupTimer ) { + delete popupTimer; + popupTimer = 0; + } + + mouseOver = false; + update(); +} + +void KasItem::dragLeave() +{ + if ( dragTimer ) { + delete dragTimer; + dragTimer = 0; + } + + mouseOver = false; + update(); +} + +bool KasItem::isShowingPopup() const +{ + if ( pop.isNull() ) + return false; + return pop->isVisible(); +} + +KasPopup *KasItem::createPopup() +{ + return 0; +} + +void KasItem::showPopup() +{ + if ( pop.isNull() ) + pop = createPopup(); + + if ( pop.isNull() ) + return; + + pop->show(); + update(); + + QTimer::singleShot( KASITEM_CHECK_POPUP_DELAY, this, SLOT( checkPopup() ) ); +} + +void KasItem::hidePopup() +{ + if ( pop.isNull() ) + return; + + pop->hide(); + activated = false; + update(); +} + +void KasItem::togglePopup() +{ + if ( activated ) + hidePopup(); + else + showPopup(); +} + +void KasItem::setPopup( KasPopup *popup ) +{ + if ( pop ) + pop->deleteLater(); + pop = popup; +} + +void KasItem::paintFrame( QPainter *p ) +{ + if ( !frame ) + return; + + qDrawShadePanel(p, 0, 0, extent(), extent(), colorGroup(), false, 2); + + QPen pen; + + if ( mouseOver ) { + if ( attention_ ) { + pen = QPen( resources()->attentionColor(), 2 ); + p->setPen( pen ); + p->drawRect( 0, 0, extent(), extent()); + } + else { + pen = QPen( Qt::white ); + p->setPen( pen ); + p->drawRect(0, 0, extent(), extent()); + } + } + else if ( kas->paintInactiveFrames() ) { + p->setPen( attention_ ? resources()->attentionColor() : Qt::black ); + p->drawRect(0, 0, extent(), extent()); + } +} + +void KasItem::paintLabel( QPainter *p ) +{ + QString text = title; + + if ( !groupItem ) { + p->fillRect( 2, 2, extent()-4, 13, QBrush( resources()->labelBgColor() ) ); + + if ( isProgressItem() ) { + QRegExp reg( "(1?[0-9]?[0-9])%" ); + if ( -1 != reg.search( text ) ) { + prog = reg.cap(1).toInt(); + paintProgress( p, prog ); + } + else { + prog = 0; + } + } + + p->setFont( KGlobalSettings::taskbarFont() ); + p->setPen( resources()->labelPenColor() ); + + if ( fontMetrics().width( text ) > extent()-4 ) + p->drawText( 2, 2, extent()-4, 12, AlignLeft | AlignVCenter, text ); + else + p->drawText( 2, 2, extent()-4, 12, AlignCenter, text ); + + return; + } + else { + QPixmap arrow( tiny_arrow ); + + QPoint popupPos = KasPopup::calcPosition( this, 10, 10 ); + QPoint iPos = kas->mapToGlobal( kas->itemPos( this ) ); + QWMatrix turn; + + if ( popupPos.x() < iPos.x() ) { + paintArrowLabel( p, arrow.width(), true ); + p->drawPixmap( 3, 4, arrow ); + } + else if ( popupPos.x() == iPos.x() ) { + if ( popupPos.y() < iPos.y() ) { + turn.rotate( 90.0 ); + arrow = arrow.xForm( turn ); + paintArrowLabel( p, arrow.width(), true ); + p->drawPixmap( 3, 6, arrow ); + } + else { + turn.rotate( 270.0 ); + arrow = arrow.xForm( turn ); + paintArrowLabel( p, arrow.width(), false ); + p->drawPixmap( extent()-12, 6, arrow ); + } + } + else { + turn.rotate( 180.0 ); + arrow = arrow.xForm( turn ); + paintArrowLabel( p, arrow.width(), false ); + p->drawPixmap( extent()-8, 4, arrow ); + } + } +} + +void KasItem::paintArrowLabel( QPainter *p, int arrowSize, bool arrowOnLeft ) +{ + QString text = title; + int lx = 2; + int ly = 2; + int w = extent()-4; + int h = 13; + arrowSize+=2; // Add a space + + p->fillRect( lx, ly, w, h, QBrush( resources()->labelBgColor() ) ); + + // Adjust for arrow + if ( arrowOnLeft ) { + lx += arrowSize; + w -= arrowSize; + } + else { + w -= arrowSize; + } + + p->setFont( KGlobalSettings::taskbarFont() ); + p->setPen( resources()->labelPenColor() ); + if ( fontMetrics().width( text ) > w ) + p->drawText( lx, ly, w, h-1, AlignLeft | AlignVCenter, text ); + else + p->drawText( lx, ly, w, h-1, AlignCenter, text ); +} + +void KasItem::paintModified( QPainter *p ) +{ + if ( modified ) + p->drawPixmap(extent()-12, extent()-22, resources()->modifiedIcon() ); +} + +void KasItem::paintBackground( QPainter *p ) +{ + if ( activated ) + p->drawPixmap( 0, 0, resources()->activeBg() ); + else if ( kas->isTransparent() ) + ; + else + p->drawPixmap( 0, 0, resources()->inactiveBg() ); +} + +void KasItem::paintProgress( QPainter *p, int percent ) +{ + double amt = (extent()-4) * (percent / 100.0L); + p->fillRect( 2, 13, (int) amt, 2, QBrush( resources()->progressColor() ) ); +} + +void KasItem::paintStateIcon( QPainter *p, uint state ) +{ + if ( kas->itemSize() != KasBar::Small ) { + switch(state) { + case StateIcon: + p->drawPixmap(extent()-11, extent()-11, resources()->minIcon() ); + break; + case StateShaded: + p->drawPixmap(extent()-11, extent()-11, resources()->shadeIcon() ); + break; + case StateNormal: + p->drawPixmap(extent()-11, extent()-11, resources()->maxIcon() ); + break; + default: + break; + } + } + else { + switch(state) { + case StateIcon: + p->drawPixmap(extent()-9, extent()-9, resources()->microMinIcon() ); + break; + case StateShaded: + p->drawPixmap(extent()-9, extent()-9, resources()->microShadeIcon() ); + break; + case StateNormal: + p->drawPixmap(extent()-9, extent()-9, resources()->microMaxIcon() ); + break; + default: + break; + } + } +} + +void KasItem::paintAttention( QPainter *p ) +{ + p->setPen( resources()->attentionColor() ); + p->drawPixmap( 3, extent()-11, resources()->attentionIcon() ); +} + +void KasItem::setAnimation( const PixmapList &frames ) +{ + anim = frames; + aniFrame = 0; +} + +void KasItem::advanceAnimation() +{ + aniFrame++; + + if ( aniFrame >= anim.count() ) + aniFrame = 0; + + update(); +} + +void KasItem::setShowAnimation( bool yes ) +{ + if ( yes == drawAnim ) + return; + + drawAnim = yes; + update(); +} + +void KasItem::paintAnimation( QPainter *p ) +{ + if ( (aniFrame+1) > anim.count() ) + return; + + QPixmap pix = anim[ aniFrame ]; + if ( pix.isNull() ) + return; + + if ( kas->itemSize() == KasBar::Small ) + p->drawPixmap( 4, 16, pix ); + else + p->drawPixmap( extent()-18, 16, pix ); +} + +void KasItem::paintIcon( QPainter *p ) +{ + if ( pix.isNull() ) + return; + + int x = (extent() - 4 - pix.width()) / 2; + int y = (extent() - 15 - pix.height()) / 2; + p->drawPixmap( x-4, y+15, pix ); +} + +void KasItem::paint( QPainter *p ) +{ + paintBackground( p ); + paintFrame( p ); + paintLabel( p ); + paintIcon( p ); + + if ( drawAnim ) + paintAnimation( p ); + + if ( attention_ ) + paintAttention( p ); +} + +void KasItem::paint( QPainter *p, int x, int y ) +{ + p->save(); + p->translate( x, y ); + paint( p ); + p->restore(); +} + +void KasItem::repaint() +{ + repaint( true ); +} + +void KasItem::repaint( bool erase ) +{ + if ( kas->isVisible() ) + kas->repaintItem( this, erase ); +} + +void KasItem::update() +{ + if ( kas->isVisible() ) + kas->updateItem( this ); +} + diff --git a/kicker/extensions/kasbar/kasitem.h b/kicker/extensions/kasbar/kasitem.h new file mode 100644 index 000000000..3555d576f --- /dev/null +++ b/kicker/extensions/kasbar/kasitem.h @@ -0,0 +1,284 @@ +/* kasitem.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASITEM_H +#define KASITEM_H + +class QPainter; +class QMouseEvent; +class KasPopup; + +#include <qobject.h> +#include <qguardedptr.h> +#include <qpoint.h> +#include <qvaluevector.h> + +#include <kdemacros.h> + +#include "kasbar.h" + +/** + * Abstract base class for items that can be in a KasBar. + * + * @author Richard Moore, rich@kde.org + */ +class KDE_EXPORT KasItem : public QObject +{ + Q_OBJECT + +public: + friend class KasBar; + + typedef QValueVector<QPixmap> PixmapList; + + /** The states that a window can be in. */ + enum WindowState { + StateIcon, StateShaded, StateNormal + }; + + KasItem( KasBar *parent ); + virtual ~KasItem(); + + /** Returns the parent KasBar of this item. */ + KasBar *kasbar() const { return kas; } + + /** Returns the size of the item in pixels. */ + int extent() const { return kas->itemExtent(); } + + /** Returns the text that will be displayed in the title. */ + QString text() const { return title; } + + /** Returns the position of this item. */ + QPoint pos() const { return pos_; } + void setPos( const QPoint &p ) { pos_ = p; } + void setPos( int x, int y ) { pos_ = QPoint( x, y ); } + + /** Returns the progress so far. This will -1 if the item is not displaying progress info. */ + int progress() const { return prog; } + + /** Returns true iff this item is displaying progress info. */ + bool isProgressItem() const { return prog != -1; } + + /** Returns true iff this item will display the modified indicator. */ + bool isModified() const { return modified; } + + /** + * Returns true if this is a group item. Group items display an arrow + * showing where the popup containing their children will appear. + */ + void setGroupItem( bool enable = true ) { groupItem = enable; } + + // + // Popup + // + + /** Returns true iff this item is showing a popup. */ + bool isShowingPopup() const; + + /** Returns the active popup or 0. */ + KasPopup *popup() const { return pop; } + + /** Sets the popup to be used by this item. */ + void setPopup( KasPopup *popup ); + + /** + * Returns true iff this item uses a custom popup policy. If this flag is + * set, the default popup behaviour is disabled. This means you must call + * show/hide/toggle yourself if you want the popup to be shown. + */ + bool hasCustomPopup() const { return customPopup; } + + /** Enables or disables custom popup handling. */ + void setCustomPopup( bool enable = true ) { customPopup = enable; } + + // + // Drawing Methods + // + + /** Translates the QPainter then calls paintItem(). */ + void paint( QPainter *p, int x, int y ); + + /** + * Subclasses should reimplement this method to paint themselves. The painter is setup so + * that the item is always at 0, 0. + */ + virtual void paint( QPainter *p ); + + /** Draw a standard frame for the item. */ + void paintFrame( QPainter *p ); + + /** Paint the background. */ + void paintBackground( QPainter *p ); + + /** Draw the label for the item. */ + void paintLabel( QPainter *p ); + + void paintIcon( QPainter *p ); + + void paintModified( QPainter *p ); + +public slots: + void repaint(); + void repaint( bool erase ); + void update(); + + void setActive( bool yes ); + void setText( const QString &title ); + void setIcon( const QPixmap &icon ); + void setProgress( int percent ); + void setShowFrame( bool yes ); + void setModified( bool yes ); + void setAttention( bool yes ); + void setAnimation( const PixmapList &frames ); + void setShowAnimation( bool yes ); + + void advanceAnimation(); + + void setLockPopup( bool yes ) { lockPopup = yes; } + + /** Shows the items popup. */ + void showPopup(); + + /** Hides the items popup. */ + void hidePopup(); + + /** Check if the popup should be visible. */ + void checkPopup(); + + /** Hides or shows the popup. */ + void togglePopup(); + + /** + * Called when something being dragged is held over the item for a while. + */ + virtual void dragOverAction() {} + +signals: + void leftButtonClicked( QMouseEvent *ev ); + void middleButtonClicked( QMouseEvent *ev ); + void rightButtonClicked( QMouseEvent *ev ); + +protected: + KasResources *resources() { return kas->resources(); } + + /** Gets the font metrics from the parent. */ + QFontMetrics fontMetrics() const { return kas->fontMetrics(); } + + /** Gets the color group from the parent. */ + const QColorGroup &colorGroup() const { return kas->colorGroup(); } + + /** Factory method that creates a popup widget for the item. */ + virtual KasPopup *createPopup(); + + /** Draw a label with an arrow, the parameters specify the position and size of the arrow. */ + void paintArrowLabel( QPainter *p, int arrowSize, bool arrowOnLeft ); + + /** Paints a progress graph. */ + void paintProgress( QPainter *p, int percent ); + + void paintStateIcon( QPainter *p, uint state ); + + void paintAttention( QPainter *p ); + + void paintAnimation( QPainter *p ); + + // + // Event Handlers + // + + /** Called when the item receives a mouse event. */ + virtual void mousePressEvent( QMouseEvent * ) {} + + /** Called when the item receives a mouse event. */ + virtual void mouseReleaseEvent( QMouseEvent * ); + + /** Called when the mouse enters the item. */ + virtual void mouseEnter(); + + /** Called when the mouse leaves the item. */ + virtual void mouseLeave(); + + /** Called when a drag enters the item. */ + virtual void dragEnter(); + + /** Called when a drag leaves the item. */ + virtual void dragLeave(); + +private: + KasBar *kas; + QGuardedPtr<KasPopup> pop; + QTimer *popupTimer; + QTimer *dragTimer; + + QPoint pos_; + QString title; + QPixmap pix; + bool mouseOver; + bool activated; + bool customPopup; + bool lockPopup; + bool groupItem; + bool frame; + bool modified; + bool attention_; + int prog; + + PixmapList anim; + uint aniFrame; + bool drawAnim; +}; + +#endif // KASITEM_H + diff --git a/kicker/extensions/kasbar/kasloaditem.cpp b/kicker/extensions/kasbar/kasloaditem.cpp new file mode 100644 index 000000000..b0f9c23e3 --- /dev/null +++ b/kicker/extensions/kasbar/kasloaditem.cpp @@ -0,0 +1,130 @@ +#include <math.h> +#include <stdlib.h> + +#include <config.h> +#ifdef HAVE_SYS_LOADAVG_H +#include <sys/loadavg.h> // e.g. Solaris +#endif + +#include <qpainter.h> +#include <qbitmap.h> +#include <qdatetime.h> +#include <qdrawutil.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kwin.h> +#include <kiconloader.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kpopupmenu.h> + +#include <taskmanager.h> + +#include "kaspopup.h" +#include "kastasker.h" + +#include "kasloaditem.h" +#include "kasloaditem.moc" + +KasLoadItem::KasLoadItem( KasBar *parent ) + : KasItem( parent ) +{ + QTimer *t = new QTimer( this ); + connect( t, SIGNAL( timeout() ), SLOT( updateDisplay() ) ); + t->start( 1000 ); + updateDisplay(); + + connect( this, SIGNAL(rightButtonClicked(QMouseEvent *)), SLOT(showMenuAt(QMouseEvent *) ) ); +} + +KasLoadItem::~KasLoadItem() +{ +} + +void KasLoadItem::updateDisplay() +{ + double load[3]; + + int ret = getloadavg( load, 3 ); + if ( ret == -1 ) + return; + + valuesOne.append( load[0] ); + valuesFive.append( load[1] ); + valuesFifteen.append( load[2] ); + + if ( valuesOne.count() > 2/*(extent()-2)*/ ) { + valuesOne.pop_front(); + valuesFive.pop_front(); + valuesFifteen.pop_front(); + } + + setText( QString("%1").arg( valuesOne.last(), 3, 'f', 2 ) ); +} + +void KasLoadItem::paint( QPainter *p ) +{ + double val = valuesOne.last(); + double maxValue = 1.0; + double scaleVal = QMAX( val, valuesFive.last() ); + + if ( scaleVal >= maxValue ) + maxValue = 2.0; + if ( scaleVal >= maxValue ) + maxValue = 5.0; + if ( scaleVal >= maxValue ) + maxValue = 10.0; + if ( scaleVal >= maxValue ) + maxValue = 20.0; + if ( scaleVal >= maxValue ) + maxValue = 50.0; + if ( scaleVal >= maxValue ) + maxValue = 100.0; + + double dh = extent()-16; + dh = dh / maxValue; + + int h = (int) floor( dh * val ); + int w = extent()-4; + h = (h > 0) ? h : 1; + w = (w > 0) ? w : 1; + + KasItem::paint( p ); + + QColor light = kasbar()->colorGroup().highlight(); + QColor dark = light.dark(); + + KPixmap pix; + pix.resize( w, h ); + KPixmapEffect::gradient( pix, light, dark, KPixmapEffect::DiagonalGradient ); + p->drawPixmap( 2, extent()-2-h, pix ); + + p->setPen( kasbar()->colorGroup().mid() ); + for ( double pos = 0.2 ; pos < 1.0 ; pos += 0.2 ) { + int ypos = (int) floor((extent()-2) - (dh*maxValue*pos)); + p->drawLine( 2, ypos, extent()-3, ypos ); + } +} + +void KasLoadItem::showMenuAt( QMouseEvent *ev ) +{ + hidePopup(); + showMenuAt( ev->globalPos() ); +} + +void KasLoadItem::showMenuAt( QPoint p ) +{ + mouseLeave(); + kasbar()->updateMouseOver(); + + KasTasker *bar = dynamic_cast<KasTasker *> (KasItem::kasbar()); + if ( !bar ) + return; + + KPopupMenu *menu = bar->contextMenu(); + menu->exec( p ); +} diff --git a/kicker/extensions/kasbar/kasloaditem.h b/kicker/extensions/kasbar/kasloaditem.h new file mode 100644 index 000000000..527a85abc --- /dev/null +++ b/kicker/extensions/kasbar/kasloaditem.h @@ -0,0 +1,36 @@ +// -*- c++ -*- + + +#ifndef KASLOADITEM_H +#define KASLOADITEM_H + +#include "kasitem.h" + +#include <kdemacros.h> + +/** + * An item that displays the system load. + */ +class KDE_EXPORT KasLoadItem : public KasItem +{ + Q_OBJECT + +public: + KasLoadItem( KasBar *parent ); + virtual ~KasLoadItem(); + + void paint( QPainter *p ); + +public slots: + void updateDisplay(); + void showMenuAt( QMouseEvent *ev ); + void showMenuAt( QPoint p ); + +private: + QValueList<double> valuesOne; + QValueList<double> valuesFive; + QValueList<double> valuesFifteen; +}; + +#endif // KASLOADITEM_H + diff --git a/kicker/extensions/kasbar/kaspopup.cpp b/kicker/extensions/kasbar/kaspopup.cpp new file mode 100644 index 000000000..4407f2f48 --- /dev/null +++ b/kicker/extensions/kasbar/kaspopup.cpp @@ -0,0 +1,121 @@ +/* kaspopup.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qapplication.h> + +#include "kasitem.h" +#include "kasbar.h" + +#include "kaspopup.h" +#include "kaspopup.moc" + +KasPopup::KasPopup( KasItem *item, const char *name ) + : QHBox( 0, name, WStyle_Customize | WStyle_StaysOnTop | WStyle_Tool | WStyle_NoBorder | WX11BypassWM ), + item_( item ), + kasbar_( item->kasbar() ) +{ +} + +KasPopup::~KasPopup() +{ +} + +void KasPopup::positionSelf() +{ + move( calcPosition( item_, width(), height() ) ); +} + +void KasPopup::show() +{ + emit aboutToShow(); + positionSelf(); + QWidget::show(); + emit shown(); +} + +QPoint KasPopup::calcPosition( KasItem *item, int w, int h ) +{ + KasBar *kasbar = item->kasbar(); + QPoint pos = kasbar->itemPos( item ); + + if ( ( pos.x() < 0 ) && ( pos.y() < 0 ) ) + return QPoint(); + + pos = kasbar->mapToGlobal( pos ); + int x = pos.x(); + int y = pos.y(); + + if ( kasbar->orientation() == Horizontal ) { + if ( y < ( qApp->desktop()->height() / 2 ) ) + y = y + kasbar->itemExtent(); + else + y = y - h; + + if ( (x + w) > qApp->desktop()->width() ) + x = x - w + kasbar->itemExtent(); + } + else { + if ( x < ( qApp->desktop()->width() / 2 ) ) + x = x + kasbar->itemExtent(); + else + x = x - w; + + if ( (y + h) > qApp->desktop()->height() ) + y = y - h + kasbar->itemExtent(); + } + + return QPoint( x, y ); +} + + + diff --git a/kicker/extensions/kasbar/kaspopup.h b/kicker/extensions/kasbar/kaspopup.h new file mode 100644 index 000000000..11c024782 --- /dev/null +++ b/kicker/extensions/kasbar/kaspopup.h @@ -0,0 +1,107 @@ +/* kaspopup.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASPOPUP_H +#define KASPOPUP_H + +#include <qguardedptr.h> +#include <qhbox.h> +#include <kpixmap.h> + +#include "kasitem.h" + +class KasBar; + +/** + * Self positioning popup for KasItems. + * + * @author Richard Moore, rich@kde.org + */ +class KasPopup : public QHBox +{ + Q_OBJECT + +public: + KasPopup( KasItem *item, const char *name=0 ); + virtual ~KasPopup(); + + /** Returns the item that is the parent of this popup. */ + KasItem *item() const { return item_; } + KasBar *kasbar() const { return kasbar_; } + + static QPoint calcPosition( KasItem *item, int w, int h ); + +public slots: + /** + * Move the popup to the right position. You should not need + * to call this directly. + */ + void positionSelf(); + + /** Reimplemented for internal reasons. */ + void show(); + +signals: + void aboutToShow(); + void shown(); + +private: + QGuardedPtr<KasItem> item_; + KasBar *kasbar_; +}; + +#endif // KASPOPUP_H + + diff --git a/kicker/extensions/kasbar/kasprefsdlg.cpp b/kicker/extensions/kasbar/kasprefsdlg.cpp new file mode 100644 index 000000000..d6f0cf39f --- /dev/null +++ b/kicker/extensions/kasbar/kasprefsdlg.cpp @@ -0,0 +1,468 @@ +/* kasprefsdlg.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgrid.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qslider.h> +#include <qspinbox.h> +#include <qvbox.h> +#include <qwhatsthis.h> + +#include <kcolorbutton.h> +#include <kconfig.h> +#include <kdialogbase.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#include <knuminput.h> + +#include "kastasker.h" + +#include "kasprefsdlg.h" +#include "kasprefsdlg.moc" + +#define Icon(x) KGlobal::iconLoader()->loadIcon( x, KIcon::NoGroup, KIcon::SizeMedium ) +#define LargeIcon(x) KGlobal::iconLoader()->loadIcon( x, KIcon::NoGroup, KIcon::SizeLarge ) + + +KasPrefsDialog::KasPrefsDialog( KasTasker *kas, QWidget *parent ) + : KDialogBase( KDialogBase::IconList, i18n("Kasbar Preferences"), + KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok, + parent, "kasbarPrefsDialog", /*true*/false ), + kasbar( kas ), + res( kas->resources() ) +{ + addLookPage(); + addBackgroundPage(); + addThumbsPage(); + addBehavePage(); +// addIndicatorsPage(); + addColorsPage(); + addAdvancedPage(); + + resize( 470, 500 ); +} + +KasPrefsDialog::~KasPrefsDialog() +{ + +} + +void KasPrefsDialog::itemSizeChanged( int sz ) +{ + customSize->setEnabled( sz == KasBar::Custom ); +} + +void KasPrefsDialog::addLookPage() +{ + QVBox *lookPage = addVBoxPage( i18n("Appearance"), QString::null, Icon( "appearance" ) ); + + // + // Item size + // + + QGrid *itemSizeBox = new QGrid( 2, lookPage ); + itemSizeBox->setSpacing( spacingHint() ); + + QWhatsThis::add( itemSizeBox, + i18n( "Specifies the size of the task items." ) ); + + QLabel *itemSizeLabel = new QLabel( i18n("Si&ze:"), itemSizeBox ); + + itemSizeCombo = new QComboBox( itemSizeBox ); + itemSizeCombo->insertItem( i18n( "Enormous" ) ); + itemSizeCombo->insertItem( i18n( "Huge" ) ); + itemSizeCombo->insertItem( i18n( "Large" ) ); + itemSizeCombo->insertItem( i18n( "Medium" ) ); + itemSizeCombo->insertItem( i18n( "Small" ) ); + itemSizeCombo->insertItem( i18n( "Custom" ) ); + + itemSizeLabel->setBuddy( itemSizeCombo ); + + connect( itemSizeCombo, SIGNAL( activated( int ) ), + kasbar, SLOT( setItemSize( int ) ) ); + connect( itemSizeCombo, SIGNAL( activated( int ) ), SLOT( itemSizeChanged( int ) ) ); + + new QWidget( itemSizeBox ); + + customSize = new QSpinBox( 5, 1000, 1, itemSizeBox ); + + customSize->setValue( kasbar->itemExtent() ); + + connect( customSize, SIGNAL( valueChanged( int ) ), + kasbar, SLOT( setItemExtent( int ) ) ); + connect( customSize, SIGNAL( valueChanged( int ) ), + kasbar, SLOT( customSizeChanged( int ) ) ); + + int sz = kasbar->itemSize(); + itemSizeCombo->setCurrentItem( sz ); + customSize->setEnabled( sz == KasBar::Custom ); + + // + // Boxes per line + // + + QHBox *maxBoxesBox = new QHBox( lookPage ); + QWhatsThis::add( maxBoxesBox, + i18n( "Specifies the maximum number of items that should be placed in a line " + "before starting a new row or column. If the value is 0 then all the " + "available space will be used." ) ); + QLabel *maxBoxesLabel = new QLabel( i18n("Bo&xes per line: "), maxBoxesBox ); + + KConfig *conf = kasbar->config(); + if ( conf ) + conf->setGroup( "Layout" ); + maxBoxesSpin = new KIntSpinBox( 0, 50, 1, + conf ? conf->readNumEntry( "MaxBoxes", 0 ) : 11, + 10, + maxBoxesBox, "maxboxes" ); + connect( maxBoxesSpin, SIGNAL( valueChanged( int ) ), kasbar, SLOT( setMaxBoxes( int ) ) ); + maxBoxesLabel->setBuddy( maxBoxesSpin ); + + // + // Mode + // + + detachedCheck = new QCheckBox( i18n("&Detach from screen edge"), lookPage ); + QWhatsThis::add( detachedCheck, i18n( "Detaches the bar from the screen edge and makes it draggable." ) ); + + detachedCheck->setEnabled( !kasbar->isStandAlone() ); + detachedCheck->setChecked( kasbar->isDetached() ); + connect( detachedCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setDetached(bool) ) ); + + (void) new QWidget( lookPage, "spacer" ); + (void) new QWidget( lookPage, "spacer" ); + (void) new QWidget( lookPage, "spacer" ); +} + +void KasPrefsDialog::addBackgroundPage() +{ + QVBox *bgPage = addVBoxPage( i18n("Background"), QString::null, Icon( "background" ) ); + + transCheck = new QCheckBox( i18n("Trans&parent"), bgPage ); + QWhatsThis::add( transCheck, i18n( "Enables pseudo-transparent mode." ) ); + transCheck->setChecked( kasbar->isTransparent() ); + connect( transCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setTransparent(bool) ) ); + + tintCheck = new QCheckBox( i18n("Enable t&int"), bgPage ); + QWhatsThis::add( tintCheck, + i18n( "Enables tinting the background that shows through in transparent mode." ) ); + tintCheck->setChecked( kasbar->hasTint() ); + connect( tintCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setTint(bool) ) ); + + QHBox *tintColBox = new QHBox( bgPage ); + QWhatsThis::add( tintColBox, + i18n( "Specifies the color used for the background tint." ) ); + connect( tintCheck, SIGNAL( toggled(bool) ), tintColBox, SLOT( setEnabled(bool) ) ); + tintColBox->setEnabled( kasbar->hasTint() ); + + QLabel *tintLabel = new QLabel( i18n("Tint &color:"), tintColBox ); + + tintButton = new KColorButton( kasbar->tintColor(), tintColBox ); + connect( tintButton, SIGNAL( changed( const QColor & ) ), + kasbar, SLOT( setTintColor( const QColor & ) ) ); + tintLabel->setBuddy( tintButton ); + + QHBox *tintAmtBox = new QHBox( bgPage ); + QWhatsThis::add( tintAmtBox, + i18n( "Specifies the strength of the background tint." ) ); + connect( tintCheck, SIGNAL( toggled(bool) ), tintAmtBox, SLOT( setEnabled(bool) ) ); + tintAmtBox->setEnabled( kasbar->hasTint() ); + + QLabel *tintStrengthLabel = new QLabel( i18n("Tint &strength: "), tintAmtBox ); + + int percent = (int) (kasbar->tintAmount() * 100.0); + tintAmount = new QSlider( 0, 100, 1, percent, Horizontal, tintAmtBox ); + tintAmount->setTracking( true ); + connect( tintAmount, SIGNAL( valueChanged( int ) ), + kasbar, SLOT( setTintAmount( int ) ) ); + tintStrengthLabel->setBuddy( tintAmount ); + + (void) new QWidget( bgPage, "spacer" ); + (void) new QWidget( bgPage, "spacer" ); + (void) new QWidget( bgPage, "spacer" ); +} + +void KasPrefsDialog::addThumbsPage() +{ + QVBox *thumbsPage = addVBoxPage( i18n("Thumbnails"), QString::null, Icon( "icons" ) ); + + thumbsCheck = new QCheckBox( i18n("Enable thu&mbnails"), thumbsPage ); + QWhatsThis::add( thumbsCheck, + i18n( "Enables the display of a thumbnailed image of the window when " + "you move your mouse pointer over an item. The thumbnails are " + "approximate, and may not reflect the current window contents.\n\n" + "Using this option on a slow machine may cause performance problems." ) ); + thumbsCheck->setChecked( kasbar->thumbnailsEnabled() ); + connect( thumbsCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setThumbnailsEnabled(bool) ) ); + + embedThumbsCheck = new QCheckBox( i18n("&Embed thumbnails"), thumbsPage ); + embedThumbsCheck->setChecked( kasbar->embedThumbnails() ); + connect( embedThumbsCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setEmbedThumbnails(bool) ) ); + + QHBox *thumbSizeBox = new QHBox( thumbsPage ); + QWhatsThis::add( thumbSizeBox, + i18n( "Controls the size of the window thumbnails. Using large sizes may " + "cause performance problems." ) ); + QLabel *thumbSizeLabel = new QLabel( i18n("Thumbnail &size: "), thumbSizeBox ); + int percent = (int) (kasbar->thumbnailSize() * 100.0); + thumbSizeSlider = new QSlider( 0, 100, 1, percent, Horizontal, thumbSizeBox ); + connect( thumbSizeSlider, SIGNAL( valueChanged( int ) ), + kasbar, SLOT( setThumbnailSize( int ) ) ); + thumbSizeLabel->setBuddy( thumbSizeSlider ); + + QHBox *thumbUpdateBox = new QHBox( thumbsPage ); + thumbUpdateBox->setSpacing( spacingHint() ); + QWhatsThis::add( thumbUpdateBox, + i18n( "Controls the frequency with which the thumbnail of the active window " + "is updated. If the value is 0 then no updates will be performed.\n\n" + "Using small values may cause performance problems on slow machines." ) ); + QLabel *thumbUpdateLabel = new QLabel( i18n("&Update thumbnail every: "), thumbUpdateBox ); + thumbUpdateSpin = new QSpinBox( 0, 1000, 1, thumbUpdateBox ); + thumbUpdateSpin->setValue( kasbar->thumbnailUpdateDelay() ); + connect( thumbUpdateSpin, SIGNAL( valueChanged( int ) ), + kasbar, SLOT( setThumbnailUpdateDelay( int ) ) ); + (void) new QLabel( i18n("seconds"), thumbUpdateBox ); + thumbUpdateLabel->setBuddy( thumbUpdateSpin ); + + (void) new QWidget( thumbsPage, "spacer" ); + (void) new QWidget( thumbsPage, "spacer" ); + (void) new QWidget( thumbsPage, "spacer" ); +} + +void KasPrefsDialog::addBehavePage() +{ + QVBox *behavePage = addVBoxPage( i18n("Behavior"), QString::null, Icon( "window_list" ) ); + + groupWindowsCheck = new QCheckBox( i18n("&Group windows"), behavePage ); + QWhatsThis::add( groupWindowsCheck, + i18n( "Enables the grouping together of related windows." ) ); + groupWindowsCheck->setChecked( kasbar->groupWindows() ); + connect( groupWindowsCheck, SIGNAL( toggled(bool) ), + kasbar, SLOT( setGroupWindows(bool) ) ); + + showAllWindowsCheck = new QCheckBox( i18n("Show all &windows"), behavePage ); + QWhatsThis::add( showAllWindowsCheck, + i18n( "Enables the display of all windows, not just those on the current desktop." ) ); + showAllWindowsCheck->setChecked( kasbar->showAllWindows() ); + connect( showAllWindowsCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setShowAllWindows(bool) ) ); + + groupInactiveCheck = new QCheckBox( i18n("&Group windows on inactive desktops"), behavePage ); + QWhatsThis::add( groupInactiveCheck, + i18n( "Enables the grouping together of windows that are not on the current desktop." ) ); + groupInactiveCheck->setChecked( kasbar->groupInactiveDesktops() ); + connect( groupInactiveCheck, SIGNAL( toggled(bool) ), + kasbar, SLOT( setGroupInactiveDesktops(bool) ) ); + + onlyShowMinimizedCheck = new QCheckBox( i18n("Only show &minimized windows"), behavePage ); + QWhatsThis::add( onlyShowMinimizedCheck, + i18n( "When this option is checked only minimized windows are shown in the bar. " \ + "This gives Kasbar similar behavior to the icon handling in older environments " \ + "like CDE or OpenLook." ) ); + onlyShowMinimizedCheck->setChecked( kasbar->onlyShowMinimized() ); + connect( onlyShowMinimizedCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setOnlyShowMinimized(bool) ) ); + + (void) new QWidget( behavePage, "spacer" ); + (void) new QWidget( behavePage, "spacer" ); +} + +void KasPrefsDialog::addColorsPage() +{ + QVBox *colorsPage = addVBoxPage( i18n("Colors"), QString::null, Icon( "colors" ) ); + + // Item label colors + QGrid *group = new QGrid( 2, colorsPage ); + + QLabel *labelPenLabel = new QLabel( i18n("Label foreground:"), group ); + + labelPenButton = new KColorButton( res->labelPenColor(), group ); + connect( labelPenButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setLabelPenColor( const QColor & ) ) ); + labelPenLabel->setBuddy( labelPenButton ); + + QLabel *labelBackgroundLabel = new QLabel( i18n("Label background:"), group ); + labelBackgroundButton = new KColorButton( res->labelBgColor(), group ); + connect( labelBackgroundButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setLabelBgColor( const QColor & ) ) ); + labelBackgroundLabel->setBuddy( labelBackgroundButton ); + + // Inactive colors + group = new QGrid( 2, colorsPage ); + + QLabel *inactivePenLabel = new QLabel( i18n("Inactive foreground:"), group ); + inactivePenButton = new KColorButton( res->inactivePenColor(), group ); + connect( inactivePenButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setInactivePenColor( const QColor & ) ) ); + inactivePenLabel->setBuddy( inactivePenButton ); + + QLabel *inactiveBgLabel = new QLabel( i18n("Inactive background:"), group ); + inactiveBgButton = new KColorButton( res->inactiveBgColor(), group ); + connect( inactiveBgButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setInactiveBgColor( const QColor & ) ) ); + inactiveBgLabel->setBuddy( inactiveBgButton ); + + // Active colors + group = new QGrid( 2, colorsPage ); + + QLabel *activePenLabel = new QLabel( i18n("Active foreground:"), group ); + activePenButton = new KColorButton( res->activePenColor(), group ); + connect( activePenButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setActivePenColor( const QColor & ) ) ); + activePenLabel->setBuddy( activePenButton ); + + QLabel *activeBgLabel = new QLabel( i18n("Active background:"), group ); + activeBgButton = new KColorButton( res->activeBgColor(), group ); + connect( activeBgButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setActiveBgColor( const QColor & ) ) ); + activeBgLabel->setBuddy( activeBgButton ); + + group = new QGrid( 2, colorsPage ); + + QLabel *progressLabel = new QLabel( i18n("&Progress color:"), group ); + progressButton = new KColorButton( res->progressColor(), group ); + connect( progressButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setProgressColor( const QColor & ) ) ); + progressLabel->setBuddy( progressButton ); + + QLabel *attentionLabel = new QLabel( i18n("&Attention color:"), group ); + attentionButton = new KColorButton( res->attentionColor(), group ); + connect( attentionButton, SIGNAL( changed( const QColor & ) ), + res, SLOT( setAttentionColor( const QColor & ) ) ); + attentionLabel->setBuddy( attentionButton ); + + (void) new QWidget( colorsPage, "spacer" ); +} + +void KasPrefsDialog::addIndicatorsPage() +{ + QVBox *indicatorsPage = addVBoxPage( i18n("Indicators"), QString::null, Icon( "bell" ) ); + + (void) new QWidget( indicatorsPage, "spacer" ); + (void) new QWidget( indicatorsPage, "spacer" ); +} + +void KasPrefsDialog::addAdvancedPage() +{ + QVBox *advancedPage = addVBoxPage( i18n("Advanced"), QString::null, Icon( "misc" ) ); + + // Startup notifier + notifierCheck = new QCheckBox( i18n("Enable &startup notifier"), advancedPage ); + QWhatsThis::add( notifierCheck, + i18n( "Enables the display of tasks that are starting but have not yet " + "created a window." ) ); + notifierCheck->setChecked( kasbar->notifierEnabled() ); + connect( notifierCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setNotifierEnabled(bool) ) ); + + // Status advanced + modifiedCheck = new QCheckBox( i18n("Enable &modified indicator"), advancedPage ); + QWhatsThis::add( modifiedCheck, + i18n( "Enables the display of a floppy disk state icon for windows containing " + "a modified document." ) ); + modifiedCheck->setChecked( kasbar->showModified() ); + connect( modifiedCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setShowModified(bool) ) ); + + progressCheck = new QCheckBox( i18n("Enable &progress indicator"), advancedPage ); + QWhatsThis::add( progressCheck, + i18n( "Enables the display of a progress bar in the label of windows show " + "are progress indicators." ) ); + progressCheck->setChecked( kasbar->showProgress() ); + connect( progressCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setShowProgress(bool) ) ); + + attentionCheck = new QCheckBox( i18n("Enable &attention indicator"), advancedPage ); + QWhatsThis::add( attentionCheck, + i18n( "Enables the display of an icon that indicates a window that needs attention." ) ); + attentionCheck->setChecked( kasbar->showAttention() ); + connect( attentionCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setShowAttention(bool) ) ); + + inactiveFramesCheck = new QCheckBox( i18n("Enable frames for inactive items"), advancedPage ); + QWhatsThis::add( inactiveFramesCheck, + i18n( "Enables frames around inactive items, if you want the bar to disappear into " \ + "the background you should probably uncheck this option." ) ); + inactiveFramesCheck->setChecked( kasbar->paintInactiveFrames() ); + connect( inactiveFramesCheck, SIGNAL( toggled(bool) ), kasbar, SLOT( setPaintInactiveFrames(bool) ) ); + + (void) new QWidget( advancedPage, "spacer" ); + (void) new QWidget( advancedPage, "spacer" ); +} + +void KasPrefsDialog::customSizeChanged ( int value ) +{ + customSize->setSuffix( i18n(" pixel", " pixels", value) ); +} + +void KasPrefsDialog::accept() +{ + KConfig *conf = kasbar->config(); + if ( conf ) { + kasbar->writeConfig( conf ); + + conf->setGroup("Layout"); + // TODO: This needs to be made independent of the gui and moved to kastasker + conf->writeEntry( "MaxBoxes", maxBoxesSpin->value() ); + + conf->sync(); + } + + QDialog::accept(); +} + +void KasPrefsDialog::reject() +{ + kasbar->readConfig(); + QDialog::reject(); +} diff --git a/kicker/extensions/kasbar/kasprefsdlg.h b/kicker/extensions/kasbar/kasprefsdlg.h new file mode 100644 index 000000000..8c6bb3200 --- /dev/null +++ b/kicker/extensions/kasbar/kasprefsdlg.h @@ -0,0 +1,142 @@ +// -*- c++ -*- + +/* kasprefsdlg.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASPREFSDLG_H +#define KASPREFSDLG_H + +#include <kdialogbase.h> + +class QComboBox; +class QCheckBox; +class QSlider; +class QSpinBox; +class KColorButton; +class KConfig; +class KIntSpinBox; + +class KasTasker; +class KasResources; + +/** + * Prefs dialog for KasBar + */ +class KasPrefsDialog : public KDialogBase +{ + Q_OBJECT + +public: + KasPrefsDialog( KasTasker *kas, QWidget *parent=0 ); + ~KasPrefsDialog(); + + void addLookPage(); + void addBackgroundPage(); + void addThumbsPage(); + void addBehavePage(); + void addIndicatorsPage(); + void addColorsPage(); + void addAdvancedPage(); + +public slots: + void itemSizeChanged( int sz ); + +protected: + virtual void accept(); + virtual void reject(); + +private slots: + void customSizeChanged ( int value ); + +private: + + QComboBox *itemSizeCombo; + QSpinBox *customSize; + QCheckBox *transCheck; + QCheckBox *tintCheck; + KColorButton *tintButton; + QSlider *tintAmount; + QCheckBox *thumbsCheck; + QCheckBox *embedThumbsCheck; + QSlider *thumbSizeSlider; + QSpinBox *thumbUpdateSpin; + QCheckBox *notifierCheck; + QCheckBox *modifiedCheck; + QCheckBox *progressCheck; + QCheckBox *showAllWindowsCheck; + QCheckBox *onlyShowMinimizedCheck; + KIntSpinBox *maxBoxesSpin; + QCheckBox *detachedCheck; + QCheckBox *groupWindowsCheck; + QCheckBox *groupInactiveCheck; + QCheckBox *attentionCheck; + QCheckBox *inactiveFramesCheck; + + KColorButton *labelPenButton; + KColorButton *labelBackgroundButton; + KColorButton *inactivePenButton; + KColorButton *inactiveBgButton; + KColorButton *activePenButton; + KColorButton *activeBgButton; + + KColorButton *progressButton; + KColorButton *attentionButton; + + KasTasker *kasbar; + KasResources *res; +}; + +#endif // KASPREFSDLG_H + diff --git a/kicker/extensions/kasbar/kasresources.cpp b/kicker/extensions/kasbar/kasresources.cpp new file mode 100644 index 000000000..0248642f4 --- /dev/null +++ b/kicker/extensions/kasbar/kasresources.cpp @@ -0,0 +1,329 @@ +/* kasbar.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#include <kstandarddirs.h> +#include <kpixmapeffect.h> + +#include "kasbar.h" + +#include "kasresources.h" +#include "kasresources.moc" + +// +// Bitmap data used for the window state indicators +// +static unsigned char min_bits[] = { + 0x00, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00}; +static unsigned char max_bits[] = { + 0xff, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xff}; +static unsigned char shade_bits[] = { + 0x06, 0x1e, 0x7e, 0xfe, 0xfe, 0x7e, 0x1e, 0x06}; + +static unsigned char attention_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +/* XPM */ +static const char *tiny_floppy[]={ +"10 10 4 1", +". c None", +"# c #000000", +"b c #a0a0a0", +"a c #ffffff", +".########.", +".#aaaaaa#.", +".#aaaaaa#.", +".#aaaaaa#.", +".########.", +".########.", +".##bbbb##.", +".##bbbb##.", +".##bbbb##.", +".........."}; + +static const char *micro_max[]={ +"6 6 2 1", +". c None", +"# c #000000", +"######", +"######", +"##..##", +"##..##", +"######", +"######", +}; + +static const char *micro_min[]={ +"6 6 2 1", +". c None", +"# c #000000", +"......", +"######", +"######", +".####.", +"..##..", +"......" +}; + +static const char *micro_shade[]={ +"6 6 2 1", +". c None", +"# c #000000", +".##...", +".###..", +".####.", +".####.", +".###..", +".##..." +}; + +KasResources::KasResources( KasBar *parent, const char *name ) + : QObject( parent, name ? name : "kasbar_resources" ), + kasbar( parent ), + labelPenColor_( Qt::white ), labelBgColor_( Qt::black ), + activePenColor_( Qt::black ), activeBgColor_( Qt::white ), + inactivePenColor_( Qt::black ), inactiveBgColor_( Qt::white ), + progressColor_( Qt::green ), attentionColor_( Qt::red ), + startupFrames_() +{ +} + +KasResources::~KasResources() +{ +} + +QBitmap KasResources::minIcon() +{ + if ( minPix.isNull() ) { + minPix = QBitmap(8, 8, min_bits, true); + minPix.setMask(minPix); + } + + return minPix; +} + +QBitmap KasResources::maxIcon() +{ + if ( maxPix.isNull() ) { + maxPix = QBitmap(8, 8, max_bits, true); + maxPix.setMask(maxPix); + } + + return maxPix; +} + +QBitmap KasResources::shadeIcon() +{ + if ( shadePix.isNull() ) { + shadePix = QBitmap(8, 8, shade_bits, true); + shadePix.setMask(shadePix); + } + + return shadePix; +} + +QBitmap KasResources::attentionIcon() +{ + if ( attentionPix.isNull() ) { + attentionPix = QBitmap( 8, 8, attention_bits, true ); + attentionPix.setMask( attentionPix ); + } + + return attentionPix; +} + +QPixmap KasResources::modifiedIcon() +{ + if ( modifiedPix.isNull() ) + modifiedPix = QPixmap( tiny_floppy ); + + return modifiedPix; +} + +QPixmap KasResources::microShadeIcon() +{ + if ( microShadePix.isNull() ) + microShadePix = QPixmap( micro_shade ); + + return microShadePix; +} + +QPixmap KasResources::microMaxIcon() +{ + if ( microMaxPix.isNull() ) + microMaxPix = QPixmap( micro_max ); + + return microMaxPix; +} + +QPixmap KasResources::microMinIcon() +{ + if ( microMinPix.isNull() ) + microMinPix = QPixmap( micro_min ); + + return microMinPix; +} + +static const int MAX_ANIMATION_FRAME=10; + +QValueVector<QPixmap> KasResources::startupAnimation() +{ + if ( startupFrames_.isEmpty() ) { + for ( int i = 1; i <= MAX_ANIMATION_FRAME; i++ ) { + QPixmap p( locate("data", "kicker/pics/disk" + QString::number(i) + ".png") ); + if ( !p.isNull() ) + startupFrames_.append( p ); + } + } + + return startupFrames_; +} + +void KasResources::setLabelPenColor( const QColor &color ) +{ + if ( labelPenColor_ == color ) + return; + + labelPenColor_ = color; + emit changed(); +} + +void KasResources::setLabelBgColor( const QColor &color ) +{ + if ( labelBgColor_ == color ) + return; + + labelBgColor_ = color; + emit changed(); +} + +void KasResources::setInactivePenColor( const QColor &color ) +{ + if ( inactivePenColor_ == color ) + return; + + inactivePenColor_ = color; + emit changed(); +} + +void KasResources::setInactiveBgColor( const QColor &color ) +{ + if ( inactiveBgColor_ == color ) + return; + + inactiveBgColor_ = color; + emit changed(); +} + +void KasResources::setActivePenColor( const QColor &color ) +{ + if ( activePenColor_ == color ) + return; + + activePenColor_ = color; + emit changed(); +} + +void KasResources::setActiveBgColor( const QColor &color ) +{ + if ( activeBgColor_ == color ) + return; + + activeBgColor_ = color; + emit changed(); +} + +void KasResources::setProgressColor( const QColor &color ) +{ + if ( progressColor_ == color ) + return; + + progressColor_ = color; + emit changed(); +} + +void KasResources::setAttentionColor( const QColor &color ) +{ + if ( attentionColor_ == color ) + return; + + attentionColor_ = color; + emit changed(); +} + +void KasResources::itemSizeChanged() +{ + actBg = KPixmap(); + inactBg = KPixmap(); +} + +KPixmap KasResources::activeBg() +{ + if ( actBg.isNull() ) { + actBg.resize( kasbar->itemExtent(), kasbar->itemExtent() ); + KPixmapEffect::gradient( actBg, + kasbar->colorGroup().light(), kasbar->colorGroup().mid(), + KPixmapEffect::DiagonalGradient ); + } + + return actBg; +} + +KPixmap KasResources::inactiveBg() +{ + if ( inactBg.isNull() ) { + inactBg.resize( kasbar->itemExtent(), kasbar->itemExtent() ); + KPixmapEffect::gradient( inactBg, + kasbar->colorGroup().mid(), kasbar->colorGroup().dark(), + KPixmapEffect::DiagonalGradient ); + } + + return inactBg; +} + diff --git a/kicker/extensions/kasbar/kasresources.h b/kicker/extensions/kasbar/kasresources.h new file mode 100644 index 000000000..44048bcc3 --- /dev/null +++ b/kicker/extensions/kasbar/kasresources.h @@ -0,0 +1,171 @@ +// -*- c++ -*- + +/* kasbar.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + +#ifndef KASRESOURCES_H +#define KASRESOURCES_H + +#include <qbitmap.h> +#include <qcolor.h> +#include <qbrush.h> +#include <qpen.h> +#include <kpixmap.h> + +#include <qobject.h> +#include <qvaluevector.h> + +class KasBar; + +/** + * Central class that holds the graphical resources for the bar. + * + * @author Richard Moore, rich@kde.org + */ +class KasResources : public QObject +{ + Q_OBJECT + +public: + KasResources( KasBar *parent, const char *name=0 ); + virtual ~KasResources(); + + QColor labelPenColor() const { return labelPenColor_; } + QColor labelBgColor() const { return labelBgColor_; } + QColor inactivePenColor() const { return inactivePenColor_; } + QColor inactiveBgColor() const { return inactiveBgColor_; } + QColor activePenColor() const { return activePenColor_; } + QColor activeBgColor() const { return activeBgColor_; } + + QColor progressColor() const { return progressColor_; } + QColor attentionColor() const { return attentionColor_; } + + /** Accessor for the min icon (singleton). */ + QBitmap minIcon(); + + /** Accessor for the max icon (singleton). */ + QBitmap maxIcon(); + + /** Accessor for the shade icon (singleton). */ + QBitmap shadeIcon(); + + /** Accessor for the attention icon (singleton). */ + QBitmap attentionIcon(); + + /** Accessor for the modified icon (singleton). */ + QPixmap modifiedIcon(); + + /** Accessor for the micro min icon (singleton). */ + QPixmap microMinIcon(); + + /** Accessor for the micro max icon (singleton). */ + QPixmap microMaxIcon(); + + /** Accessor for the micro shade icon (singleton). */ + QPixmap microShadeIcon(); + + /** Accessor used by items to get the active bg fill. */ + KPixmap activeBg(); + + /** Accessor used by items to get the inactive bg fill. */ + KPixmap inactiveBg(); + + QValueVector<QPixmap> startupAnimation(); + +public slots: + void setLabelPenColor( const QColor &color ); + void setLabelBgColor( const QColor &color ); + void setInactivePenColor( const QColor &color ); + void setInactiveBgColor( const QColor &color ); + void setActivePenColor( const QColor &color ); + void setActiveBgColor( const QColor &color ); + + void setProgressColor( const QColor &color ); + void setAttentionColor( const QColor &color ); + + void itemSizeChanged(); + +signals: + void changed(); + +private: + KasBar *kasbar; + + QBitmap minPix; + QBitmap maxPix; + QBitmap shadePix; + QBitmap attentionPix; + QPixmap modifiedPix; + QPixmap microShadePix; + QPixmap microMaxPix; + QPixmap microMinPix; + + QColor labelPenColor_; + QColor labelBgColor_; + QColor activePenColor_; + QColor activeBgColor_; + QColor inactivePenColor_; + QColor inactiveBgColor_; + + QColor progressColor_; + QColor attentionColor_; + + KPixmap actBg; + KPixmap inactBg; + + QValueVector<QPixmap> startupFrames_; +}; + +#endif // KASRESOURCES_H + diff --git a/kicker/extensions/kasbar/kasstartupitem.cpp b/kicker/extensions/kasbar/kasstartupitem.cpp new file mode 100644 index 000000000..334edc836 --- /dev/null +++ b/kicker/extensions/kasbar/kasstartupitem.cpp @@ -0,0 +1,161 @@ +/* kasstartupitem.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qpainter.h> +#include <qbitmap.h> +#include <qdrawutil.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kwin.h> +#include <kiconloader.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> +#include <klocale.h> +#include <taskmanager.h> + +#include "kaspopup.h" + +#include "kasstartupitem.h" +#include "kasstartupitem.moc" + +KasStartupItem::KasStartupItem( KasBar *parent, Startup::Ptr startup ) + : KasItem( parent ), + startup_(startup), frame(0) +{ + setText( startup_->text() ); + setIcon( icon() ); + setShowFrame( false ); + setAnimation( resources()->startupAnimation() ); + + aniTimer = new QTimer( this ); + connect( aniTimer, SIGNAL( timeout() ), SLOT( aniTimerFired() ) ); + aniTimer->start( 100 ); +} + +KasStartupItem::~KasStartupItem() +{ +} + +QPixmap KasStartupItem::icon() const +{ + /** + * This icon stuff should all be handled by the task manager api, but isn't yet. + */ + QPixmap pixmap; + + switch( kasbar()->itemSize() ) { + case KasBar::Small: + /* ***** NOP ****** + pixmap = KGlobal::iconLoader()->loadIcon( startup_->icon(), + KIcon::NoGroup, + KIcon::SizeSmall ); + */ + break; + case KasBar::Medium: + pixmap = KGlobal::iconLoader()->loadIcon( startup_->icon(), + KIcon::NoGroup, + KIcon::SizeMedium ); + break; + case KasBar::Large: + pixmap = KGlobal::iconLoader()->loadIcon( startup_->icon(), + KIcon::NoGroup, + KIcon::SizeLarge ); + break; + case KasBar::Huge: + pixmap = KGlobal::iconLoader()->loadIcon( startup_->icon(), + KIcon::NoGroup, + KIcon::SizeHuge ); + break; + case KasBar::Enormous: + pixmap = KGlobal::iconLoader()->loadIcon( startup_->icon(), + KIcon::NoGroup, + KIcon::SizeEnormous ); + break; + default: + pixmap = KGlobal::iconLoader()->loadIcon( "error", + KIcon::NoGroup, + KIcon::SizeSmall ); + } + + return pixmap; +} + +void KasStartupItem::aniTimerFired() +{ + + if ( frame == 40 ) + frame = 0; + else + frame++; + + advanceAnimation(); +} + +void KasStartupItem::paint( QPainter *p ) +{ + p->save(); + + p->setClipRect( 0, 0, extent(), extent(), QPainter::CoordPainter ); + p->translate( extent()/2, extent()/2 ); + p->rotate( 9.0L * frame ); + p->scale( 0.7L, 0.7L ); + p->translate( -extent()/2, -extent()/2 ); + + KasItem::paint( p ); + + p->restore(); + paintAnimation( p ); +} + diff --git a/kicker/extensions/kasbar/kasstartupitem.h b/kicker/extensions/kasbar/kasstartupitem.h new file mode 100644 index 000000000..b8019f337 --- /dev/null +++ b/kicker/extensions/kasbar/kasstartupitem.h @@ -0,0 +1,97 @@ +/* kasstartupitem.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + + +#ifndef KASSTARTUPITEM_H +#define KASSTARTUPITEM_H + +#include <qpixmap.h> +#include <qstring.h> +#include "kasitem.h" + +class Startup; +class KasPopup; +class QTimer; + +/** + * A KasItem that represents a single Startup. + */ +class KasStartupItem : public KasItem +{ + Q_OBJECT + +public: + KasStartupItem( KasBar *parent, Startup::Ptr startup ); + virtual ~KasStartupItem(); + + QPixmap icon() const; + Startup::Ptr startup() const { return startup_; } + + /** + * Reimplemented to paint the item. + */ + virtual void paint( QPainter *p ); + +protected slots: + void aniTimerFired(); + +private: + Startup::Ptr startup_; + QTimer *aniTimer; + int frame; +}; + +#endif // KASSTARTUPITEM_H + diff --git a/kicker/extensions/kasbar/kastasker.cpp b/kicker/extensions/kasbar/kastasker.cpp new file mode 100644 index 000000000..9c93db56c --- /dev/null +++ b/kicker/extensions/kasbar/kastasker.cpp @@ -0,0 +1,745 @@ +/* kastasker.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qapplication.h> +#include <qtimer.h> + +#include <kactionclasses.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kiconloader.h> + +//#include <kconfiggroupsaver.h> + +#include <taskmanager.h> + +#include "kasaboutdlg.h" +#include "kastaskitem.h" +#include "kasprefsdlg.h" +#include "kasstartupitem.h" +#include "kasgroupitem.h" +#include "kasgrouper.h" +#include "kasclockitem.h" +#include "kasloaditem.h" + +#include "kastasker.h" +#include "kastasker.moc" + +static const int SWITCH_DESKTOPS_REGROUP_DELAY = 50; + +KasTasker::KasTasker( Orientation o, QWidget* parent, const char* name, WFlags f ) + : KasBar( o, parent, name, f ), + menu( 0 ), + conf( 0 ), + grouper( 0 ), + standalone_( false ), + enableThumbs_( true ), + embedThumbs_( false ), + thumbnailSize_( 0.2 ), + enableNotifier_( true ), + showModified_( true ), + showProgress_( false ), + showAllWindows_( true ), + thumbUpdateDelay_( 10 ), + groupWindows_( false ), + groupInactiveDesktops_( false ), + showAttention_( true ), + showClock_( false ), + clockItem(0), + showLoad_( false ), + loadItem(0) +{ + setAcceptDrops( true ); + connect(TaskManager::the(), SIGNAL(taskAdded(Task::Ptr)), SLOT(addTask(Task::Ptr))); + connect(TaskManager::the(), SIGNAL(taskRemoved(Task::Ptr)), SLOT(removeTask(Task::Ptr))); + connect(TaskManager::the(), SIGNAL(startupAdded(Startup::Ptr)), SLOT(addStartup(Startup::Ptr))); + connect(TaskManager::the(), SIGNAL(startupRemoved(Startup::Ptr)), SLOT(removeStartup(Startup::Ptr))); + connect(TaskManager::the(), SIGNAL(desktopChanged(int)), SLOT(refreshAllLater())); +// connect( manager, SIGNAL( windowChanged( Task::Ptr ) ), SLOT( refreshAllLater() ) ); + + connect( this, SIGNAL( itemSizeChanged( int ) ), SLOT( refreshAll() ) ); + + connect( this, SIGNAL( detachedPositionChanged(const QPoint &) ), SLOT( writeLayout() ) ); + connect( this, SIGNAL( directionChanged() ), SLOT( writeLayout() ) ); +} + +KasTasker::KasTasker( Orientation o, KasTasker *master, QWidget* parent, const char* name, WFlags f ) + : KasBar( o, master, parent, name, f ), + menu( 0 ), + conf( 0 ), + grouper( 0 ), + standalone_( master->standalone_ ), + enableThumbs_( master->enableThumbs_ ), + embedThumbs_( master->embedThumbs_ ), + thumbnailSize_( master->thumbnailSize_ ), + enableNotifier_( master->enableNotifier_ ), + showModified_( master->showModified_ ), + showProgress_( master->showProgress_ ), + showAllWindows_( master->showAllWindows_ ), + thumbUpdateDelay_( master->thumbUpdateDelay_ ), + groupWindows_( false ), + groupInactiveDesktops_( false ), + showAttention_( master->showAttention_ ), + showClock_( false ), + clockItem(0), + showLoad_( false ), + loadItem(0) +{ + setAcceptDrops( true ); +} + +KasTasker::~KasTasker() +{ + delete menu; + delete grouper; +} + +KPopupMenu *KasTasker::contextMenu() +{ + if ( !menu ) { + menu = new KPopupMenu; + + showAllWindowsAction = new KToggleAction( i18n("Show &All Windows"), KShortcut(), + this, "toggle_show_all_windows" ); + showAllWindowsAction->setChecked( showAllWindows() ); + showAllWindowsAction->plug( menu ); + connect( showAllWindowsAction, SIGNAL(toggled(bool)), SLOT(setShowAllWindows(bool)) ); + connect( this, SIGNAL(showAllWindowsChanged(bool)), showAllWindowsAction, SLOT(setChecked(bool)) ); + + groupWindowsAction = new KToggleAction( i18n("&Group Windows"), KShortcut(), + this, "toggle_group_windows" ); + groupWindowsAction->setChecked( groupWindows() ); + groupWindowsAction->plug( menu ); + connect( groupWindowsAction, SIGNAL(toggled(bool)), SLOT(setGroupWindows(bool)) ); + connect( this, SIGNAL(groupWindowsChanged(bool)), groupWindowsAction, SLOT(setChecked(bool)) ); + + showClockAction = new KToggleAction( i18n("Show &Clock"), KShortcut(), this, "toggle_show_clock" ); + showClockAction->setChecked( showClock() ); + showClockAction->plug( menu ); + connect( showClockAction, SIGNAL(toggled(bool)), SLOT(setShowClock(bool)) ); + connect( this, SIGNAL(showClockChanged(bool)), showClockAction, SLOT(setChecked(bool)) ); + + showLoadAction = new KToggleAction( i18n("Show &Load Meter"), KShortcut(), this, "toggle_show_load" ); + showLoadAction->setChecked( showLoad() ); + showLoadAction->plug( menu ); + connect( showLoadAction, SIGNAL(toggled(bool)), SLOT(setShowLoad(bool)) ); + connect( this, SIGNAL(showLoadChanged(bool)), showLoadAction, SLOT(setChecked(bool)) ); + + menu->insertSeparator(); + + if ( !standalone_ ) { + toggleDetachedAction = new KToggleAction( i18n("&Floating"), KShortcut(), this, "toggle_detached" ); + toggleDetachedAction->setChecked( isDetached() ); + toggleDetachedAction->plug( menu ); + connect( toggleDetachedAction, SIGNAL(toggled(bool)), SLOT(setDetached(bool)) ); + connect( this, SIGNAL(detachedChanged(bool)), toggleDetachedAction, SLOT(setChecked(bool)) ); + } + + rotateBarAction = new KAction( i18n("R&otate Bar"), QString("rotate"), KShortcut(), + this, SLOT( toggleOrientation() ), + this, "rotate_bar" ); + rotateBarAction->plug( menu ); + connect( this, SIGNAL(detachedChanged(bool)), rotateBarAction, SLOT(setEnabled(bool)) ); + connect( rotateBarAction, SIGNAL(activated()), SLOT(writeConfigLater()) ); + + menu->insertItem( SmallIcon("reload"), i18n("&Refresh"), this, SLOT( refreshAll() ) ); + + menu->insertSeparator(); + + menu->insertItem( SmallIcon("configure"), i18n("&Configure Kasbar..."), this, SLOT( showPreferences() ) ); + + // Help menu + KPopupMenu *help = new KPopupMenu; + help->insertItem( SmallIcon("about"), i18n("&About Kasbar"), this, SLOT( showAbout() ) ); + menu->insertItem( SmallIcon("help"), i18n("&Help"), help ); + + if ( standalone_ ) { + menu->insertSeparator(); + menu->insertItem( SmallIcon("exit"), i18n("&Quit"), qApp, SLOT( quit() ) ); + } + } + + return menu; +} + +KasTasker *KasTasker::createChildBar( Orientation o, QWidget *parent, const char *name ) +{ + KasTasker *child = new KasTasker( o, this, parent, name ); + child->conf = this->conf; + return child; +} + +KasTaskItem *KasTasker::findItem( Task::Ptr t ) +{ + KasTaskItem *result = 0; + for ( uint i = 0; i < itemCount(); i++ ) { + if ( itemAt(i)->inherits( "KasTaskItem" ) ) { + KasTaskItem *curr = static_cast<KasTaskItem *> (itemAt( i )); + if ( curr->task() == t ) { + result = curr; + break; + } + } + } + return result; +} + +KasStartupItem *KasTasker::findItem( Startup::Ptr s ) +{ + KasStartupItem *result = 0; + for ( uint i = 0; i < itemCount(); i++ ) { + if ( itemAt(i)->inherits( "KasStartupItem" ) ) { + KasStartupItem *curr = static_cast<KasStartupItem *> (itemAt( i )); + if ( curr->startup() == s ) { + result = curr; + break; + } + } + } + return result; +} + +void KasTasker::addTask( Task::Ptr t ) +{ + KasItem *item = 0; + + if ( onlyShowMinimized_ && !t->isMinimized() ) + return; + + if ( showAllWindows_ || t->isOnCurrentDesktop() ) { + if ( grouper ) + item = grouper->maybeGroup( t ); + if ( !item ) { + item = new KasTaskItem( this, t ); + append( item ); + } + + // + // Ensure the window manager knows where we put the icon. + // + QPoint p = mapToGlobal( itemPos( item ) ); + QSize s( itemExtent(), itemExtent() ); + t->publishIconGeometry( QRect( p, s ) ); + } +} + +void KasTasker::removeTask( Task::Ptr t ) +{ + KasTaskItem *i = findItem( t ); + if ( !i ) + return; + + remove( i ); + refreshIconGeometry(); +} + +KasGroupItem *KasTasker::convertToGroup( Task::Ptr t ) +{ + KasTaskItem *ti = findItem( t ); + int i = indexOf( ti ); + KasGroupItem *gi = new KasGroupItem( this ); + gi->addTask( t ); + removeTask( t ); + insert( i, gi ); + + connect(TaskManager::the(), SIGNAL(taskRemoved(Task::Ptr)), gi, SLOT(removeTask(Task::Ptr))); + + return gi; +} + +void KasTasker::moveToMain( KasGroupItem *gi, Task::Ptr t ) +{ + int i = indexOf( gi ); + if ( i != -1 ) { + remove( gi ); + insert( i, new KasTaskItem( this, t ) ); + } + else + append( new KasTaskItem( this, t ) ); + + refreshIconGeometry(); +} + +void KasTasker::moveToMain( KasGroupItem *gi ) +{ + bool updates = isUpdatesEnabled(); + setUpdatesEnabled( false ); + + int i = indexOf( gi ); + + for ( int ti = 0 ; ti < gi->taskCount() ; ti++ ) { + Task::Ptr t = gi->task( ti ); + insert( i, new KasTaskItem( this, t ) ); + } + + gi->hidePopup(); + remove( gi ); + + setUpdatesEnabled( updates ); + updateLayout(); +} + +void KasTasker::addStartup( Startup::Ptr s ) +{ + if ( enableNotifier_ ) + append( new KasStartupItem( this, s ) ); +} + +void KasTasker::removeStartup( Startup::Ptr s ) +{ + KasStartupItem *i = findItem( s ); + remove( i ); +} + +void KasTasker::refreshAll() +{ + bool updates = isUpdatesEnabled(); + setUpdatesEnabled( false ); + + clear(); + + if ( showClock_ ) { + showClock_ = false; + setShowClock( true ); + } + + if ( showLoad_ ) { + showLoad_ = false; + setShowLoad( true ); + } + + Task::Dict l = TaskManager::the()->tasks(); + for ( Task::Dict::iterator t = l.begin(); t != l.end(); ++t ) { + addTask( t.data() ); + } + + setUpdatesEnabled( updates ); + updateLayout(); +} + +void KasTasker::refreshAllLater() +{ + QTimer::singleShot( SWITCH_DESKTOPS_REGROUP_DELAY, this, SLOT( refreshAll() ) ); +} + +void KasTasker::refreshIconGeometry() +{ + for ( uint i = 0; i < itemCount(); i++ ) { + if ( itemAt(i)->inherits( "KasTaskItem" ) ) { + KasTaskItem *curr = static_cast<KasTaskItem *> (itemAt( i )); + + QPoint p = mapToGlobal( itemPos( curr ) ); + QSize s( itemExtent(), itemExtent() ); + curr->task()->publishIconGeometry( QRect( p, s ) ); + } + } +} + +void KasTasker::setNotifierEnabled( bool enable ) +{ + enableNotifier_ = enable; +} + +void KasTasker::setThumbnailSize( double size ) +{ + thumbnailSize_ = size; +} + +void KasTasker::setThumbnailSize( int percent ) +{ + double amt = (double) percent / 100.0; + setThumbnailSize( amt ); +} + +void KasTasker::setThumbnailsEnabled( bool enable ) +{ + enableThumbs_ = enable; +} + +void KasTasker::setShowModified( bool enable ) +{ + showModified_ = enable; + update(); +} + +void KasTasker::setShowProgress( bool enable ) +{ + showProgress_ = enable; + update(); +} + +void KasTasker::setShowAttention( bool enable ) +{ + showAttention_ = enable; + update(); +} + +void KasTasker::setShowAllWindows( bool enable ) +{ + if ( showAllWindows_ != enable ) { + showAllWindows_ = enable; + refreshAll(); + if ( !showAllWindows_ ) { + connect(TaskManager::the(), SIGNAL(desktopChanged(int)), SLOT(refreshAll())); +// connect( manager, SIGNAL( windowChanged( Task::Ptr ) ), SLOT( refreshAll() ) ); + } + else { + disconnect(TaskManager::the(), SIGNAL(desktopChanged(int)), this, SLOT(refreshAll())); +// disconnect( manager, SIGNAL( windowChanged( Task::Ptr ) ), this, SLOT( refreshAll() ) ); + } + + emit showAllWindowsChanged( enable ); + } +} + +void KasTasker::setThumbnailUpdateDelay( int secs ) +{ + thumbUpdateDelay_ = secs; +} + +void KasTasker::setEmbedThumbnails( bool enable ) +{ + if ( embedThumbs_ == enable ) + return; + + embedThumbs_ = enable; + update(); +} + +void KasTasker::setShowClock( bool enable ) +{ + if ( showClock_ == enable ) + return; + + showClock_ = enable; + + if ( enable ) { + clockItem = new KasClockItem( this ); + insert( 0, clockItem ); + } + else if ( clockItem ) { + remove( clockItem ); + clockItem = 0; + } + + + emit showClockChanged( showClock_ ); + writeConfigLater(); +} + +void KasTasker::setShowLoad( bool enable ) +{ + if ( showLoad_ == enable ) + return; + + showLoad_ = enable; + + if ( enable ) { + loadItem = new KasLoadItem( this ); + insert( showClock_ ? 1 : 0, loadItem ); + } + else if ( loadItem ) { + remove( loadItem ); + loadItem = 0; + } + + emit showLoadChanged( showLoad_ ); + writeConfigLater(); +} + +void KasTasker::setGroupWindows( bool enable ) +{ + if ( groupWindows_ != enable ) { + groupWindows_ = enable; + if ( enable && (!grouper) ) + grouper = new KasGrouper( this ); + refreshAll(); + + emit groupWindowsChanged( enable ); + } +} + +void KasTasker::setGroupInactiveDesktops( bool enable ) +{ + if ( groupInactiveDesktops_ != enable ) { + groupInactiveDesktops_ = enable; + if ( enable && (!grouper) ) + grouper = new KasGrouper( this ); + + refreshAll(); + } +} + +void KasTasker::setOnlyShowMinimized( bool enable ) +{ + if ( onlyShowMinimized_ != enable ) { + onlyShowMinimized_ = enable; + refreshAll(); + } +} + +void KasTasker::setStandAlone( bool enable ) +{ + standalone_ = enable; +} + +// +// Configuration Loader +// + +void KasTasker::setConfig( KConfig *conf ) +{ + this->conf = conf; +} + +void KasTasker::readConfig() +{ + readConfig(conf); +} + +void KasTasker::writeConfigLater() +{ + QTimer::singleShot( 10, this, SLOT( writeConfig() ) ); +} + +void KasTasker::writeConfig() +{ + writeConfig(conf); +} + +void KasTasker::readConfig( KConfig *conf ) +{ + if ( !conf ) { + kdWarning() << "KasTasker::readConfig() got a null KConfig" << endl; + return; + } + + if ( master() ) { + kdWarning() << "KasTasker::readConfig() for child bar" << endl; + return; + } + + bool updates = isUpdatesEnabled(); + setUpdatesEnabled( false ); + + + // + // Appearance Settings. + // + KConfigGroupSaver saver( conf, "Appearance" ); + + int ext = conf->readNumEntry( "ItemExtent", -1 ); + if ( ext > 0 ) + setItemExtent( ext ); + else + setItemSize( conf->readNumEntry( "ItemSize", KasBar::Medium ) ); + + setTint( conf->readBoolEntry( "EnableTint", false ) ); + setTintColor( conf->readColorEntry( "TintColor", &Qt::black ) ); + setTintAmount( conf->readDoubleNumEntry( "TintAmount", 0.1 ) ); + setTransparent( conf->readBoolEntry( "Transparent", true ) ); + setPaintInactiveFrames( conf->readBoolEntry( "PaintInactiveFrames", true ) ); + + // + // Painting colors + // + conf->setGroup("Colors"); + + KasResources *res = resources(); + res->setLabelPenColor( conf->readColorEntry( "LabelPenColor", &Qt::white ) ); + res->setLabelBgColor( conf->readColorEntry( "LabelBgColor", &Qt::black ) ); + res->setInactivePenColor( conf->readColorEntry( "InactivePenColor", &Qt::black ) ); + res->setInactiveBgColor( conf->readColorEntry( "InactiveBgColor", &Qt::white ) ); + res->setActivePenColor( conf->readColorEntry( "ActivePenColor", &Qt::black ) ); + res->setActiveBgColor( conf->readColorEntry( "ActiveBgColor", &Qt::white ) ); + res->setProgressColor( conf->readColorEntry( "ProgressColor", &Qt::green ) ); + res->setAttentionColor( conf->readColorEntry( "AttentionColor", &Qt::red ) ); + + // + // Thumbnail Settings + // + conf->setGroup("Thumbnails"); + setThumbnailsEnabled( conf->readBoolEntry( "Thumbnails", true ) ); + setThumbnailSize( conf->readDoubleNumEntry( "ThumbnailSize", 0.2 ) ); + setThumbnailUpdateDelay( conf->readNumEntry( "ThumbnailUpdateDelay", 10 ) ); + setEmbedThumbnails( conf->readBoolEntry( "EmbedThumbnails", false ) ); + + // + // Behaviour Settings + // + conf->setGroup("Behaviour"); + setNotifierEnabled( conf->readBoolEntry( "StartupNotifier", true ) ); + setShowModified( conf->readBoolEntry( "ModifiedIndicator", true ) ); + setShowProgress( conf->readBoolEntry( "ProgressIndicator", false ) ); + setShowAttention( conf->readBoolEntry( "AttentionIndicator", true ) ); + setShowAllWindows( conf->readBoolEntry( "ShowAllWindows", true ) ); + setGroupWindows( conf->readBoolEntry( "GroupWindows", true ) ); + setGroupInactiveDesktops( conf->readBoolEntry( "GroupInactiveDesktops", false ) ); + setOnlyShowMinimized( conf->readBoolEntry( "OnlyShowMinimized", false ) ); + + // + // Layout Settings + // + conf->setGroup("Layout"); + + setDirection( (Direction) conf->readNumEntry( "Direction", QBoxLayout::LeftToRight ) ); + setOrientation( (Qt::Orientation) conf->readNumEntry( "Orientation", Horizontal ) ); + setMaxBoxes( conf->readUnsignedNumEntry( "MaxBoxes", 0 ) ); + + QPoint pos(100, 100); + setDetachedPosition( conf->readPointEntry( "DetachedPosition", &pos ) ); + setDetached( conf->readBoolEntry( "Detached", false ) ); + + // + // Custom Items + // + conf->setGroup("Custom Items"); + setShowClock( conf->readBoolEntry( "ShowClock", true ) ); + setShowLoad( conf->readBoolEntry( "ShowLoad", true ) ); + + // fillBg = conf->readBoolEntry( "FillIconBackgrounds", /*true*/ false ); + // fillActiveBg = conf->readBoolEntry( "FillActiveIconBackground", true ); + // enablePopup = conf->readBoolEntry( "EnablePopup", true ); + + setUpdatesEnabled( updates ); + emit configChanged(); +} + +void KasTasker::writeConfig( KConfig *conf ) +{ + if ( !conf ) { + kdWarning() << "KasTasker::writeConfig() got a null KConfig" << endl; + return; + } + + if ( master() ) { + kdWarning() << "KasTasker::writeConfig() for child bar" << endl; + return; + } + + conf->setGroup("Appearance"); + conf->writeEntry( "ItemSize", itemSize() ); + conf->writeEntry( "ItemExtent", itemExtent() ); + conf->writeEntry( "Transparent", isTransparent() ); + conf->writeEntry( "EnableTint", hasTint() ); + conf->writeEntry( "TintColor", tintColor() ); + conf->writeEntry( "TintAmount", tintAmount() ); + conf->writeEntry( "PaintInactiveFrames", paintInactiveFrames() ); + + conf->setGroup("Colors"); + conf->writeEntry( "LabelPenColor", resources()->labelPenColor() ); + conf->writeEntry( "LabelBgColor", resources()->labelBgColor() ); + conf->writeEntry( "InactivePenColor", resources()->inactivePenColor() ); + conf->writeEntry( "InactiveBgColor", resources()->inactiveBgColor() ); + conf->writeEntry( "ActivePenColor", resources()->activePenColor() ); + conf->writeEntry( "ActiveBgColor", resources()->activeBgColor() ); + conf->writeEntry( "ProgressColor", resources()->progressColor() ); + conf->writeEntry( "AttentionColor", resources()->attentionColor() ); + + conf->setGroup("Thumbnails"); + conf->writeEntry( "Thumbnails", thumbnailsEnabled() ); + conf->writeEntry( "ThumbnailSize", thumbnailSize() ); + conf->writeEntry( "ThumbnailUpdateDelay", thumbnailUpdateDelay() ); + conf->writeEntry( "EmbedThumbnails", embedThumbnails() ); + + conf->setGroup("Behaviour"); + conf->writeEntry( "StartupNotifier", notifierEnabled() ); + conf->writeEntry( "ModifiedIndicator", showModified() ); + conf->writeEntry( "ProgressIndicator", showProgress() ); + conf->writeEntry( "AttentionIndicator", showAttention() ); + conf->writeEntry( "ShowAllWindows", showAllWindows() ); + conf->writeEntry( "GroupWindows", groupWindows() ); + conf->writeEntry( "GroupInactiveDesktops", groupInactiveDesktops() ); + conf->writeEntry( "OnlyShowMinimized", onlyShowMinimized() ); + + conf->setGroup("Layout"); + conf->writeEntry( "Orientation", orientation() ); + conf->writeEntry( "Direction", direction() ); + conf->writeEntry( "Detached", isDetached() ); + + conf->setGroup("Custom Items"); + conf->writeEntry( "ShowClock", showClock() ); + conf->writeEntry( "ShowLoad", showLoad() ); +} + +void KasTasker::writeLayout() +{ + if ( !conf ) + return; + + conf->setGroup("Layout"); + conf->writeEntry( "Orientation", orientation() ); + conf->writeEntry( "Direction", direction() ); + conf->writeEntry( "Detached", isDetached() ); + conf->writeEntry( "DetachedPosition", detachedPosition() ); + conf->sync(); +} + +void KasTasker::showPreferences() +{ + KasPrefsDialog *dlg = new KasPrefsDialog( this ); + dlg->exec(); + delete dlg; + + readConfig(); +} + +void KasTasker::showAbout() +{ + KasAboutDialog *dlg = new KasAboutDialog( 0 ); + dlg->exec(); + delete dlg; +} + diff --git a/kicker/extensions/kasbar/kastasker.h b/kicker/extensions/kasbar/kastasker.h new file mode 100644 index 000000000..1379c8d8c --- /dev/null +++ b/kicker/extensions/kasbar/kastasker.h @@ -0,0 +1,280 @@ +// -*- c++ -*- + +/* kastasker.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ + +#ifndef KASTASKER_H +#define KASTASKER_H + +#include "kasbar.h" + +#include <kdemacros.h> +#include <taskmanager.h> + +class KConfig; +class KPixmap; +class KPopupMenu; +class KAction; +class KToggleAction; + +class Task; +class Startup; + +class KasTaskItem; +class KasStartupItem; +class KasGroupItem; +class KasTasker; +class KasGrouper; + +/** + * A KasBar that provides a taskbar using the TaskManager API. + * + * @author Richard Moore, rich@kde.org + */ +class KDE_EXPORT KasTasker : public KasBar +{ + Q_OBJECT + Q_PROPERTY( bool isTopLevel READ isTopLevel ) + Q_PROPERTY( bool showClock READ showClock ) + Q_PROPERTY( bool showLoad READ showLoad ) + +public: + /** Create a KasTasker widget. */ + KasTasker( Orientation o, QWidget* parent = 0, const char* name = 0, WFlags f = 0 ); + + /** + * Create a KasTasker widget that is slaved to another KasTasker. The + * created widget will inherit the settings of the parent, but will + * not connect to the signals of the TaskManager. + */ + KasTasker( Orientation o, KasTasker *master, + QWidget *parent=0, const char *name=0, WFlags f=0 ); + + /** Cleans up. */ + virtual ~KasTasker(); + + /** Factory method that returns the default menu for items in the bar. */ + virtual KPopupMenu *contextMenu(); + + virtual KasTasker *createChildBar( Orientation o, QWidget *parent, const char *name=0 ); + + /** + * Returns true if this is the top KasTasker. Note that it is possible for + * the top KasTasker to be a child of another KasBar derived class, so + * this can return a different result to KasBar::isTopLevel(). + */ + bool isTopLevel() const { return dynamic_cast<KasTasker *>( KasBar::master() ) ? true : false; } + KasTasker *master() const { return dynamic_cast<KasTasker *>( KasBar::master() ); } + + /** Finds the item representing a task (if there is one). */ + KasTaskItem *findItem( Task::Ptr ); + + /** Finds the item representing a startup (if there is one). */ + KasStartupItem *findItem( Startup::Ptr s ); + + /** Returns true iff thumbnails are enabled. */ + bool thumbnailsEnabled() const { return enableThumbs_; } + + /** Returns true iff thumbnails should be shown in the boxes instead of icons. */ + bool embedThumbnails() const { return embedThumbs_; } + + bool showClock() const { return showClock_; } + bool showLoad() const { return showLoad_; } + + /** Returns the proportions of the window thumbnails. */ + double thumbnailSize() const { return thumbnailSize_; } + + /** Returns true iff the startup notifier is enabled. */ + bool notifierEnabled() const { return enableNotifier_; } + + /** Returns true iff the modified flag should be shown. */ + bool showModified() const { return showModified_; } + + /** Returns true iff a progress bar should be shown for progress windows. */ + bool showProgress() const { return showProgress_; } + + /** Returns true iff we should indicate when a window demands attention. */ + bool showAttention() const { return showAttention_; } + + /** Returns true iff windows from all desktops should be displayed. */ + bool showAllWindows() const { return showAllWindows_; } + + /** Returns the delay between thumbnail updates (in seconds). */ + int thumbnailUpdateDelay() const { return thumbUpdateDelay_; } + + /** Returns true iff windows should be grouped together. */ + bool groupWindows() const { return groupWindows_; } + + /** Returns true iff windows on inactive desktops should be grouped together. */ + bool groupInactiveDesktops() const { return groupInactiveDesktops_; } + + /** Returns true iff we should only show windows that are minimized. */ + bool onlyShowMinimized() const { return onlyShowMinimized_; } + + /** Returns true if this bar is floating. */ + bool isStandAlone() const { return standalone_; } + + // + // Internal stuff + // + + /** + * Converts the item for a task into a group item to which additional + * tasks can be added. + */ + KasGroupItem *convertToGroup( Task::Ptr t ); + + /** Moves an item from a group into the main bar. */ + void moveToMain( KasGroupItem *gi, Task::Ptr t ); + + /** Moves all the items from a group into the main bar and removes the group. */ + void moveToMain( KasGroupItem *gi ); + +public slots: + /** Adds a task to the bar. */ + void addTask( Task::Ptr ); + + /** Removes a task from the bar. */ + void removeTask( Task::Ptr ); + + /** Adds a startup item to the bar. */ + void addStartup( Startup::Ptr ); + + /** Removes a startup item from the bar. */ + void removeStartup( Startup::Ptr ); + + void refreshAll(); + void refreshAllLater(); + void refreshIconGeometry(); + + void setNotifierEnabled( bool enable ); + void setShowModified( bool enable ); + void setShowProgress( bool enable ); + void setShowAttention( bool enable ); + + void setShowAllWindows( bool enable ); + void setGroupWindows( bool enable ); + void setGroupInactiveDesktops( bool enable ); + void setOnlyShowMinimized( bool enable ); + + void setThumbnailSize( double size ); + void setThumbnailSize( int percent ); + void setThumbnailsEnabled( bool enable ); + void setThumbnailUpdateDelay( int secs ); + void setEmbedThumbnails( bool enable ); + + void setShowClock( bool enable ); + void setShowLoad( bool enable ); + + void showPreferences(); + void showAbout(); + + /** Sets the current KConfig object. */ + void setConfig( KConfig *config ); + KConfig *config() const { return conf; } + + /** Reads the settings from the current KConfig. */ + void readConfig(); + void writeConfig(); + void writeConfigLater(); + void writeLayout(); + + /** Writes the settings of this bar to the specified KConfig. */ + void writeConfig( KConfig *conf ); + + void setStandAlone( bool enable ); + +signals: + void showAllWindowsChanged( bool ); + void groupWindowsChanged( bool ); + void showClockChanged( bool ); + void showLoadChanged( bool ); + +protected slots: + /** Load settings from the specified configuration. */ + void readConfig( KConfig *conf ); + +private: + KPopupMenu *menu; + KConfig *conf; + KasGrouper *grouper; + KToggleAction *toggleDetachedAction; + KToggleAction *showAllWindowsAction; + KToggleAction *groupWindowsAction; + KToggleAction *showClockAction; + KToggleAction *showLoadAction; + KAction *rotateBarAction; + bool standalone_; + + bool passive_; + bool enableThumbs_; + bool embedThumbs_; + double thumbnailSize_; + bool enableNotifier_; + bool showModified_; + bool showProgress_; + bool showAllWindows_; + int thumbUpdateDelay_; + bool groupWindows_; + bool groupInactiveDesktops_; + bool showAttention_; + bool onlyShowMinimized_; + bool showClock_; + KasItem *clockItem; + bool showLoad_; + KasItem *loadItem; +}; + +#endif // KASTASKER_H + diff --git a/kicker/extensions/kasbar/kastaskitem.cpp b/kicker/extensions/kasbar/kastaskitem.cpp new file mode 100644 index 000000000..d21d5ccc6 --- /dev/null +++ b/kicker/extensions/kasbar/kastaskitem.cpp @@ -0,0 +1,510 @@ +/* kastaskitem.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <errno.h> + +#include <qbitmap.h> +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qmetaobject.h> +#include <qpainter.h> +#include <qregexp.h> +#include <qtabwidget.h> +#include <qtextview.h> +#include <qtimer.h> +#include <qvbox.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klistview.h> +#include <klocale.h> +#include <kpassivepopup.h> +#include <kpopupmenu.h> +#include <kprocess.h> +#include <dcopclient.h> +#include <kapplication.h> + +#include <taskmanager.h> +#include <taskrmbmenu.h> + +#include "kastasker.h" +#include "kastaskpopup.h" +#include "kastaskitem.h" +#include "kasbarextension.h" + +#define Icon(x) KGlobal::iconLoader()->loadIcon( x, KIcon::NoGroup, KIcon::SizeMedium ) + +static const int CHECK_ATTENTION_DELAY = 2000; + +KasTaskItem::KasTaskItem( KasTasker *parent, Task::Ptr task ) + : KasItem( parent ), + task_(task), + thumbTimer(0), + attentionTimer(0) +{ + setIcon( icon() ); + setAttention( task->demandsAttention() ); + updateTask(false); + + connect( task, SIGNAL( changed(bool) ), this, SLOT( updateTask(bool) ) ); + connect( task, SIGNAL( activated() ), this, SLOT( startAutoThumbnail() ) ); + connect( task, SIGNAL( deactivated() ), this, SLOT( stopAutoThumbnail() ) ); + connect( task, SIGNAL( iconChanged() ), this, SLOT( iconChanged() ) ); + connect( task, SIGNAL( thumbnailChanged() ), this, SLOT( iconChanged() ) ); + + connect( this, SIGNAL(leftButtonClicked(QMouseEvent *)), SLOT(toggleActivateAction()) ); + connect( this, SIGNAL(rightButtonClicked(QMouseEvent *)), SLOT(showWindowMenuAt(QMouseEvent *) ) ); + + attentionTimer = new QTimer( this, "attentionTimer" ); + connect( attentionTimer, SIGNAL( timeout() ), SLOT( checkAttention() ) ); + attentionTimer->start( CHECK_ATTENTION_DELAY ); +} + +KasTaskItem::~KasTaskItem() +{ +} + +KasTasker *KasTaskItem::kasbar() const +{ + return static_cast<KasTasker *> (KasItem::kasbar()); +} + +QPixmap KasTaskItem::icon() +{ + int sizes[] = { KIcon::SizeEnormous, + KIcon::SizeHuge, + KIcon::SizeLarge, + KIcon::SizeMedium, + KIcon::SizeSmall }; + + if ( kasbar()->embedThumbnails() && task_->hasThumbnail() ) { + usedIconLoader = true; + + QPixmap thumb = task_->thumbnail(); + QSize sz = thumb.size(); + sz.scale( sizes[kasbar()->itemSize()], sizes[kasbar()->itemSize()], QSize::ScaleMin ); + + QImage img = thumb.convertToImage(); + img = img.smoothScale( sz ); + + bool ok = thumb.convertFromImage( img ); + if ( ok ) + return thumb; + } + + usedIconLoader = false; + QPixmap p = task_->bestIcon( sizes[kasbar()->itemSize()], usedIconLoader ); + if ( !p.isNull() ) + return p; + + return task_->icon( sizes[kasbar()->itemSize()], sizes[kasbar()->itemSize()], true ); +} + +void KasTaskItem::iconChanged() +{ + iconHasChanged = true; + setIcon( icon() ); + update(); +} + +void KasTaskItem::checkAttention() +{ + setAttention( task_->demandsAttention() ); +} + +void KasTaskItem::updateTask(bool geometryChangeOnly) +{ + if (geometryChangeOnly) + { + return; + } + + bool updates = kasbar()->isUpdatesEnabled(); + kasbar()->setUpdatesEnabled( false ); + + setProgress( kasbar()->showProgress() ? 0 : -1 ); + setText( task_->visibleIconicName() ); + setModified( task_->isModified() ); + setActive( task_->isActive() ); + + kasbar()->setUpdatesEnabled( updates ); + update(); +} + +void KasTaskItem::paint( QPainter *p ) +{ + KasItem::paint( p ); + + KasResources *res = resources(); + QColor c = task_->isActive() ? res->activePenColor() : res->inactivePenColor(); + p->setPen( c ); + + // + // Overlay the small icon if the icon has changed, we have space, + // and we are using a KIconLoader icon rather than one from the NET props. + // This only exists because we are almost always using the icon loader for + // large icons. + // + KasTasker *kas = kasbar(); + bool haveSpace = ( kas->itemSize() != KasBar::Small ) + && ( kas->itemSize() != KasBar::Medium ); + + if ( usedIconLoader && iconHasChanged && haveSpace ) { + QPixmap pix = icon(); + int x = (extent() - 4 - pix.width()) / 2; + QPixmap overlay = task_->pixmap(); + p->drawPixmap( x-4+pix.width()-overlay.width(), 18, overlay ); + } + + // + // Draw window state. + // + if( task_->isIconified() ) + paintStateIcon( p, StateIcon ); + else if ( task_->isShaded() ) + paintStateIcon( p, StateShaded ); + else + paintStateIcon( p, StateNormal ); + + // + // Draw desktop number. + // + + // Check if we only have one desktop + bool oneDesktop = (TaskManager::the()->numberOfDesktops() == 1) ? true : false; + + QString deskStr; + if ( task_->isOnAllDesktops() ) + deskStr = i18n( "All" ); + else + deskStr.setNum( task_->desktop() ); + + + if ( kas->itemSize() != KasBar::Small ) { + // Medium and Large modes + if ( !oneDesktop ) + p->drawText( extent()-fontMetrics().width(deskStr)-3, 15+fontMetrics().ascent(), deskStr ); + + // Draw document state. + if ( kas->showModified() ) + paintModified( p ); + } + else { + // Small mode + if ( !oneDesktop ) + p->drawText( extent()-fontMetrics().width(deskStr)-2, 13+fontMetrics().ascent(), deskStr ); + } +} + +void KasTaskItem::toggleActivateAction() +{ + hidePopup(); + + if ( task_->isActive() && task_->isShaded() ) { + task_->setShaded( false ); + } + else { + task_->activateRaiseOrIconify(); + } +} + +void KasTaskItem::showWindowMenuAt( QMouseEvent *ev ) +{ + hidePopup(); + showWindowMenuAt( ev->globalPos() ); +} + +KasPopup *KasTaskItem::createPopup() +{ + KasPopup *pop = new KasTaskPopup( this ); + pop->adjustSize(); + return pop; +} + +void KasTaskItem::dragOverAction() +{ + if ( !task_->isOnCurrentDesktop() ) + task_->toCurrentDesktop(); + if ( task_->isShaded() ) + task_->setShaded( false ); + if ( task_->isIconified() ) + task_->restore(); + if ( !task_->isActive() ) + task_->activate(); +} + +void KasTaskItem::startAutoThumbnail() +{ + if ( thumbTimer ) + return; + if ( !kasbar()->thumbnailsEnabled() ) + return; + + if ( kasbar()->thumbnailUpdateDelay() > 0 ) { + thumbTimer = new QTimer( this, "thumbTimer" ); + connect( thumbTimer, SIGNAL( timeout() ), SLOT( refreshThumbnail() ) ); + + thumbTimer->start( kasbar()->thumbnailUpdateDelay() * 1000 ); + } + + QTimer::singleShot( 200, this, SLOT( refreshThumbnail() ) ); +} + +void KasTaskItem::stopAutoThumbnail() +{ + if ( !thumbTimer ) + return; + + delete thumbTimer; + thumbTimer = 0; +} + +void KasTaskItem::refreshThumbnail() +{ + if ( !kasbar()->thumbnailsEnabled() ) + return; + if ( !task_->isActive() ) + return; + + // TODO: Check if the popup obscures the window + KasItem *i = kasbar()->itemUnderMouse(); + if ( i && i->isShowingPopup() ) { + QTimer::singleShot( 200, this, SLOT( refreshThumbnail() ) ); + return; + } + + task_->setThumbnailSize( kasbar()->thumbnailSize() ); + task_->updateThumbnail(); +} + +void KasTaskItem::showWindowMenuAt( QPoint p ) +{ + TaskRMBMenu *tm = new TaskRMBMenu(task_, true, kasbar()); + tm->insertItem( i18n("To &Tray" ), this, SLOT( sendToTray() ) ); + tm->insertSeparator(); + tm->insertItem( i18n("&Kasbar"), kasbar()->contextMenu() ); + tm->insertSeparator(); + tm->insertItem( i18n("&Properties" ), this, SLOT( showPropertiesDialog() ) ); + + mouseLeave(); + kasbar()->updateMouseOver(); + + tm->exec( p ); +} + +void KasTaskItem::sendToTray() +{ + QString s; + s.setNum( task_->window() ); + + KProcess proc; + proc << "ksystraycmd"; + proc << "--wid" << s << "--hidden"; + + bool ok = proc.start( KProcess::DontCare ); + if ( !ok ) { + kdWarning(1345) << "Unable to launch ksystraycmd" << endl; + KPassivePopup::message( i18n("Could Not Send to Tray"), + i18n("%1").arg(strerror(errno)), + Icon("error"), + kasbar() ); + return; + } + + proc.detach(); +} + +void KasTaskItem::showPropertiesDialog() +{ + // + // Create Dialog + // + QDialog *dlg = new QDialog( /*kasbar()*/0L, "task_props", false ); + + // + // Title + // + KPopupTitle *title = new KPopupTitle( dlg, "title" ); + dlg->setCaption( i18n("Task Properties") ); + title->setText( i18n("Task Properties") ); + title->setIcon( icon() ); + + // + // Tabbed View + // + QTabWidget *tabs = new QTabWidget( dlg ); + tabs->addTab( createX11Props( tabs ), i18n("General") ); + tabs->addTab( createTaskProps( task_, tabs ), i18n("Task") ); + + tabs->addTab( createTaskProps( this, tabs ), i18n("Item") ); + tabs->addTab( createTaskProps( kasbar(), tabs, false ), i18n("Bar") ); + +#if 0 + tabs->addTab( createNETProps( tabs ), i18n("NET") ); +#endif + + // + // Layout Dialog + // + QVBoxLayout *vbl = new QVBoxLayout( dlg, KDialog::marginHint(), KDialog::spacingHint() ); + vbl->addWidget( title ); + vbl->addWidget( tabs ); + + dlg->resize( 470, 500 ); + dlg->show(); + +} + +QWidget *KasTaskItem::createTaskProps( QObject *target, QWidget *parent, bool recursive ) +{ + QVBox *vb = new QVBox( parent ); + vb->setSpacing( KDialog::spacingHint() ); + vb->setMargin( KDialog::marginHint() ); + + // Create List View + KListView *taskprops = new KListView( vb, "props_view" ); + taskprops->setResizeMode( QListView::LastColumn ); + taskprops->addColumn( i18n("Property"), 0 ); + taskprops->addColumn( i18n("Type"), 0 ); + taskprops->addColumn( i18n("Value") ); + + // Create List Items + QMetaObject *mo = target->metaObject(); + for ( int i = 0; i < mo->numProperties( recursive ); i++ ) { + const QMetaProperty *p = mo->property(i, recursive); + + (void) new KListViewItem( taskprops, + p->name(), p->type(), + target->property( p->name() ).toString() ); + } + + return vb; +} + +QString KasTaskItem::expandMacros( const QString &format, QObject *data ) +{ + QString s = format; + QRegExp re("\\$(\\w+)"); + + int pos = 0; + while ( pos >= 0 ) { + pos = re.search( s, pos ); + if ( pos >= 0 ) { + QVariant val = data->property( re.cap(1).latin1() ); + QString v = val.asString(); + s.replace( pos, re.matchedLength(), v ); + pos = pos + v.length(); + } + } + + return s; +} + +QWidget *KasTaskItem::createX11Props( QWidget *parent ) +{ + QVBox *vb2 = new QVBox( parent ); + vb2->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred ); + vb2->setSpacing( KDialog::spacingHint() ); + vb2->setMargin( KDialog::marginHint() ); + + // Create View + new QLabel( i18n("General"), vb2, "view" ); + QTextView *tv = new QTextView( vb2 ); + + QString fmt = i18n( + "<html>" + "<body>" + "<b>Name</b>: $name<br>" + "<b>Visible name</b>: $visibleName<br>" + "<br>" + "<b>Iconified</b>: $iconified<br>" + "<b>Minimized</b>: $minimized<br>" + "<b>Maximized</b>: $maximized<br>" + "<b>Shaded</b>: $shaded<br>" + "<b>Always on top</b>: $alwaysOnTop<br>" + "<br>" + "<b>Desktop</b>: $desktop<br>" + "<b>All desktops</b>: $onAllDesktops<br>" + "<br>" + "<b>Iconic name</b>: $iconicName<br>" + "<b>Iconic visible name</b>: $visibleIconicName<br>" + "<br>" + "<b>Modified</b>: $modified<br>" + "<b>Demands attention</b>: $demandsAttention<br>" + "</body>" + "</html>" + ); + + tv->setText( expandMacros( fmt, task_ ) ); + tv->setWordWrap( QTextEdit::WidgetWidth ); + + return vb2; +} + +QWidget *KasTaskItem::createNETProps( QWidget *parent ) +{ + QVBox *vb3 = new QVBox( parent ); + vb3->setSpacing( KDialog::spacingHint() ); + vb3->setMargin( KDialog::marginHint() ); + + // Create View + new QLabel( i18n("NET WM Specification Info"), vb3, "view" ); + new QTextView( vb3 ); + + return vb3; +} + +#include "kastaskitem.moc" diff --git a/kicker/extensions/kasbar/kastaskitem.h b/kicker/extensions/kasbar/kastaskitem.h new file mode 100644 index 000000000..cc7d0d188 --- /dev/null +++ b/kicker/extensions/kasbar/kastaskitem.h @@ -0,0 +1,135 @@ +/* kastaskitem.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + + +#ifndef KASTASKITEM_H +#define KASTASKITEM_H + +#include <qpixmap.h> +#include "kasitem.h" + +class Task; +class KasPopup; +class KasTasker; +class KPixmap; + +/** + * A KasItem that represents a single Task. + */ +class KasTaskItem : public KasItem +{ + Q_OBJECT + + public: + KasTaskItem( KasTasker *parent, Task::Ptr task ); + virtual ~KasTaskItem(); + + QPixmap icon(); + + /** Reimplemented to paint the item. */ + virtual void paint( QPainter *p ); + + /** Returns the task the item is displaying. */ + Task::Ptr task() const { return task_; } + + /** Returns the parent KasTasker object. */ + KasTasker *kasbar() const; + + QString expandMacros( const QString &format, QObject *data ); + +public slots: + void updateTask(bool geometryChangeOnly); + + /** Create a thumbnail for this task (does nothing if they're disabled). */ + void refreshThumbnail(); + + void startAutoThumbnail(); + void stopAutoThumbnail(); + + void iconChanged(); + void checkAttention(); + + void showWindowMenuAt( QPoint pos ); + void sendToTray(); + void showPropertiesDialog(); + + void toggleActivateAction(); + void showWindowMenuAt( QMouseEvent *ev ); + +protected: + /** + * Reimplemented to create a KasTaskPopup. + */ + virtual KasPopup *createPopup(); + + QWidget *createTaskProps( QObject *target, QWidget *parent=0, bool recursive=true ); + QWidget *createX11Props( QWidget *tabbed ); + QWidget *createNETProps( QWidget *tabbed ); + + /** + * Reimplemented to activate the task. + */ + void dragOverAction(); + +private: + Task::Ptr task_; + QTimer *thumbTimer; + bool usedIconLoader; + bool iconHasChanged; + QTimer *attentionTimer; +}; + +#endif // KASTASKITEM_H + diff --git a/kicker/extensions/kasbar/kastaskpopup.cpp b/kicker/extensions/kasbar/kastaskpopup.cpp new file mode 100644 index 000000000..91f3ecbc9 --- /dev/null +++ b/kicker/extensions/kasbar/kastaskpopup.cpp @@ -0,0 +1,139 @@ +/* kastaskpopup.cpp +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +#include <qpainter.h> +#include <qapplication.h> + +#include <kdebug.h> +#include <kglobalsettings.h> +#include <kpixmapeffect.h> + +#include <taskmanager.h> + +#include "kastaskitem.h" +#include "kastasker.h" + +#include "kastaskpopup.h" +#include "kastaskpopup.moc" + +static const int TITLE_HEIGHT = 13; + +KasTaskPopup::KasTaskPopup( KasTaskItem *item, const char *name ) + : KasPopup( item, name ) +{ + this->item = item; + + setFont(KGlobalSettings::generalFont()); + setMouseTracking( true ); + + QString text = item->task()->visibleIconicName(); + if ( item->kasbar()->thumbnailsEnabled() && item->task()->hasThumbnail() ) { + titleBg.resize( width(), TITLE_HEIGHT ); + + setFixedSize( item->task()->thumbnail().width() + 2, + TITLE_HEIGHT + item->task()->thumbnail().height() + 2 ); + } + else { + int w = fontMetrics().width( text ) + 4; + int h = TITLE_HEIGHT + 1; + titleBg.resize( w, h ); + setFixedSize( w, h ); + } + + KPixmapEffect::gradient( titleBg, + Qt::black, colorGroup().mid(), + KPixmapEffect::DiagonalGradient ); + + connect( item->task(), SIGNAL( thumbnailChanged() ), SLOT( refresh() ) ); +} + +KasTaskPopup::~KasTaskPopup() +{ +} + +void KasTaskPopup::refresh() +{ + QString text = item->task()->visibleIconicName(); + if ( item->kasbar()->thumbnailsEnabled() && item->task()->hasThumbnail() ) { + resize( item->task()->thumbnail().width() + 2, + TITLE_HEIGHT + item->task()->thumbnail().height() + 2 ); + titleBg.resize( width(), TITLE_HEIGHT ); + } + update(); +} + +void KasTaskPopup::paintEvent( QPaintEvent * ) +{ + QPainter p( this ); + p.drawPixmap( 0, 0, titleBg ); + + QString text = item->task()->visibleIconicName(); + + p.setPen( Qt::white ); + if ( fontMetrics().width( text ) > width() - 4 ) + p.drawText( 1, 1, width() - 4, TITLE_HEIGHT - 1, AlignLeft | AlignVCenter, + text ); + else + p.drawText( 1, 1, width() - 4, TITLE_HEIGHT - 1, AlignCenter, text ); + + QPixmap thumb = item->task()->thumbnail(); + if ( !thumb.isNull() ) + p.drawPixmap( 1, TITLE_HEIGHT, thumb ); + + // + // Draw border + // + p.setPen( Qt::black ); + p.drawRect( 0, 0, width(), height() ); +} + diff --git a/kicker/extensions/kasbar/kastaskpopup.h b/kicker/extensions/kasbar/kastaskpopup.h new file mode 100644 index 000000000..8118fff6c --- /dev/null +++ b/kicker/extensions/kasbar/kastaskpopup.h @@ -0,0 +1,90 @@ +/* kastaskpopup.h +** +** Copyright (C) 2001-2004 Richard Moore <rich@kde.org> +** Contributor: Mosfet +** All rights reserved. +** +** KasBar is dual-licensed: you can choose the GPL or the BSD license. +** Short forms of both licenses are included below. +*/ + +/* +** 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 in a file called COPYING; if not, write to +** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +** MA 02110-1301, USA. +*/ + +/* +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* +** Bug reports and questions can be sent to kde-devel@kde.org +*/ +// -*- c++ -*- + +#ifndef KASTASKPOPUP_H +#define KASTASKPOPUP_H + +#include <kpixmap.h> +#include "kaspopup.h" + +class KasTaskItem; + +/** + * A subclass of KasPopup which shows info about a task. + * + * @author Richard Moore, rich@kde.org + */ +class KasTaskPopup : public KasPopup +{ + Q_OBJECT + +public: + KasTaskPopup( KasTaskItem *item, const char *name=0 ); + virtual ~KasTaskPopup(); + +public slots: + void refresh(); + +protected: + virtual void paintEvent( QPaintEvent * ); + + private: + KasTaskItem *item; + KPixmap titleBg; +}; + +#endif // KASTASKPOPUP_H + + diff --git a/kicker/extensions/kasbar/version.h b/kicker/extensions/kasbar/version.h new file mode 100644 index 000000000..57554a838 --- /dev/null +++ b/kicker/extensions/kasbar/version.h @@ -0,0 +1,3 @@ +#define VERSION_STRING "v3-0.06" +#define HOMEPAGE_URL "http://xmelegance.org/kasbar/" + diff --git a/kicker/extensions/sidebar/Makefile.am b/kicker/extensions/sidebar/Makefile.am new file mode 100644 index 000000000..18f0cfbc0 --- /dev/null +++ b/kicker/extensions/sidebar/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = -I$(top_srcdir)/libkonq $(all_includes) + +kde_module_LTLIBRARIES = sidebar_panelextension.la + +sidebar_panelextension_la_SOURCES = sidebarextension.cpp + +sidebar_panelextension_la_METASOURCES = AUTO +sidebar_panelextension_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +sidebar_panelextension_la_LIBADD = $(LIB_KDEUI) $(LIB_KPARTS) ../../../libkonq/libkonq.la + + +lnkdir = $(kde_datadir)/kicker/extensions +lnk_DATA = sidebarextension.desktop + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/kickersidebarextension.pot diff --git a/kicker/extensions/sidebar/sidebarextension.cpp b/kicker/extensions/sidebar/sidebarextension.cpp new file mode 100644 index 000000000..a959f7f87 --- /dev/null +++ b/kicker/extensions/sidebar/sidebarextension.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + sidebarextension.cpp + ------------------- + begin : Sun July 20 16:00:00 CEST 2003 + copyright : (C) 2003 Joseph Wenninger + email : jowenn@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include "sidebarextension.h" +#include "sidebarextension.moc" +#include <kdebug.h> +#include <kmessagebox.h> +#include <kglobal.h> +#include <klocale.h> +#include <kparts/part.h> +#include <kparts/componentfactory.h> +#include <qlayout.h> +#include <konq_historymgr.h> +#include <krun.h> +#include <kurl.h> +#include <qvbox.h> +#include <qcursor.h> + +extern "C" +{ + KDE_EXPORT KPanelExtension *init( QWidget *parent, const QString& configFile ) + { + KGlobal::locale()->insertCatalogue("kickersidebarextension"); + KGlobal::locale()->insertCatalogue("konqueror"); + return new SidebarExtension( configFile, + KPanelExtension::Normal, + 0, + parent, "kickersidebarextension"); + } +} + +SidebarExtension::SidebarExtension( const QString& configFile, + Type type, + int actions, + QWidget *parent, const char *name ) + : KPanelExtension( configFile, type, actions, parent, name ),m_resizing(false),m_expandedSize(200) +{ + kdDebug() << "SidebarExtension: Created '" << name << "', '" << configFile << "'" << endl; + new KonqHistoryManager(0,"SidebarExtensionHistoryManager"); + m_layout=new QHBoxLayout(this); + m_layout->activate(); + m_sbWrapper=new QVBox(this); + KParts::ReadOnlyPart *p=KParts::ComponentFactory::createPartInstanceFromLibrary<KParts::ReadOnlyPart>( + "konq_sidebar", + m_sbWrapper, + "SideBar_View", + this, + "Sidebar","universal"); + + KParts::BrowserExtension *be=KParts::BrowserExtension::childObject(p); + if (be) { + connect(be,SIGNAL(openURLRequest( const KURL &, const KParts::URLArgs &)), + this,SLOT(openURLRequest( const KURL &, const KParts::URLArgs &))); + connect(be,SIGNAL(createNewWindow( const KURL &, const KParts::URLArgs &)), + this,SLOT(openURLRequest( const KURL &, const KParts::URLArgs &))); + + } + + m_resizeHandle=new QFrame(this); + m_resizeHandle->setFrameShape(QFrame::Panel); + m_resizeHandle->setFrameShadow(QFrame::Raised); + m_resizeHandle->setFixedWidth(6); + m_resizeHandle->setCursor(QCursor(Qt::SizeHorCursor)); + connect(p->widget(),SIGNAL(panelHasBeenExpanded(bool)),this,SLOT(needLayoutUpdate(bool))); + needLayoutUpdate(false); + m_resizeHandle->installEventFilter(this); + m_resizeHandle->setMouseTracking(true); +// l->add(p->widget()); +// p->widget()->show(); +// l->activate(); + +} + +void SidebarExtension::needLayoutUpdate(bool exp) { + setReserveStrut(!exp); // only reserve a strut when we are collapsed + if (exp) { + m_currentWidth=m_expandedSize; + m_resizeHandle->show(); + raise(); + } else { + m_currentWidth=24; + m_resizeHandle->hide(); + } + topLevelWidget()->setFixedWidth(m_currentWidth); + emit updateLayout(); +} + +void SidebarExtension::openURLRequest( const KURL &url, const KParts::URLArgs &) { + KRun::runCommand("kfmclient openURL \""+url.prettyURL()+"\"", "kfmclient", "konqueror"); + +} + + +SidebarExtension::~SidebarExtension() +{ + KGlobal::locale()->removeCatalogue("kickersidebarextension"); + KGlobal::locale()->removeCatalogue("konqueror"); +} + +bool SidebarExtension::eventFilter( QObject *, QEvent *e ) { + if (e->type()==QEvent::MouseButtonPress) { + m_resizing=true; + m_x=((QMouseEvent*)e)->globalX(); + return true; + } else if (e->type()==QEvent::MouseButtonRelease) { + m_resizing=false; + m_expandedSize=topLevelWidget()->width(); + needLayoutUpdate(true); + return true; + } else if (e->type()==QEvent::MouseMove) { + if (m_resizing) { + Position p=position(); + if (p==Left) { + int diff=((QMouseEvent*)e)->globalX()-m_x; + if (abs(diff)>3) { + topLevelWidget()->setFixedWidth(topLevelWidget()->width()+diff); + m_x=((QMouseEvent*)e)->globalX(); + } + } else if (p==Right) { + int diff=((QMouseEvent*)e)->globalX()-m_x; + if (abs(diff)>3) { + topLevelWidget()->setFixedWidth(topLevelWidget()->width()-diff); + topLevelWidget()->move(topLevelWidget()->x()+diff,topLevelWidget()->y()); + m_x=((QMouseEvent*)e)->globalX(); + } + } + return true; + } + } + return false; +} + +KPanelExtension::Position SidebarExtension::preferedPosition() const { + kdDebug()<<"SidebarExtension::preferedPosition()***************"<<endl; + return KPanelExtension::Left; +} + +QSize SidebarExtension::sizeHint(Position, QSize maxSize ) const +{ + return QSize(m_currentWidth,maxSize.height()); +} + +void SidebarExtension::positionChange( Position position ) { + if (position == Right) { + m_layout->remove(m_sbWrapper); + m_layout->remove(m_resizeHandle); + + m_layout->add(m_resizeHandle); + m_layout->add(m_sbWrapper); + } else if (position == Left) { + m_layout->remove(m_sbWrapper); + m_layout->remove(m_resizeHandle); + + m_layout->add(m_sbWrapper); + m_layout->add(m_resizeHandle); + + } + +} + +void SidebarExtension::about() +{ +} + +void SidebarExtension::preferences() +{ +} + diff --git a/kicker/extensions/sidebar/sidebarextension.desktop b/kicker/extensions/sidebar/sidebarextension.desktop new file mode 100644 index 000000000..8ff52adb7 --- /dev/null +++ b/kicker/extensions/sidebar/sidebarextension.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=Universal Sidebar +Name[af]=Universele Kantbalk +Name[ar]=الشريط الجانبي العالمي +Name[az]=Ãœmumi Yan Çubuq +Name[be]=УніверÑÐ°Ð»ÑŒÐ½Ð°Ñ Ð±Ð°ÐºÐ°Ð²Ð°Ñ Ð¿Ð°Ð½Ñль +Name[bg]=УниверÑален панел +Name[bn]=সারà§à¦¬à¦œà¦¨à§€à¦¨ সাইডবার +Name[bs]=Univerzalni sidebar +Name[ca]=Barra universal +Name[cs]=Univerzálnà postrannà liÅ¡ta +Name[csb]=Ùniwersalnô bòcznô lëstew +Name[cy]=BarOchr Cyffredinol +Name[da]=Universel sidebjælke +Name[de]=Universeller Navigationsbereich +Name[el]=Καθολική πλευÏική μπάÏα +Name[eo]=Äœenerala flankzono +Name[es]=Barra lateral universal +Name[et]=Universaalne külgriba +Name[eu]=Alboko barra unibertsala +Name[fa]=میله جانبی عمومی +Name[fi]=Yleissivupalkki +Name[fr]=Barre latérale universelle +Name[fy]=Universele sydbalke +Name[ga]=Barra Taoibh UilÃoch +Name[gl]=Barra Lateral Universal +Name[he]=סרגל־צד ××•× ×™×‘×¨×¡×œ×™ +Name[hi]=सरà¥à¤µà¤µà¥à¤¯à¤¾à¤ªà¥€ बाज़ू-पटà¥à¤Ÿà¥€ +Name[hr]=Univerzalna boÄna traka +Name[hu]=Univerzális oldalsáv +Name[is]=Algild hliðarslá +Name[it]=Barra laterale universale +Name[ja]=汎用サイドãƒãƒ¼ +Name[ka]=უნივერსáƒáƒšáƒ£áƒ ი გვერდითი პáƒáƒœáƒ”ლი +Name[kk]=Әмбебап бүйірдегі панель +Name[km]=របារ​ចំហៀង​ទូទៅ +Name[lt]=Universali Å¡oninÄ— juosta +Name[lv]=UnversÄlÄ sÄnjosla +Name[mk]=Универзална Ñтранична лента +Name[mn]=УниверÑал хажуу Ñамбар +Name[ms]=Bar Sisi Universal +Name[mt]=Sidebar Universali +Name[nb]=Universell sidestolpe +Name[nds]=Siet-Navigatschoonbalken +Name[ne]=विशà¥à¤µà¤µà¥à¤¯à¤¾à¤ªà¥€ छेउपटà¥à¤Ÿà¥€ +Name[nl]=Universele zijbalk +Name[nn]=Universell sidestolpe +Name[pa]=ਯੂਨੀਵਰਸਲ ਬਾਹੀ +Name[pl]=Uniwersalny pasek boczny +Name[pt]=Barra Lateral Universal +Name[pt_BR]=Barra Lateral Universal +Name[ro]=Bară laterală universală +Name[ru]=УниверÑÐ°Ð»ÑŒÐ½Ð°Ñ Ð±Ð¾ÐºÐ¾Ð²Ð°Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ +Name[rw]=Umurongokuruhande Mpuzamahanga +Name[se]=Universella holga +Name[sk]=Univerzálny boÄný panel +Name[sl]=Univerzalna stranska vrstica +Name[sr]=Универзална бочна трака +Name[sr@Latn]=Univerzalna boÄna traka +Name[sv]=Generell sidopanel +Name[ta]=பொத௠வரலாறà¯à®±à¯à®ªà¯ பகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿ +Name[th]=à¹à¸–บข้าง +Name[tr]=Genel Yan Çubuk +Name[tt]=Küpçaralı Yantirä +Name[uk]=УніверÑальна бічна панель +Name[uz]=Universal yon paneli +Name[uz@cyrillic]=УниверÑал ён панели +Name[vi]=Thanh bên Chung +Name[wa]=BÃ¥r di costé universele +Name[zh_CN]=通用侧边æ +Name[zh_TW]=整體的邊列 + +Comment=Wrapper around Konqueror's navigation panel +Comment[af]='n Toevou program rondom Konqueror se navigasie paneel +Comment[be]=ПанÑль Ð´Ð»Ñ Ñ…ÑƒÑ‚ÐºÐ°Ð¹ навігацыі +Comment[bg]=Допълнителен универÑален панел, подобен на панела на браузъра +Comment[bn]=কনকরার-à¦à¦° নà§à¦¯à¦¾à¦à¦¿à¦—েশন পà§à¦¯à¦¾à¦¨à§‡à¦²-à¦à¦° পà§à¦°à¦¸à¦¾à¦°à¦£ +Comment[bs]=OmotaÄ za Konquerorov navigacioni panel +Comment[ca]=Embolcall al voltant del plafó de navegació del Konqueror +Comment[csb]=Programa òpakòwujÄ…cô nawigacëjny panel Konquerora +Comment[cy]=Lapiad o gwmpas panel morlywio Konqueror +Comment[da]=Konvolut om Konquerors navigationspanel +Comment[de]=Erweiterung zum Navigationsbereich von Konqueror +Comment[el]=Ενσωματωτής στο ΠεÏιηγητή του Konqueror +Comment[eo]=Åœelo ĉirkaÅ la Konkeranta stirpanelo +Comment[es]=Envoltura para el panel de navegación de Konqueror +Comment[et]=Konquerori liikumisriba skelett +Comment[eu]=Konquerorren arakatze panelerako bilgarria +Comment[fa]=سطرشکن در اطرا٠تابلوی ناوش Konqueror +Comment[fi]=Kuori Konquerorin navigaatiopaneelin ympärille +Comment[fr]=Un enveloppement autour du panneau de navigation de Konqueror +Comment[fy]=In kontainer rûn de Konqueror's navigaasjepaniel +Comment[gl]=Reutilización do painel de navegación de Konqueror +Comment[he]=מעטפת מסביב ללוח ×”× ×™×•×•×˜ של Konqueror +Comment[hi]=कॉनà¥à¤•à¤°à¤° के नेविगेशन फलक के चारों ओर रैपर +Comment[hr]=OmotaÄ oko Konqueror navigacijske ploÄe +Comment[hu]=Segédelem a Konqueror navigációs paneljéhez +Comment[is]=Lag à kringum stjórnborð Konqueror vefrans +Comment[it]=Wrapper per il pannello di navigazione di Konqueror +Comment[ja]=Konqueror ã®ãƒŠãƒ“ゲーションパãƒãƒ«ã®ãƒ©ãƒƒãƒ‘ー +Comment[ka]=Konqueror -ის პáƒáƒœáƒ”ლის დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბელი +Comment[kk]=Konqueror's баÑқару панелінің өңдеушіÑÑ– +Comment[km]=Wrapper ជុំ​វិញ​បន្ទះ​រុករក​របស់ Konqueror +Comment[lt]=Konqueror navigacijos pulto dÄ—klas +Comment[lv]=IekarotÄja navigÄcijas paneļa vraperis +Comment[mk]=Обвивка околу навигациониот панел на Konqueror +Comment[ms]=Pembalut sekeliling panel navigasi Konqueror +Comment[mt]="Wrapper" madwar il-pannell ta' navigazzjoni ta' Konqueror +Comment[nb]=Overbygning pÃ¥ navigasjonspanelet i Konqueror +Comment[nds]=Konqueror sien Navigatschoonpaneel för den Schriefdisch +Comment[ne]=कनà¥à¤•à¥à¤µà¥‡à¤°à¤°à¤•à¥‹ नेà¤à¤¿à¤—ेसन पà¥à¤¯à¤¾à¤¨à¤² वरिपरि आवरण +Comment[nl]=Een container rond Konqueror's navigatiepaneel +Comment[nn]=Overbygning pÃ¥ navigasjonspanelet i Konqueror +Comment[pa]=ਕੋਨਕਿਉਰਰ ਦੇ à¨à¨§à¨°-ਓਧਰ ਪੈਨਲ ਲਈ ਸਮੇਟਣ ਵਾਲੀ +Comment[pl]=Program opakowujÄ…cy panel nawigacyjny Konquerora +Comment[pt]=Uma interface sobre o painel de navegação do Konqueror +Comment[pt_BR]=Wrapper para o painel de navegação do Konqueror +Comment[ro]=O încapsulare a panoului de navigare Konqueror +Comment[ru]=Обработчик панели навигации Konqueror +Comment[rw]=Mufunika hafi y'umwanya w'ibuganya wa Konqueror +Comment[sk]=Obálka pre navigaÄný panel Konquerora +Comment[sl]=Objemalnik okoli Konquerorjevega navigacijskega pulta +Comment[sr]=Омотач Konqueror-вог навигационог панела +Comment[sr@Latn]=OmotaÄ Konqueror-vog navigacionog panela +Comment[sv]=Omgivning för Konquerors navigeringspanel +Comment[ta]=கானà¯à®•à¯Šà®°à®°à¯ நவிகேஷன௠பலகதà¯à®¤à¯ˆ சà¯à®±à¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. +Comment[th]=หุ้มà¸à¸¢à¸¹à¹ˆà¸£à¸à¸šà¹† Navigation panel ขà¸à¸‡à¸„à¸à¸™à¹€à¸„วà¸à¸£à¹Œà¹€à¸£à¸à¸£à¹Œ +Comment[tr]=Konqueror'un yönlendirme paneli çevresindeki satır atlatıcı +Comment[tt]=Konqueror'nıñ küçü taqtasınıñ sıydırması +Comment[uk]=Обгортка навколо навігаційної панелі Konqueror +Comment[vi]=Bao bá»c xung quanh bảng duyệt của Konqueror +Comment[wa]=On bagaedje Ã¥toû do scriftôr di naiviaedje di Konqueror +Comment[zh_CN]=Konqueror 导航é¢æ¿çš„转æ¢å™¨ +Comment[zh_TW]=包è£æ–¼ konqueror 的導覽é¢æ¿ + +Icon=view_sidetree + +X-KDE-Library=sidebar_panelextension +X-KDE-UniqueApplet=true +X-KDE-PanelExt-Resizeable=true +X-KDE-PanelExt-StdSizes=true +X-KDE-PanelExt-StdSizeDefault=1 +X-KDE-PanelExt-CustomSizeMin=24 +X-KDE-PanelExt-CustomSizeMax=400 +X-KDE-PanelExt-CustomSizeDefault=200 +X-KDE-UniqueExtension=true +X-KDE-PanelExt-Positions=Left,Right diff --git a/kicker/extensions/sidebar/sidebarextension.h b/kicker/extensions/sidebar/sidebarextension.h new file mode 100644 index 000000000..a44c270ba --- /dev/null +++ b/kicker/extensions/sidebar/sidebarextension.h @@ -0,0 +1,63 @@ +/*************************************************************************** + sidebarextension.h + ------------------- + begin : Sun July 20 16:00:00 CEST 2003 + copyright : (C) 2003 Joseph Wenninger + email : jowenn@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef SIDEBAREXTENSION_H +#define SIDEBAREXTENSION_H + +#include <kpanelextension.h> +#include <kurl.h> +#include <kparts/browserextension.h> + +class QHBoxLayout; +class QVBox; + +class SidebarExtension : public KPanelExtension +{ + Q_OBJECT + +public: + SidebarExtension( const QString& configFile, + Type t = Normal, + int actions = 0, + QWidget *parent = 0, const char *name = 0 ); + + virtual ~SidebarExtension(); + + QSize sizeHint( Position, QSize maxSize ) const; + Position preferedPosition() const; + + virtual void positionChange( Position position ); + +protected: + virtual void about(); + virtual void preferences(); + virtual bool eventFilter( QObject *o, QEvent *e ); +protected slots: + void openURLRequest( const KURL &, const KParts::URLArgs &); + void needLayoutUpdate(bool); + +private: + int m_currentWidth; + int m_x; + QFrame *m_resizeHandle; + bool m_resizing; + int m_expandedSize; + QHBoxLayout *m_layout; + QVBox *m_sbWrapper; +}; + +#endif + diff --git a/kicker/extensions/taskbar/Makefile.am b/kicker/extensions/taskbar/Makefile.am new file mode 100644 index 000000000..4dfa1b929 --- /dev/null +++ b/kicker/extensions/taskbar/Makefile.am @@ -0,0 +1,23 @@ +INCLUDES = -I$(srcdir)/../../taskmanager -I$(srcdir)/../../taskbar -I$(srcdir)/../../libkicker -I$(top_builddir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = taskbar_panelextension.la + +taskbar_panelextension_la_SOURCES = taskbarextension.cpp taskbarextension.skel +taskbar_panelextension_la_METASOURCES = AUTO +taskbar_panelextension_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +taskbar_panelextension_la_LIBADD = $(LIB_KDEUI) $(LIB_KPARTS) \ + ../../libkicker/libkickermain.la \ + ../../taskmanager/libtaskmanager.la \ + ../../taskbar/libtaskbar.la + +noinst_HEADERS = taskbarextension.h + +lnkdir = $(kde_datadir)/kicker/extensions +lnk_DATA = taskbarextension.desktop + +EXTRA_DIST = $(lnk_DATA) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/taskbarextension.pot + +taskbarextension.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/extensions/taskbar/taskbarextension.cpp b/kicker/extensions/taskbar/taskbarextension.cpp new file mode 100644 index 000000000..a25297b39 --- /dev/null +++ b/kicker/extensions/taskbar/taskbarextension.cpp @@ -0,0 +1,235 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlayout.h> +#include <qtimer.h> +#include <qwmatrix.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <krootpixmap.h> +#include <kstandarddirs.h> + +#include "global.h" +#include "kickerSettings.h" +#include "taskbarcontainer.h" + +#include "taskbarextension.h" +#include "taskbarextension.moc" + +extern "C" +{ + KDE_EXPORT KPanelExtension* init( QWidget *parent, const QString& configFile ) + { + KGlobal::locale()->insertCatalogue( "taskbarextension" ); + return new TaskBarExtension( configFile, KPanelExtension::Stretch, + KPanelExtension::Preferences, parent, "taskbarextension" ); + } +} + +TaskBarExtension::TaskBarExtension(const QString& configFile, Type type, + int actions, QWidget *parent, const char *name) + : KPanelExtension(configFile, type, actions, parent, name), + m_bgImage(0), + m_bgFilename(0), + m_rootPixmap(0) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + m_container = new TaskBarContainer(false, this); + m_container->setBackgroundOrigin(AncestorOrigin); + positionChange(position()); + layout->addWidget(m_container); + + connect(m_container, SIGNAL(containerCountChanged()), + SIGNAL(updateLayout())); + + kapp->dcopClient()->setNotifications(true); + connectDCOPSignal("kicker", "kicker", "configurationChanged()", + "configure()", false); + + connect(kapp, SIGNAL(kdisplayPaletteChanged()), + SLOT(setBackgroundTheme())); + + QTimer::singleShot(0, this, SLOT(setBackgroundTheme())); +} + +TaskBarExtension::~TaskBarExtension() +{ + KGlobal::locale()->removeCatalogue( "taskbarextension" ); +} + +void TaskBarExtension::positionChange( Position p ) +{ + + m_container->orientationChange(orientation()); + + switch (p) + { + case Bottom: + m_container->popupDirectionChange(KPanelApplet::Up); + break; + case Top: + m_container->popupDirectionChange(KPanelApplet::Down); + break; + case Right: + m_container->popupDirectionChange(KPanelApplet::Left); + break; + case Left: + m_container->popupDirectionChange(KPanelApplet::Right); + break; + case Floating: + if (orientation() == Horizontal) + { + m_container->popupDirectionChange(KPanelApplet::Down); + } + else if (QApplication::reverseLayout()) + { + m_container->popupDirectionChange(KPanelApplet::Left); + } + else + { + m_container->popupDirectionChange(KPanelApplet::Right); + } + break; + } + setBackgroundTheme(); +} + +void TaskBarExtension::preferences() +{ + m_container->preferences(); +} + +QSize TaskBarExtension::sizeHint(Position p, QSize maxSize) const +{ + if (p == Left || p == Right) + maxSize.setWidth(sizeInPixels()); + else + maxSize.setHeight(sizeInPixels()); + +// kdDebug(1210) << "TaskBarExtension::sizeHint( Position, QSize )" << endl; +// kdDebug(1210) << " width: " << size.width() << endl; +// kdDebug(1210) << "height: " << size.height() << endl; + return m_container->sizeHint(p, maxSize); +} + +void TaskBarExtension::configure() +{ + setBackgroundTheme(); + update(); +} + +void TaskBarExtension::setBackgroundTheme() +{ + if (KickerSettings::transparent()) + { + if (!m_rootPixmap) + { + m_rootPixmap = new KRootPixmap(this); + m_rootPixmap->setCustomPainting(true); + connect(m_rootPixmap, SIGNAL(backgroundUpdated(const QPixmap&)), + SLOT(updateBackground(const QPixmap&))); + } + else + { + m_rootPixmap->repaint(true); + } + + double tint = double(KickerSettings::tintValue()) / 100; + m_rootPixmap->setFadeEffect(tint, KickerSettings::tintColor()); + m_rootPixmap->start(); + return; + } + else if (m_rootPixmap) + { + delete m_rootPixmap; + m_rootPixmap = 0; + } + + unsetPalette(); + + if (KickerSettings::useBackgroundTheme()) + { + QString bgFilename = locate("appdata", KickerSettings::backgroundTheme()); + + if (m_bgFilename != bgFilename) + { + m_bgFilename = bgFilename; + m_bgImage.load(m_bgFilename); + } + + if (!m_bgImage.isNull()) + { + QImage bgImage = m_bgImage; + + if (orientation() == Vertical) + { + if (KickerSettings::rotateBackground()) + { + QWMatrix matrix; + matrix.rotate(position() == KPanelExtension::Left ? 90: 270); + bgImage = bgImage.xForm(matrix); + } + + bgImage = bgImage.scaleWidth(size().width()); + } + else + { + if (position() == KPanelExtension::Top && + KickerSettings::rotateBackground()) + { + QWMatrix matrix; + matrix.rotate(180); + bgImage = bgImage.xForm(matrix); + } + + bgImage = bgImage.scaleHeight(size().height()); + } + + if (KickerSettings::colorizeBackground()) + { + KickerLib::colorize(bgImage); + } + setPaletteBackgroundPixmap(bgImage); + } + } + + m_container->setBackground(); +} + +void TaskBarExtension::updateBackground(const QPixmap& bgImage) +{ + unsetPalette(); + setPaletteBackgroundPixmap(bgImage); + m_container->setBackground(); +} + +void TaskBarExtension::resizeEvent(QResizeEvent *e) +{ + QFrame::resizeEvent(e); + setBackgroundTheme(); +} + diff --git a/kicker/extensions/taskbar/taskbarextension.desktop b/kicker/extensions/taskbar/taskbarextension.desktop new file mode 100644 index 000000000..691e3fe0e --- /dev/null +++ b/kicker/extensions/taskbar/taskbarextension.desktop @@ -0,0 +1,147 @@ +[Desktop Entry] +Name=External Taskbar +Name[af]=Eksterne Taakbalk +Name[ar]=شريط المهام الخارجي +Name[az]=Xarici VÉ™zifÉ™ ÇubuÄŸu +Name[be]=Ð’Ð¾Ð½ÐºÐ°Ð²Ð°Ñ Ð¿Ð°Ð½Ñль заданнÑÑž +Name[bg]=Допълнителна лента +Name[bn]=বহিঃসà§à¦¥ টাসà§à¦•à¦¬à¦¾à¦° +Name[br]=Barrenn dleadoù diavaez +Name[bs]=Eksterni taskbar +Name[ca]=Barra de tasques externa +Name[cs]=Externà pruh úloh +Name[csb]=Bùtnowô lëstew dzejaniów +Name[cy]=Bar tasgau allanol +Name[da]=Ekstern opgavelinje +Name[de]=Externe Fensterleiste +Name[el]=ΕξωτεÏική γÏαμμή εÏγασιών +Name[eo]=Ekstera Taskostrio +Name[es]=Barra de tareas externa +Name[et]=Väline tegumiriba +Name[eu]=Kanpoko ataza-barra +Name[fa]=میله‌ تکلی٠خارجی +Name[fi]=Ulkoinen ohjelmapalkki +Name[fr]=Barre des tâches externe +Name[fy]=Eksterne taakbalke +Name[ga]=Tascbharra Seachtrach +Name[gl]=Barra de Tarefas Externa +Name[he]=שורת משימות ×—×™×¦×•× ×™×ª +Name[hi]=बाहरी कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ +Name[hr]=Vanjska traka zadataka +Name[hu]=KülsÅ‘ feladatlista +Name[id]=Taskbar eksternal +Name[is]=Utanáliggjandi verkefnaslá +Name[it]=Barra delle applicazioni esterna +Name[ja]=外部タスクãƒãƒ¼ +Name[ka]=გáƒáƒ¤áƒáƒ თáƒáƒ•áƒ”ბული áƒáƒ›áƒáƒªáƒáƒœáƒáƒ—რპáƒáƒœáƒ”ლი +Name[kk]=Сыртқы тапÑырмалар панелі +Name[km]=របារ​ភារកិច្ច​ážáž¶áž„​ក្រៅ +Name[lo]=ຖາດງານພາàºàº™àºàº +Name[lt]=IÅ¡orinÄ— užduoÄių juosta +Name[lv]=Ä€rÄ“jÄ Uzdevumjosla +Name[mk]=Ðадворешна лента Ñо програми +Name[mn]=Гадаад ажлын Ñамбар +Name[ms]=Taskbar Luaran +Name[mt]=Taskbar Estern +Name[nb]=Ekstern oppgavelinje +Name[nds]=Extern Programmbalken +Name[ne]=बाहà¥à¤¯ कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ +Name[nl]=Externe taakbalk +Name[nn]=Ekstern oppgÃ¥velinje +Name[nso]=Bar ya Mosongwana wa Kantle +Name[pa]=ਬਾਹਰੀ ਕੰਮ-ਪੱਟੀ +Name[pl]=ZewnÄ™trzny pasek zadaÅ„ +Name[pt]=Barra de Tarefas Externa +Name[pt_BR]=Barra de Tarefas Externa +Name[ro]=Bară de procese externă +Name[ru]=ВнешнÑÑ Ð¿Ð°Ð½ÐµÐ»ÑŒ задач +Name[rw]=Umurongoibikorwa w'Inyuma +Name[se]=Olgguldas bargoholga +Name[sk]=Externý taskbar +Name[sl]=Zunanja opravilna vrstica +Name[sr]=Спољашња трака задатака +Name[sr@Latn]=SpoljaÅ¡nja traka zadataka +Name[sv]=Externt aktivitetsfält +Name[ta]=பà¯à®± பணிபà¯à®ªà®Ÿà¯à®Ÿà®¿ +Name[tg]=Сафҳаи маÑъалаҳои ваÑеъ +Name[th]=ถาดงานภายนà¸à¸ +Name[tr]=Harici Görev ÇubuÄŸu +Name[tt]=Tışqı EÅŸlärtirä +Name[uk]=Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ñмужка задач +Name[uz]=Vazifalar tashqi paneli +Name[uz@cyrillic]=Вазифалар ташқи панели +Name[ven]=Bara ya mushumo ya nga nnda +Name[vi]=Thanh tác vụ Ngoà i +Name[wa]=BÃ¥r Ã¥s bouyes dÃ¥ dfoû +Name[xh]=Ibar yomsebenzi Wangaphandle +Name[zh_CN]=外部任务æ +Name[zh_TW]=外部工作列 +Name[zu]=Ibha yemisebenzi yangaphandle +Comment=External taskbar panel extension +Comment[af]=Eksterne taakbalk paneel uitbreiding +Comment[ar]=تمديدة لوØØ© شريط المهام الخارجي +Comment[be]=Вонкавае пашырÑнне панÑлі заданнÑÑž +Comment[bg]=Допълнителна лента за задачите +Comment[bn]=মূল পà§à¦¯à¦¾à¦¨à§‡à¦²-à¦à¦° বাইরে আলাদা টাসà§à¦•à¦¬à¦¾à¦° +Comment[bs]=ProÅ¡irenje panela za eksterni taskbar +Comment[ca]=Extensió del plafó de la barra de tasques externa +Comment[cs]=RozÅ¡ÃÅ™enà s externÃm pruhem úloh +Comment[csb]=Rozszérzenié panelu z bùtnowÄ… lëstwÄ… dzejaniów +Comment[cy]=Estyniad panel bar tasgau allanol +Comment[da]=Paneludvidelse - ekstern joblinje +Comment[de]=Eine alternative Fensterleiste +Comment[el]=ΕπÎκταση του πίνακα εξωτεÏική γÏαμμή εÏγασιών +Comment[eo]=Ekstera taskostria panelaldono +Comment[es]=Extensión del panel con barra de tareas externa +Comment[et]=Välise tegumiriba laiendus +Comment[eu]=Panelaren hedapena kanpoko ataza-barrarekin +Comment[fa]=پسوند تابلوی میله‌ تکلی٠خارجی +Comment[fi]=Ulkoinen ohjelmapalkin paneelilaajennus +Comment[fr]=Barre des tâches externe +Comment[fy]=Eksterne taakbalke +Comment[gl]=Extensión do painel da barra de tarefas externa +Comment[he]=הרחבת שורת משימות ×—×™×¦×•× ×™×ª +Comment[hr]=Vanjsko proÅ¡irenje ploÄe trake zadataka +Comment[hu]=KülsÅ‘ feladatlista-kiterjesztés +Comment[is]=ÚtvÃkkun utanáliggjandi spjalds +Comment[it]=Barra delle applicazioni esterna +Comment[ja]=外部タスクãƒãƒ¼ãƒ‘ãƒãƒ«æ‹¡å¼µ +Comment[ka]=გáƒáƒ ე პულტისრდრპáƒáƒœáƒ”ლის გáƒáƒ¤áƒáƒ თáƒáƒ”ბრ+Comment[kk]=ҚоÑымша тапÑырмалар панелі. +Comment[km]=ផ្នែក​បន្ážáŸ‚ម​បន្ទះ​របារ​ភារកិច្ច​ážáž¶áž„​ក្រៅ ។ +Comment[lt]=IÅ¡orinis užduoÄių juostos praplÄ—timas +Comment[mk]=ЕкÑтензија на панелот - надворешна лента Ñо програми. +Comment[nb]=Oppgavelinje utenfor panelet +Comment[nds]=En Programmbalken buten dat Paneel +Comment[ne]=बाहà¥à¤¯ कारà¥à¤¯à¤ªà¤Ÿà¥à¤Ÿà¥€ पà¥à¤¯à¤¾à¤¨à¤² विसà¥à¤¤à¤¾à¤° +Comment[nl]=Externe taakbalk +Comment[nn]=OppgÃ¥velinje utanfor panelet +Comment[pa]=ਬਾਹਰੀ ਕੰਮਪੱਟੀ ਪੈਨਲ ਵਧਾਰਾ +Comment[pl]=Rozszerzenie panelu z zewnÄ™trznym paskiem zadaÅ„ +Comment[pt]=Extensão do painel de barra de tarefas externa +Comment[pt_BR]=Extensão do painel para a barra de tarefas externa +Comment[ro]=Extensie pentru bară de procese externă +Comment[ru]=ВнешнÑÑ Ð¿Ð°Ð½ÐµÐ»ÑŒ задач KDE +Comment[se]=Olgguldas bargoholga viiddádus +Comment[sk]=RozÅ¡Ãrenie externého panelu úloh +Comment[sl]=Zunanja razÅ¡iritev opravilne vrstice +Comment[sr]=Спољашња трака задатака, проширење панела. +Comment[sr@Latn]=SpoljaÅ¡nja traka zadataka, proÅ¡irenje panela. +Comment[sv]=Extern utökning till aktivitetsfältet +Comment[th]=ส่วนขยายเพิ่มเติมà¹à¸à¸žà¹€à¸žà¸¥à¹‡à¸•à¸–าดงานภายนà¸à¸ +Comment[tr]=Harici görev çubuÄŸu uzantısı. +Comment[uk]=Зовнішнє Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– задач +Comment[vi]=Bảng Ä‘iá»u khiển mở rá»™ng có thanh tác vụ bên ngoà i +Comment[wa]=On module di scriftôr di bÃ¥r Ã¥s bouyes dÃ¥ dfoû +Comment[zh_CN]=外部任务æ é¢æ¿æ‰©å±• +Comment[zh_TW]=外部工作列é¢æ¿å»¶ä¼¸ + +Icon=taskbar +X-KDE-Library=taskbar_panelextension +X-KDE-UniqueApplet=true +X-KDE-PanelExt-Resizeable=true +X-KDE-PanelExt-StdSizes=true +X-KDE-PanelExt-StdSizeDefault=1 +X-KDE-PanelExt-CustomSizeMin=24 +X-KDE-PanelExt-CustomSizeMax=400 +X-KDE-PanelExt-CustomSizeDefault=58 diff --git a/kicker/extensions/taskbar/taskbarextension.h b/kicker/extensions/taskbar/taskbarextension.h new file mode 100644 index 000000000..021420483 --- /dev/null +++ b/kicker/extensions/taskbar/taskbarextension.h @@ -0,0 +1,72 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskbarextension_h__ +#define __taskbarextension_h__ + +#include <qimage.h> + +#include <dcopobject.h> +#include <kpanelextension.h> + +class KRootPixmap; +class TaskBarContainer; + +class TaskBarExtension : public KPanelExtension, virtual public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + int panelSize() { return sizeInPixels(); } + int panelOrientation() { return static_cast<int>(orientation()); } + int panelPosition() { return static_cast<int>(position()); } + void setPanelSize(int size) { setSize(static_cast<Size>(size),true);}///slotSetSize(size); } + void configure(); + +public: + TaskBarExtension( const QString& configFile, Type t = Normal, + int actions = 0, QWidget *parent = 0, const char *name = 0 ); + ~TaskBarExtension(); + + QSize sizeHint( Position, QSize maxSize ) const; + Position preferedPosition() const { return Bottom; } + +protected: + void resizeEvent(QResizeEvent*); + + void positionChange( Position ); + void preferences(); + +private: + TaskBarContainer *m_container; + QImage m_bgImage; + QString m_bgFilename; + KRootPixmap *m_rootPixmap; + +private slots: + void setBackgroundTheme(); + void updateBackground(const QPixmap&); +}; + +#endif diff --git a/kicker/kicker/Makefile.am b/kicker/kicker/Makefile.am new file mode 100644 index 000000000..857ac9cff --- /dev/null +++ b/kicker/kicker/Makefile.am @@ -0,0 +1,40 @@ +INCLUDES = $(all_includes) + +SUBDIRS = core ui buttons . + +bin_PROGRAMS = +lib_LTLIBRARIES = +kdeinit_LTLIBRARIES = kicker.la + +CLEANFILES = dummy.cpp + +kicker_la_LIBADD = core/libkicker_core.la buttons/libkicker_buttons.la \ + ui/libkicker_ui.la ../libkicker/libkickermain.la $(LIB_KIO) $(LIB_KUTILS) + +kicker_la_SOURCES = dummy.cpp +kicker_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +autostart_DATA = panel.desktop +autostartdir = $(datadir)/autostart + +xdg_apps_DATA = kcmkicker.desktop + +messages: rc.cpp + $(EXTRACTRC) ui/*ui >> rc.cpp + $(EXTRACTRC) core/*.kcfg >> rc.cpp + $(XGETTEXT) buttons/*.cpp core/*.cpp ui/*.cpp *.cpp -o $(podir)/kicker.pot + +dummy.cpp: + echo > $@ + +kconf_PROGRAMS = kicker-3.4-reverseLayout +kconfdir = $(libdir)/kconf_update_bin + +kicker_3_4_reverseLayout_SOURCES = kicker-3.4-reverseLayout.cpp +kicker_3_4_reverseLayout_LDADD = $(LIB_QT) $(LIB_KDECORE) +kicker_3_4_reverseLayout_LDFLAGS = $(all_libraries) + +updatedir = $(kde_datadir)/kconf_update +update_DATA = kickerrc.upd +update_SCRIPTS = kicker-3.1-properSizeSetting.pl kicker-3.5-taskbarEnums.pl kicker-3.5-kconfigXTize.pl + diff --git a/kicker/kicker/buttons/Makefile.am b/kicker/kicker/buttons/Makefile.am new file mode 100644 index 000000000..2ba4d20c6 --- /dev/null +++ b/kicker/kicker/buttons/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I$(srcdir)/../core -I$(srcdir)/../../libkicker -I../../libkicker \ + -I$(srcdir)/../ui -I$(top_srcdir)/libkonq $(all_includes) + +noinst_LTLIBRARIES = libkicker_buttons.la + +libkicker_buttons_la_SOURCES = servicebutton.cpp bookmarksbutton.cpp \ + browserbutton.cpp \ + desktopbutton.cpp extensionbutton.cpp kbutton.cpp \ + nonkdeappbutton.cpp servicemenubutton.cpp urlbutton.cpp \ + windowlistbutton.cpp + +libkicker_buttons_la_LDFLAGS = $(all_libraries) +libkicker_buttons_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(LIB_KDEUI) $(XTESTLIB) +libkicker_buttons_la_METASOURCES = AUTO + +desktopmenu_DATA = bookmarks.desktop browser.desktop desktop.desktop \ + exec.desktop kmenu.desktop windowlist.desktop +desktopmenudir = $(kde_datadir)/kicker/builtins + +browserbutton.lo: ../../libkicker/kickerSettings.h +desktopbutton.lo: ../../libkicker/kickerSettings.h +panelbutton.lo: ../../libkicker/kickerSettings.h +servicebutton.lo: ../../libkicker/kickerSettings.h +urlbutton.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/kicker/buttons/bookmarks.desktop b/kicker/kicker/buttons/bookmarks.desktop new file mode 100644 index 000000000..2957099d1 --- /dev/null +++ b/kicker/kicker/buttons/bookmarks.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Bookmarks Menu +Name[af]=Boekmerke Kieslys +Name[ar]=قائمة علامات مواقع +Name[be]=Меню закладак +Name[bg]=Отметки +Name[bn]=বà§à¦•à¦®à¦¾à¦°à§à¦• মেনৠ+Name[br]=Meuziad ar sinedoù +Name[bs]=Meni zabiljeÅ¡ki +Name[ca]=Menú de punts +Name[cs]=NabÃdka záložek +Name[csb]=Załóżczi +Name[da]=Bogmærkemenu +Name[de]=Lesezeichen +Name[el]=ÎœÎµÎ½Î¿Ï ÏƒÎµÎ»Î¹Î´Î¿Î´ÎµÎ¹ÎºÏ„ÏŽÎ½ +Name[eo]=Legosigna Menuo +Name[es]=Marcadores +Name[et]=Järjehoidjate menüü +Name[eu]=Laster-marken menua +Name[fa]=گزینگان چوب الÙها +Name[fi]=Kirjanmerkit +Name[fr]=Menu des signets +Name[fy]=Blêdwizers menu +Name[ga]=Roghchlár na Leabharmharcanna +Name[gl]=Marcadores +Name[he]=תפריט ×¡×™×ž× ×™×•×ª +Name[hr]=Izbornik oznaka +Name[hu]=KönyvjelzÅ‘k menü +Name[is]=Bókamerkjavalmynd +Name[it]=Menu dei segnalibri +Name[ja]=ブックマークメニュー +Name[ka]=სáƒáƒœáƒ˜áƒ¨áƒœáƒ”ების მენიუ +Name[kk]=Бетбелгілер мәзірі +Name[km]=ម៉ឺនុយ​ចំណាំ +Name[ko]=책갈피 +Name[lt]=Žymelių meniu +Name[mk]=Мени Ñо обележувачи +Name[nb]=Bokmerkemeny +Name[nds]=Leestekens +Name[ne]=पà¥à¤¸à¥à¤¤à¤•à¤šà¤¿à¤¨à¥‹ मेनॠ+Name[nl]=Bladwijzermenu +Name[nn]=Bokmerkemeny +Name[pa]=ਬà©à©±à¨•à¨®à¨¾à¨°à¨• ਮੇਨੂ +Name[pl]=ZakÅ‚adki +Name[pt]=Menu de Favoritos +Name[pt_BR]=Menu favoritos +Name[ro]=Meniu semne de carte +Name[ru]=Закладки +Name[rw]=Ibikubiyemo by'Utumenyetso +Name[se]=Girjemearkafállu +Name[sk]=Menu záložiek +Name[sl]=Meni z zaznamki +Name[sr]=Мени маркера +Name[sr@Latn]=Meni markera +Name[sv]=Bokmärkesmeny +Name[te]=పేజి à°—à±à°°à±à°¤à±à°² పటà±à°Ÿà°¿ +Name[tg]=Менюи хатчӯбҳо +Name[th]=ที่คั่นหน้า +Name[tr]=Yer imleri Menüsü +Name[tt]=Bitbilge Saylağı +Name[uk]=Меню закладок +Name[uz]=XatchoÊ»plar menyusi +Name[uz@cyrillic]=Хатчўплар менюÑи +Name[vi]=Thá»±c Ä‘Æ¡n có Sổ lÆ°u liên kết +Name[wa]=Dressêye des rmÃ¥kes +Name[zh_CN]=书ç¾èœå• +Name[zh_TW]=書籤é¸å–® +Comment=Your Konqueror bookmarks +Comment[af]=Jou Konqueror boekmerke +Comment[ar]=علامات مواقعك Ù„Ùــ Konqueror +Comment[be]=Закладкі Konqueror +Comment[bg]=Отметки на браузъра +Comment[bn]=আপনার কনকরার বà§à¦•à¦®à¦¾à¦°à§à¦•-সমূহ +Comment[bs]=VaÅ¡e Konqueror zabiljeÅ¡ke +Comment[ca]=Els vostres punts Konqueror +Comment[cs]=VaÅ¡e záložky Konqueroru +Comment[csb]=Załóżczi Konquerora +Comment[da]=Dine Konqueror bogmærker +Comment[de]=Ein Menü mit Ihren Konqueror-Lesezeichen +Comment[el]=Οι σελιδοδείκτες σας του Konqueror +Comment[eo]=Viaj Konkeranto-legosignoj +Comment[es]=Sus marcadores de Konqueror +Comment[et]=Konquerori järjehoidjad +Comment[eu]=Zure Konquerorren laster-markak +Comment[fa]=چوب ‌الÙهای Konqueror شما +Comment[fi]=Konquerorin kirjanmerkit +Comment[fr]=Vos signets Konqueror +Comment[fy]=Jo blêdwizers yn Konqueror +Comment[ga]=Do Chuid Leabharmharcanna Konqueror +Comment[gl]=Os seus marcadores de Konqueror +Comment[he]=×”×¡×™×ž× ×™×•×ª Konqueror שלך +Comment[hr]=VaÅ¡e Konqueror oznake +Comment[hu]=A Konqueror könyvjelzÅ‘i +Comment[is]=Konqueror bókamerkin þÃn +Comment[it]=I tuoi segnalibri di Konqueror +Comment[ja]=Konqueror ブックマーク +Comment[ka]=Konqueror-ის თქვენი სáƒáƒœáƒ˜áƒ¨áƒœáƒ”ები +Comment[kk]=Konqueror шолғыштың бетбелгілері +Comment[km]=ចំណាំ Konqueror របស់​អ្នក +Comment[lt]=Konqueror žymelÄ—s +Comment[mk]=Вашите обележувачи од Konqueror +Comment[nb]=Dine bokmerker i Konqueror +Comment[nds]=Menü mit Dien Konqueror-Leestekens +Comment[ne]=तपाईà¤à¤•à¥‹ कनà¥à¤•à¥à¤µà¥‡à¤°à¤°à¤•à¤¾ पà¥à¤¸à¥à¤¤à¤•à¤šà¤¿à¤¨à¥‹ +Comment[nl]=Uw bladwijzers in Konqueror +Comment[nn]=Konqueror-bokmerka +Comment[pa]=ਤà©à¨¹à¨¾à¨¡à©‡ ਕੋਨਕਿਉਰੋਰ ਬà©à©±à¨•à¨®à¨¾à¨°à¨• +Comment[pl]=ZakÅ‚adki Konquerora +Comment[pt]=Os seus favoritos do Konqueror +Comment[pt_BR]=Seus favoritos do Konqueror +Comment[ro]=Semnele de carte Konqueror +Comment[ru]=Закладки Konqueror +Comment[rw]=Ibimenyetso bya Konqueror yawe +Comment[se]=Konqueror:a girjemearkkat +Comment[sk]=Konqueror záložky +Comment[sl]=Meni z zaznamki iz Konquerorja +Comment[sr]=Ваши маркери у Konqueror-у +Comment[sr@Latn]=VaÅ¡i markeri u Konqueror-u +Comment[sv]=Dina bokmärken i Konqueror +Comment[te]=మీ కాంకెరరౠపేజి à°—à±à°°à±à°¤à±à°²à± +Comment[tg]=Хатчӯбҳои Konqueror +Comment[th]=ที่คั่นหน้าคà¸à¸™à¹€à¸„วà¸à¸£à¹Œà¹€à¸£à¸à¸£à¹Œà¸‚à¸à¸‡à¸„ุณ +Comment[tr]=Konqueror yer imleriniz +Comment[tt]=Konqueror Bitbilgeläre +Comment[uk]=Закладки з Konqueror +Comment[uz]=Konqueror xatchoÊ»plari +Comment[uz@cyrillic]=Konqueror хатчўплари +Comment[vi]=Các liên kết đã lÆ°u tại Konqueror của bạn +Comment[wa]=Vos rmÃ¥kes Konqueror +Comment[zh_CN]=您的 Konqueror ä¹¦ç¾ +Comment[zh_TW]=您的 Konqueror 書籤 +Icon=bookmark +X-KDE-Library=BookmarksButton diff --git a/kicker/kicker/buttons/bookmarksbutton.cpp b/kicker/kicker/buttons/bookmarksbutton.cpp new file mode 100644 index 000000000..b351af263 --- /dev/null +++ b/kicker/kicker/buttons/bookmarksbutton.cpp @@ -0,0 +1,72 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> + +#include <kaction.h> +#include <kbookmark.h> +#include <kbookmarkmenu.h> +#include <konqbookmarkmanager.h> +#include <klocale.h> +#include <kpopupmenu.h> + +#include "bookmarksbutton.h" +#include "bookmarksbutton.moc" + +BookmarksButton::BookmarksButton(QWidget* parent) + : PanelPopupButton(parent, "BookmarksButton"), + bookmarkParent(0), + bookmarkMenu(0), + actionCollection(0), + bookmarkOwner(0) +{ + actionCollection = new KActionCollection( this ); + bookmarkParent = new KPopupMenu(this, "bookmarks"); + bookmarkOwner = new KBookmarkOwner; + bookmarkMenu = new KBookmarkMenu(KonqBookmarkManager::self(), + bookmarkOwner, + bookmarkParent, + actionCollection, + true, false); + setPopup(bookmarkParent); + QToolTip::add(this, i18n("Bookmarks")); + setTitle(i18n("Bookmarks")); + setIcon("bookmark"); +} + +BookmarksButton::~BookmarksButton() +{ + delete bookmarkMenu; + delete bookmarkOwner; +} + +void BookmarksButton::initPopup() +{ + bookmarkMenu->ensureUpToDate(); +} + +void BookmarksButton::properties() +{ + KonqBookmarkManager::self()->slotEditBookmarks(); +} + diff --git a/kicker/kicker/buttons/bookmarksbutton.h b/kicker/kicker/buttons/bookmarksbutton.h new file mode 100644 index 000000000..95ffa9609 --- /dev/null +++ b/kicker/kicker/buttons/bookmarksbutton.h @@ -0,0 +1,58 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __bookmarksbutton_h__ +#define __bookmarksbutton_h__ + +#include "panelbutton.h" + +class KPopupMenu; +class KBookmarkMenu; +class KActionCollection; +class KBookmarkOwner; + +/** + * Button that contains a bookmark menu + */ +class BookmarksButton : public PanelPopupButton +{ + Q_OBJECT + +public: + BookmarksButton(QWidget* parent); + ~BookmarksButton(); + + void loadConfig(const KConfigGroup& config); + virtual void properties(); + +protected: + virtual QString tileName() { return "WindowList"; } + virtual void initPopup(); + + KPopupMenu* bookmarkParent; + KBookmarkMenu* bookmarkMenu; + KActionCollection* actionCollection; + KBookmarkOwner* bookmarkOwner; +}; + +#endif diff --git a/kicker/kicker/buttons/browser.desktop b/kicker/kicker/buttons/browser.desktop new file mode 100644 index 000000000..f7236786b --- /dev/null +++ b/kicker/kicker/buttons/browser.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Name=Quick File Browser +Name[af]=Vinnige Lêer Blaaier +Name[ar]=متصÙØ Ù…Ù„Ùات سريع +Name[be]=Хуткі праглÑд +Name[bg]=Бърз файлов браузър +Name[bn]=চটপট ফাইল বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° +Name[bs]=Brzi preglednik datoteka +Name[ca]=Fullejador de fitxers rà pid +Name[cs]=Rychlý prohlÞeÄ souborů +Name[csb]=Chùtczé przezéranié lopków +Name[da]=Hurtig filsøgning +Name[de]=Schnellanzeiger +Name[el]=ΓÏήγοÏος πεÏιηγητής αÏχείων +Name[eo]=Rapida Dosiero Legilo +Name[es]=Navegador rápido de archivos +Name[et]=Failide kiirbrauser +Name[eu]=Fitxategi arakatzaile bizkorra +Name[fa]=مرورگر پروندۀ سریع +Name[fi]=Nopea tiedostoselain +Name[fr]=Explorateur de fichiers rapide +Name[fy]=Flugge triem blêder +Name[gl]=Navegador Rápido +Name[he]=דפדפן ×§×‘×¦×™× ×ž×”×™×¨ +Name[hr]=Brzi pretraživaÄ datoteka +Name[hu]=Gyors fájlböngészÅ‘ +Name[is]=Flýti skráarvafri +Name[it]=Browser rapido dei file +Name[ja]=クイックファイルブラウザ +Name[ka]=ფáƒáƒ˜áƒšáƒ”ბის სწრáƒáƒ¤áƒ˜ ნუსხრ+Name[kk]=Жедел файл шолғышы +Name[km]=កម្មវិធី​រុករកឯកសារ​រហáŸážŸ +Name[lt]=Paprasta bylų narÅ¡yklÄ— +Name[mk]=Брз прелиÑтувач на датотеки +Name[nb]=Enkel filbehandler +Name[nds]=Fix-Dateiwieser +Name[ne]=दà¥à¤°à¥à¤¤ फाइल बà¥à¤°à¤¾à¤‰à¤œà¤° +Name[nn]=Snøgglesar +Name[pa]=ਤੇਜ਼ ਫਾਇਲ à¨à¨²à¨•à¨¾à¨°à¨¾ +Name[pl]=Szybkie przeglÄ…danie plików +Name[pt]=Navegação Rápida de Ficheiros +Name[pt_BR]=Navegador de Arquivos Rápido +Name[ro]=Navigator de fiÈ™iere rapid +Name[ru]=БыÑтрый выбор файла +Name[rw]=Mucukumbuzi y'Idosiye Yihuta +Name[se]=Jođánis fiilagieÄ‘ahalli +Name[sk]=Rýchly prehliadaÄ súborov +Name[sl]=Preprost brskalnik +Name[sr]=Брзи прегледач фајлова +Name[sr@Latn]=Brzi pregledaÄ fajlova +Name[sv]=Snabbfilbläddrare +Name[tg]=Интихоби файлҳои тез +Name[th]=โปรà¹à¸à¸£à¸¡à¹€à¸£à¸µà¸¢à¸à¸”ูไฟล์à¸à¸¢à¹ˆà¸²à¸‡à¸£à¸§à¸”เร็ว +Name[tr]=Hızlı Dosya Tarayıcı +Name[tt]=Tiz Birem-Küzätüçe +Name[uk]=Швидкий навігатор файлів +Name[uz]=Tez koÊ»ruvchi +Name[uz@cyrillic]=Тез кўрувчи +Name[vi]=Duyệt nhanh các táºp tin +Name[wa]=Betchteu d' fitchî simpe +Name[zh_CN]=快速文件æµè§ˆå™¨ +Name[zh_TW]=快速檔案ç€è¦½å™¨ +Comment=A menu that lists files in a given folder +Comment[af]='n Kieslys wat die lêers in 'n spesifieke gids vertoon +Comment[ar]=قائمة تعرض الملÙات ÙÙŠ مجلّد معيين +Comment[be]=Меню, Ñкое паказвае файлы Ñž вызначанай Ñ‚Ñчцы +Comment[bg]=Меню, което показва файловете в зададена Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ +Comment[bn]=à¦à¦•à¦Ÿà¦¿ মেনৠযা ফোলà§à¦¡à¦¾à¦°-à¦à¦° ফাইলসমূহ তালিকাবদà§à¦§ করে +Comment[bs]=Meni u kojem se nalaze datoteke u datom direktoriju +Comment[ca]=Un menú que llista els fitxers d'una carpeta +Comment[cs]=NabÃdka vypisujÃcà soubory v dané složce +Comment[csb]=Menu pokazëwôjÄ…ce lopczi w pòdónym katalogù +Comment[da]=En menu der lister filer i en given mappe +Comment[de]=Ein Menü, das die Dateien eines bestimmten Ordners auflistet +Comment[el]=Ένα Î¼ÎµÎ½Î¿Ï Ï€Î¿Ï… εμφανίζει τα αÏχεία ενός δοσμÎνου φακÎλου +Comment[eo]=Menuo kiu listigas dosierojn en la nomita dosierujo +Comment[es]=Un menú que le muestra los archivos de una carpeta +Comment[et]=Menüü, mis näitab valitud kataloogi faile +Comment[eu]=Emandako karpetako fitxategiak zerrendatzen dituen menua +Comment[fa]=گزینگانی Ú©Ù‡ پرونده‌ها را در پوشۀ داده‌شده Ùهرست می‌کند +Comment[fi]=Valikko, joka listaa annetun kansion tiedostot +Comment[fr]=Un menu affichant les fichiers d'un dossier donné +Comment[fy]=In menu dat de triemmen út de oantsjutte map sjen lit +Comment[ga]=Roghchlár a thaispeánann na comhaid i bhfillteán +Comment[gl]=Un menu que lista os ficheiros dos seus cartafoles +Comment[he]=תפריט ×©× ×•×ª×Ÿ רשימה של ×§×‘×¦×™× ×”×§×™×™×ž×™× ×‘×ª×™×§×™×™×” מסוימת +Comment[hr]=Izbornik s popisom datoteka unutar dane mape +Comment[hu]=Egy adott könyvtár tartalmát kilistázó menü +Comment[is]=Valmynd sem sýnir skrár à uppgefinni möppu +Comment[it]=Un menu che elenca i file di una data cartella +Comment[ja]=指定ã—ãŸãƒ•ã‚©ãƒ«ãƒ€ã®ãƒ•ã‚¡ã‚¤ãƒ«ã®ãƒªã‚¹ãƒˆã‚’表示ã™ã‚‹ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[kk]=Каталогтағы файлдар тізім мәзірі +Comment[km]=ម៉ឺនុយ​ដែល​រាយ​ឯកសារ​ក្នុង​ážážâ€‹ážŠáŸ‚លបាន​ផ្ážáž›áŸ‹â€‹áž˜áž½áž™ +Comment[lt]=Bylų sÄ…raÅ¡Ä… nurodytame aplanke pateikiantis meniu +Comment[mk]=Мени што ги лиÑта датотеките во дадена папка +Comment[nb]=En meny som viser filene i en bestemt mappe +Comment[nds]=Menü dat de Dateien ut en angeven Orner wiest +Comment[ne]=दिà¤à¤•à¥‹ फोलà¥à¤¡à¤°à¤®à¤¾ फाइलहरू सूचीकृत गरà¥à¤¨à¥‡ मेनॠ+Comment[nl]=Een menu dat de bestanden uit de opgegeven map toont +Comment[nn]=Ein meny som viser filene i ei mappe +Comment[pa]=ਇੱਕ ਮੇਨੂ, ਜੋ ਕਿ ਦਿੱਤੇ ਫੋਲਡਰ ਵਿੱਚ ਫਾਇਲਾਂ ਵਿਖਾ ਸਕਦਾ ਹੈ +Comment[pl]=Menu pokazujÄ…ce pliki w podanym katalogu +Comment[pt]=Um menu que mostra os ficheiros numa dada pasta +Comment[pt_BR]=Um menu que lista arquivos em uma determinada pasta +Comment[ro]=Un meniu care listează fiÈ™ierele dintr-un folder +Comment[ru]=Меню Ñ Ð±Ñ‹Ñтрым выбором файла из указанной папки +Comment[rw]=Ibikubiyemo bitanga urutonde rw'amadosiye mu bubiko butanzwe +Comment[se]=Fállu mii Äájeha fiillaid dihto máhpas +Comment[sk]=Menu, ktoré zobrazà súbory v prieÄinku +Comment[sl]=Meni, ki prikazuje seznam datotek v dani mapi +Comment[sr]=Мени који лиÑта фајлове у датој фаÑцикли +Comment[sr@Latn]=Meni koji lista fajlove u datoj fascikli +Comment[sv]=En meny som listar filer i en given katalog +Comment[th]=เมนูที่à¹à¸ªà¸”งรายà¸à¸²à¸£à¹à¸Ÿà¹‰à¸¡à¸‚à¸à¸‡à¹‚ฟลเดà¸à¸£à¹Œà¸—ี่à¸à¸³à¸«à¸™à¸” +Comment[tr]=Belirlenen bir dizinde dosyaları listeleme menüsü +Comment[tt]=Berär törgäkneñ birem tezmäsen kürsätüçe saylaq +Comment[uk]=Меню, Ñке дає перелік файлів в даній теці +Comment[uz]=KoÊ»rsatilgan jilddagi fayllarning roÊ»yxatini koÊ»rsatuvchi +Comment[uz@cyrillic]=КўрÑатилган жилддаги файлларнинг рўйхатини кўрÑатувчи +Comment[vi]=Má»™t thá»±c Ä‘Æ¡n liệt kê các táºp tin có trong thÆ° mục +Comment[wa]=Ene dressêye ki fwait l' lisse des fitchî dins on ridant d' diné +Comment[zh_CN]=列出给定文件夹ä¸æ–‡ä»¶çš„èœå• +Comment[zh_TW]=列出所é¸è³‡æ–™å¤¾ä¸æª”案的é¸å–® +Icon=kdisknav +X-KDE-Library=BrowserButton diff --git a/kicker/kicker/buttons/browserbutton.cpp b/kicker/kicker/buttons/browserbutton.cpp new file mode 100644 index 000000000..9a445d218 --- /dev/null +++ b/kicker/kicker/buttons/browserbutton.cpp @@ -0,0 +1,147 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtimer.h> +#include <qtooltip.h> +#include <qdragobject.h> + +#include <kconfig.h> +#include <klocale.h> +#include <konq_operations.h> +#include <kfileitem.h> + +#include "kicker.h" +#include "browser_mnu.h" +#include "browser_dlg.h" +#include "global.h" + +#include "browserbutton.h" +#include "browserbutton.moc" + +BrowserButton::BrowserButton( const QString& icon, const QString& startDir, QWidget* parent ) + : PanelPopupButton( parent, "BrowserButton" ) + , topMenu( 0 ) +{ + initialize( icon, startDir ); +} + +BrowserButton::BrowserButton( const KConfigGroup& config, QWidget* parent ) + : PanelPopupButton( parent, "BrowserButton" ) + , topMenu( 0 ) +{ + initialize( config.readEntry("Icon", "kdisknav"), config.readPathEntry("Path") ); +} + +BrowserButton::~BrowserButton() +{ + delete topMenu; +} + +void BrowserButton::initialize( const QString& icon, const QString& path ) +{ + _icon = icon; + + // Don't parent to this, so that the tear of menu is not always-on-top. + topMenu = new PanelBrowserMenu( path ); + setPopup(topMenu); + + _menuTimer = new QTimer( this ); + connect( _menuTimer, SIGNAL(timeout()), SLOT(slotDelayedPopup()) ); + + QToolTip::add(this, i18n("Browse: %1").arg(path)); + setTitle( path ); + setIcon ( _icon ); +} + +void BrowserButton::saveConfig( KConfigGroup& config ) const +{ + config.writeEntry("Icon", _icon); + config.writePathEntry("Path", topMenu->path()); +} + +void BrowserButton::dragEnterEvent( QDragEnterEvent *ev ) +{ + if ((ev->source() != this) && KURLDrag::canDecode(ev)) + { + _menuTimer->start(500, true); + ev->accept(); + } + else + { + ev->ignore(); + } + PanelButton::dragEnterEvent(ev); +} + +void BrowserButton::dragLeaveEvent( QDragLeaveEvent *ev ) +{ + _menuTimer->stop(); + PanelButton::dragLeaveEvent(ev); +} + +void BrowserButton::dropEvent( QDropEvent *ev ) +{ + KURL path ( topMenu->path() ); + _menuTimer->stop(); + KFileItem item( path, QString::fromLatin1( "inode/directory" ), KFileItem::Unknown ); + KonqOperations::doDrop( &item, path, ev, this ); + PanelButton::dropEvent(ev); +} + +void BrowserButton::initPopup() +{ + topMenu->initialize(); +} + +void BrowserButton::slotDelayedPopup() +{ + topMenu->initialize(); + topMenu->popup(KickerLib::popupPosition(popupDirection(), topMenu, this)); + setDown(false); +} + +void BrowserButton::properties() +{ + PanelBrowserDialog dlg( topMenu->path(), _icon, this ); + + if( dlg.exec() == QDialog::Accepted ){ + _icon = dlg.icon(); + QString path = dlg.path(); + + if ( path != topMenu->path() ) { + delete topMenu; + topMenu = new PanelBrowserMenu( path, this ); + setPopup( topMenu ); + setTitle( path ); + } + setIcon( _icon ); + emit requestSave(); + } +} + +void BrowserButton::startDrag() +{ + KURL url(topMenu->path()); + emit dragme(KURL::List(url), labelIcon()); +} + diff --git a/kicker/kicker/buttons/browserbutton.h b/kicker/kicker/buttons/browserbutton.h new file mode 100644 index 000000000..00ff0abea --- /dev/null +++ b/kicker/kicker/buttons/browserbutton.h @@ -0,0 +1,66 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __browserbutton_h__ +#define __browserbutton_h__ + +#include "panelbutton.h" + +class PanelBrowserMenu; + +/** + * Button that contains a Browser directory menu + */ +class BrowserButton : public PanelPopupButton +{ + Q_OBJECT + +public: + BrowserButton( const QString& icon, const QString& startDir, QWidget* parent ); + BrowserButton( const KConfigGroup& config, QWidget* parent ); + virtual ~BrowserButton(); + + void saveConfig( KConfigGroup& config ) const; + + virtual void properties(); + +protected slots: + virtual void slotDelayedPopup(); + virtual void startDrag(); + +protected: + void initialize( const QString& icon, const QString& startDir ); + virtual QString tileName() { return "Browser"; } + virtual void initPopup(); + virtual void dropEvent(QDropEvent *ev); + virtual void dragEnterEvent(QDragEnterEvent *ev); + virtual void dragLeaveEvent(QDragLeaveEvent *ev); + virtual QString defaultIcon() const { return "kdisknav"; }; + + PanelBrowserMenu* topMenu; + QString _icon; + QTimer *_menuTimer; +}; + +#endif + diff --git a/kicker/kicker/buttons/desktop.desktop b/kicker/kicker/buttons/desktop.desktop new file mode 100644 index 000000000..f9ccbc81d --- /dev/null +++ b/kicker/kicker/buttons/desktop.desktop @@ -0,0 +1,129 @@ +[Desktop Entry] +Name=Show Desktop +Name[af]=Vertoon Werkskerm +Name[ar]=أعرض Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ +Name[be]=Паказаць працоўны Ñтол +Name[bg]=Показване на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ð»Ð¾Ñ‚ +Name[bn]=ডেসà§à¦•à¦Ÿà¦ª দেখাও +Name[br]=Diskouez ar burev +Name[bs]=Prikaži desktop +Name[ca]=Mostra l'escriptori +Name[cs]=Zobrazit plochu +Name[csb]=Pòkôże pùlt +Name[da]=Vis desktop +Name[de]=Zugriff auf Arbeitsfläche +Name[el]=Εμφάνιση επιφάνειας εÏγασίας +Name[eo]=Montri Tabulon +Name[es]=Mostrar escritorio +Name[et]=Näita töölauda +Name[eu]=Erakutsi mahaigaina +Name[fa]=نمایش رومیزی +Name[fi]=Näytä työpöytä +Name[fr]=Afficher le bureau +Name[fy]=Buroblêd sjen litte +Name[ga]=Taispeáin an Deasc +Name[gl]=Escritório +Name[he]=הצג שולחן עבודה +Name[hr]=Prikaži radnu povrÅ¡inu +Name[hu]=A munkaasztal megjelenÃtése +Name[is]=Sýna skjáborð +Name[it]=Mostra il desktop +Name[ja]=デスクトップを表示 +Name[ka]=სáƒáƒ›áƒ£áƒ¨áƒáƒ დáƒáƒ¤áƒ˜áƒ¡ ჩვენებრ+Name[kk]=Ò®Ñтелге ауыÑу +Name[km]=បង្ហាញ​ផ្ទៃážáž» +Name[ko]=ë°ìŠ¤í¬í†± 1ë¡œ 바꾸기 +Name[lt]=Rodyti darbastalį +Name[mk]=Прикажи работна површина +Name[nb]=Vis skrivebord +Name[nds]=Schriefdischwieser +Name[ne]=डेसà¥à¤•à¤Ÿà¤ª देखाउनà¥à¤¹à¥‹à¤¸à¥ +Name[nl]=Bureaublad tonen +Name[nn]=Vis skrivebord +Name[pa]=ਵੇਹੜਾ ਵੇਖਾਓ +Name[pl]=Pokaż pulpit +Name[pt]=Mostrar o Ecrã +Name[pt_BR]=Mostrar Ãrea de Trabalho +Name[ro]=Arată desktop +Name[ru]=Свернуть вÑе окна +Name[rw]=Kwerekana Ibiro +Name[se]=Čájet Äállinbeavddi +Name[sk]=Ukáže pracovnú plochu +Name[sl]=Prikaži namizje +Name[sr]=Прикажи радну површину +Name[sr@Latn]=Prikaži radnu povrÅ¡inu +Name[sv]=Visa skrivbord +Name[te]=à°°à°‚à°—à°¸à±à°¥à°²à°¾à°¨à±à°¨à°¿ చూపౠ+Name[tg]=Ðамоиши мизи корӣ +Name[th]=à¹à¸ªà¸”งพื้นที่หน้าจภ+Name[tr]=Masaüstünü Göster +Name[tt]=Östäl Kürsätü +Name[uk]=Показати Ñтільницю +Name[uz]=Ish stoli +Name[uz@cyrillic]=Иш Ñтоли +Name[vi]=Hiển thị Mà n hình ná»n +Name[wa]=Mostrer l' sicribanne +Name[zh_CN]=æ˜¾ç¤ºæ¡Œé¢ +Name[zh_TW]=é¡¯ç¤ºæ¡Œé¢ +Comment=A button that gives quick access to the desktop when pressed +Comment[af]='n Knoppie wat vinnige toegang tot die werkskerm gee wanneer dit gedruk word +Comment[ar]=زرّ ÙŠØ³Ù…Ø Ø¨Ø§Ù„ÙˆØµÙˆÙ„ السريع إلى Ø³Ø·Ø Ø§Ù„Ù…ÙƒØªØ¨ عند ضغطه +Comment[be]=Кнопка, ÑÐºÐ°Ñ Ð´Ð°Ðµ хуткі доÑтуп да працоўнага Ñтала +Comment[bg]=Бутон за бърз доÑтъп до Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ð»Ð¾Ñ‚ +Comment[bn]=à¦à¦•à¦Ÿà¦¾ বাটন যেটি চাপলে ডেসà§à¦•à¦Ÿà¦ª ফাà¦à¦•à¦¾ করে দেখানো হবে +Comment[bs]=Dugme koje sklanja sve prozore sa ekrana i prikazuje desktop +Comment[ca]=Un botó que dóna accés rà pid a l'escriptori en prémer-hi +Comment[cs]=TlaÄÃtko s rychlým pÅ™Ãstupem k pracovnà ploÅ¡e +Comment[csb]=KnÄ…pa chùtczégò przistãpù do pùltu +Comment[da]=En knap der giver hurtig adgang til desktoppen nÃ¥r den trykkes ned +Comment[de]=Dieser Knopf ermöglicht den schnellen Zugriff auf die Arbeitsfläche +Comment[el]=Ένα κουμπί που όταν πατηθεί δίνει γÏήγοÏη Ï€Ïόσβαση στην επιφάνεια εÏγασίας +Comment[eo]=Butono kiu ebligas rapid aliron al labortabulo kiam premita +Comment[es]=Muestra rápidamente el escritorio al pulsarlo +Comment[et]=Nupp, mis võimaldab ühe klõpsuga kiiresti pääseda otse töölauale +Comment[eu]=Zapatzean mahagainera sarbide bizkorra ematen duen botoia +Comment[fa]=دکمه‌ای Ú©Ù‡ وقتی Ùشار داده ‌شد، امکان دستیابی سریع به رومیزی را می‌دهد. +Comment[fi]=Painike, jota painamalla pääsee nopeasti työpöydälle +Comment[fr]=Un bouton, qui, en étant cliqué, donne un accès rapide au bureau +Comment[fy]=In knop hokker flugge tagong ta it buroblêd jout +Comment[gl]=Un botón que dá aceso rápido ao escritório cando se preme +Comment[he]=כפתור ×”× ×•×ª×Ÿ גישה מהירה לשולחן העבודה ×›×שר × ×œ×—×¥ +Comment[hr]=Gumb koji omogućuje brz pristup radnoj povrÅ¡ini +Comment[hu]=Ezzel a gombbal gyorsan elérhetÅ‘ a munkaasztal +Comment[is]=Hnappur sem veitir hraðan aðgang að skjáborðinu +Comment[it]=Un pulsante che da accesso rapido al desktop quando viene premuto +Comment[ja]=デスクトップã«ç´ æ—©ãアクセスã™ã‚‹ãŸã‚ã®ãƒœã‚¿ãƒ³ +Comment[kk]=Бір баÑып Ò¯Ñтелге қатынау батырмаÑÑ‹ +Comment[km]=ប៊ូážáž»áž„​ដែល​ផ្ážáž›áŸ‹â€‹áž€áž¶ážšâ€‹áž…ូល​ដំណើរការ​រហáŸážŸáž‘ៅ​ផ្ទៃážáž» áž–áŸáž›â€‹áž…ុច +Comment[lt]=Mygtukas, kurį nuspaudus suteikiama greita prieiga prie darbastalio +Comment[mk]=Копче што дава брз приÑтап кон работната површина кога е притиÑнато +Comment[nb]=En knapp som gir deg rask tilgang til skrivebordet +Comment[nds]=Disse Knoop laat Een direktemang op den Schriefdisch togriepen +Comment[ne]=थिचेको बेलामा डेसà¥à¤•à¤Ÿà¤ªà¤®à¤¾ दà¥à¤°à¥à¤¤ पहà¥à¤à¤š पà¥à¤°à¤¦à¤¾à¤¨ गरà¥à¤¨à¥‡ बटन +Comment[nl]=Een knop die snelle toegang tot het bureaublad geeft +Comment[nn]=Ein knapp som gir deg rask tilgang til skrivebordet +Comment[pa]=ਇੱਕ ਬਟਨ, ਜੋ ਕਿ ਦਬਾਉਣ ਉਪਰੰਤ ਤà©à¨¹à¨¾à¨¨à©‚ ਵੇਹੜਾ ਉਪਲੱਬਧ ਕਰਵਾਉਦਾ ਹੈ +Comment[pl]=Przycisk szybkiego dostÄ™pu do pulpitu +Comment[pt]=Um botão que dá acesso rápido ao ecrã, quando for carregado +Comment[pt_BR]=Um botão que fornece acesso rápido para a área de trabalho, quando pressionado +Comment[ro]=Un buton care permite acces rapid la desktop la apăsare +Comment[ru]=Кнопка перехода на заданный рабочий Ñтол +Comment[rw]=Buto itanga ukugera vuba ku biro igihe ikanzwe +Comment[se]=Boallu mii Äiehká buot lásiid mat leat Äállinbeavddis go dan coahkkala +Comment[sk]=TlaÄidlo pre rýchly prÃstup na pracovnú plochu +Comment[sl]=Klik tega gumba omogoÄa hiter dostop do namizja +Comment[sr]=Дугме које по притиÑку даје брз приÑтуп радној површини +Comment[sr@Latn]=Dugme koje po pritisku daje brz pristup radnoj povrÅ¡ini +Comment[sv]=En knapp som ger snabb Ã¥tkomst till skrivbordet när den klickas +Comment[th]=ปุ่มที่à¸à¸”à¹à¸¥à¹‰à¸§à¸ˆà¸°à¹à¸ªà¸”งพื้นที่หน้าจà¸à¸à¸¢à¹ˆà¸²à¸‡à¸£à¸§à¸”เร็ว +Comment[tr]=Tıklandığı zaman masaüstüne hızlı eriÅŸim saÄŸlar +Comment[tt]=Östäl eçtälegenä tiz ireÅŸergä birüçe töymä +Comment[uk]=Кнопка, Ñка при натиÑканні надає швидкий доÑтуп до Ñтільниці +Comment[uz]=Ish stoliga qisqa yoÊ»l +Comment[uz@cyrillic]=Иш Ñтолига қиÑқа йўл +Comment[vi]=Má»™t nút cho phép bạn truy cáºp ngay đến mà n hình ná»n má»—i khi ấn và o +Comment[wa]=On boton ki dene raddimint accès Ã¥ scribanne cwand il est tchôkî +Comment[zh_CN]=按下å¯å¿«é€Ÿè®¿é—®æ¡Œé¢çš„按钮 +Comment[zh_TW]=按下去能快速顯示桌é¢çš„按鈕 +Icon=desktop +X-KDE-Library=DesktopButton diff --git a/kicker/kicker/buttons/desktopbutton.cpp b/kicker/kicker/buttons/desktopbutton.cpp new file mode 100644 index 000000000..3831303d7 --- /dev/null +++ b/kicker/kicker/buttons/desktopbutton.cpp @@ -0,0 +1,84 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> +#include <qdragobject.h> + +#include <klocale.h> +#include <kglobalsettings.h> +#include <konq_operations.h> +#include <kfileitem.h> + +#include "showdesktop.h" +#include "kicker.h" +#include "kickerSettings.h" + +#include "desktopbutton.h" +#include "desktopbutton.moc" + +DesktopButton::DesktopButton( QWidget* parent ) + : PanelButton( parent, "DesktopButton" ) +{ + setToggleButton(true); + + QToolTip::add(this, i18n("Show desktop")); + setTitle(i18n("Desktop Access")); + setIcon("desktop"); + + connect( this, SIGNAL(toggled(bool)), this, SLOT(showDesktop(bool)) ); + connect( ShowDesktop::the(), SIGNAL(desktopShown(bool)), this, SLOT(toggle(bool)) ); + + setOn( ShowDesktop::the()->desktopShowing() ); +} + +void DesktopButton::toggle(bool showDesktop) +{ + KickerTip::enableTipping(false); + setOn(showDesktop); + KickerTip::enableTipping(true); +} + +void DesktopButton::showDesktop(bool showDesktop) +{ + KickerTip::enableTipping(false); + ShowDesktop::the()->showDesktop(showDesktop); + KickerTip::enableTipping(true); +} + +void DesktopButton::dragEnterEvent( QDragEnterEvent *ev ) +{ + if ((ev->source() != this) && KURLDrag::canDecode(ev)) + ev->accept(rect()); + else + ev->ignore(rect()); + PanelButton::dragEnterEvent(ev); +} + +void DesktopButton::dropEvent( QDropEvent *ev ) +{ + KURL dPath ( KGlobalSettings::desktopPath() ); + KFileItem item( dPath, QString::fromLatin1( "inode/directory" ), KFileItem::Unknown ); + KonqOperations::doDrop( &item, dPath, ev, this ); + PanelButton::dropEvent(ev); +} + diff --git a/kicker/kicker/buttons/desktopbutton.h b/kicker/kicker/buttons/desktopbutton.h new file mode 100644 index 000000000..62de4c342 --- /dev/null +++ b/kicker/kicker/buttons/desktopbutton.h @@ -0,0 +1,49 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __desktopbutton_h__ +#define __desktopbutton_h__ + +#include "panelbutton.h" + +/** + * Button that shows the deskop + */ +class DesktopButton : public PanelButton +{ + Q_OBJECT + +public: + DesktopButton( QWidget* parent ); + +protected: + virtual QString tileName() { return "DesktopButton"; } + virtual void dragEnterEvent(QDragEnterEvent *ev); + virtual void dropEvent(QDropEvent *ev); + +protected slots: + void toggle(bool); + void showDesktop(bool); +}; + +#endif diff --git a/kicker/kicker/buttons/exec.desktop b/kicker/kicker/buttons/exec.desktop new file mode 100644 index 000000000..ab30698f3 --- /dev/null +++ b/kicker/kicker/buttons/exec.desktop @@ -0,0 +1,125 @@ +[Desktop Entry] +Name=Non-KDE Application Launcher +Name[af]=Nie-KDE Program Lanseerder +Name[ar]=Ù…ÙطلÙÙ‚ التطبيقات اغير KDE +Name[be]=ЗапуÑкальнік праграмы не-KDE +Name[bg]=Стартиране на програми +Name[bn]=নন-কে.ডি.ই অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨ লঞà§à¦šà¦¾à¦° +Name[bs]=PokretaÄ ne-KDE programa +Name[ca]=Engegador d'aplicacions no KDE +Name[cs]=SpouÅ¡tÄ›Ä aplikacà nepatÅ™ÃcÃch do KDE +Name[csb]=Zrëszanié programów z bùtna KDE +Name[da]=Starter ikke-KDE-programmer +Name[de]=Nicht-KDE-Programm +Name[el]=Εκτελεστής μη-KDE εφαÏμογών +Name[eo]=neKDE-a Aplikaĵolanĉilo +Name[es]=Aplicaciones No-KDE +Name[et]=KDE-väliste rakenduste käivitaja +Name[eu]=KDEren ez diren aplikazio abiarazlea +Name[fa]=راه‌انداز کاربرد غیر KDE +Name[fi]=Ei-KDE:n sovellusten käynnistäjä +Name[fr]=Lancement des applications non KDE +Name[fy]=Net-KDE-programma's útfierder +Name[ga]=Tosaitheoir Feidhmchlár Neamh-KDE +Name[gl]=Lanzador de Aplicacións Non-KDE +Name[he]=מפעיל ×ª×•×›× ×™×•×ª ×©×œ× ×©×™×™×›×•×ª למשפחת KDE +Name[hr]=PokretaÄ vanjskih KDE aplikacija +Name[hu]=ProgramindÃtó nem KDE-s alkalmazásokhoz +Name[is]=Ræsir fyrir ekki-KDE forrit +Name[it]=Lancio di applicazioni non-KDE +Name[ja]=KDE 以外ã®ã‚¢ãƒ—リケーションランãƒãƒ£ãƒ¼ +Name[ka]=áƒáƒ რKDE-ს პრáƒáƒ’რáƒáƒ›áƒ”ბის +Name[kk]=KDE-ге тиеÑілі ÐµÐ¼ÐµÑ Ò›Ð¾Ð»Ð´Ð°Ð½Ð±Ð°Ð»Ð°Ñ€Ð´Ñ‹ жегу +Name[km]=ឧបករណáŸâ€‹áž”ើក​កម្មវិធី​មិន​មែន KDE +Name[ko]=프로그램 실행기 +Name[lt]=Ne-KDE programų startavimo priedas +Name[mk]=Стартувач на не-KDE апликации +Name[nb]=Last ikke-KDE-programmer +Name[nds]=Starter för Nich-KDE-Programmen +Name[ne]=KDE बाहेकको अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤— सà¥à¤°à¥à¤†à¤¤à¤•à¤°à¥à¤¤à¤¾ +Name[nl]=Niet-KDE-programma's starten +Name[nn]=Start av ikkje-KDE-program +Name[pa]=ਨਾ-KDE ਕਾਰਜ ਸ਼à©à¨°à©‚ਆਤੀ +Name[pl]=Uruchamianie programów spoza KDE +Name[pt]=Lançador de Aplicações não-KDE +Name[pt_BR]=Lançador de aplicativos que não são do KDE +Name[ro]=Lansator de aplicaÈ›ii Non-KDE +Name[ru]=ЗапуÑк Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ из KDE +Name[rw]=Bitari-KDE Porogaramu Mutangiza +Name[se]=Ii-KDE prográmmaid álggaheaddji +Name[sk]=SpúšťaÄ non-KDE aplikácià +Name[sl]=Zaganjalnik ne-KDE programov +Name[sr]=Покретач не-KDE програма +Name[sr@Latn]=PokretaÄ ne-KDE programa +Name[sv]=Start av program som inte hör till KDE +Name[th]=ตัวเรียà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸à¸žà¸žà¸¥à¸´à¹€à¸„ชันที่ไม่ใช่ขà¸à¸‡ KDE +Name[tr]=KDE Dışı Uygulama BaÅŸlatıcısı +Name[tt]=KDE-bulmaÄŸan Yazılım Cibärgeç +Name[uk]=ЗапуÑк не-KDE програм +Name[uz]=No-KDE dasturlarni ishga tushuruvchi +Name[uz@cyrillic]=Ðо-KDE даÑтурларни ишга тушурувчи +Name[vi]=Trình khởi Ä‘á»™ng ChÆ°Æ¡ng trình không của KDE +Name[wa]=Enondeu di programes nén KDE +Name[zh_CN]=éž KDE 应用程åºå¯åŠ¨å™¨ +Name[zh_TW]=éž-KDE 應用程å¼å•Ÿå‹•å™¨ +Comment=A launcher for programs not in the K Menu +Comment[af]='n Lanseerder vir programme wat nie in die K-Kieslys voorkom nie +Comment[ar]=Ù…ÙطلÙÙ‚ البرامج غير التابعة Ù„Ùلقائمة K +Comment[be]=ЗапуÑкальнік Ð´Ð»Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹, Ñкой нÑма Ñž меню KDE +Comment[bg]=Стартиране на програми, които Ñа извън главното меню (К) +Comment[bn]=কে-মেনà§-তে নেই à¦à¦®à¦¨ পà§à¦°à§‹à¦—à§à¦°à¦¾à¦®-à¦à¦° চালৠকরার জনà§à¦¯ à¦à¦•à¦Ÿà¦¿ লঞà§à¦šà¦¾à¦° +Comment[bs]=PokretaÄ programa koji nisu u K meniju +Comment[ca]=Un engegador de programes que no hi són al menú K +Comment[cs]=SpouÅ¡tÄ›Ä pro programy nenacházejÃcà se v hlavnà nabÃdce KDE +Comment[csb]=Zrëszanié programów, jaczich nie dô w K menu +Comment[da]=En starter af programmer der ikke er i K-Menuen +Comment[de]=Startet Programme, die sich nicht im K-Menü befinden +Comment[el]=Ένας εκτελεστής εφαÏμογών που δε βÏίσκονται στο ÎœÎµÎ½Î¿Ï K +Comment[eo]=Lanĉilo por programoj ne en la K Menuo +Comment[es]=Le permite ejecutar aplicaciones que no están en el Menu K +Comment[et]=K menüüst puuduvate rakenduste käivitaja +Comment[eu]=K Menuan ez dauden aplikazio abiarazlea +Comment[fa]=یک راه‌انداز برای برای برنامه‌هایی Ú©Ù‡ در گزینگان K نیست +Comment[fi]=Käynnistäjä ohjelmille, jotka eivät ole K-valikossa +Comment[fr]=Lancement des programmes n'étant pas dans le menu K +Comment[fy]=In útfierder foar programma's hokker net yn it K-menu stean +Comment[gl]=Un lanzador para aplicacións que non estexan no Menu de KDE +Comment[he]=מפעיל עבור ×™×™×©×•×ž×™× ×©×œ× ×‘×ª×¤×¨×™×˜ המערכת +Comment[hr]=PokretaÄ programa koji se ne nalaze na KDE izborniku +Comment[hu]=ProgramindÃtó +Comment[is]=Ræsir fyrir forrit sem eru ekki à K valmyndinni +Comment[it]=Per lanciare programmi che non sono nel menu K +Comment[ja]=K メニューã«ãªã„プãƒã‚°ãƒ©ãƒ ã‚’èµ·å‹• +Comment[kk]=KDE мәзрінде жоқ бағдарламаларды жегу +Comment[km]=ឧបករណáŸâ€‹áž”ើក​កម្មវិធី​ដែល​មិន​នៅ​ក្នុង​ម៉ឺនុយ K +Comment[lt]=K meniu nesanÄių programų startavimo meniu +Comment[mk]=Стартување на програми што не Ñе во К-менито +Comment[nb]=Mulighet til Ã¥ starte programmer som ikke er i KDE-menyen +Comment[nds]=En Starter för Programmen, de nich in't K-Menü staht +Comment[ne]=के मेनà¥à¤®à¤¾ नà¤à¤à¤•à¤¾ कारà¥à¤¯à¤•à¥à¤°à¤®à¤•à¤¾ लागि सà¥à¤°à¥à¤†à¤¤à¤•à¤°à¥à¤¤à¤¾ +Comment[nl]=Een starter voor het uitvoeren van programma's die niet in het K-menu staan +Comment[nn]=Start av program som ikkje ligg i K-menyen +Comment[pa]= ਕੇ(K) ਮੇਨੂ ਵਿੱਚ ਨਾ-ਮੌਜੂਦ ਕਾਰਜ ਲਈ ਸ਼à©à¨°à©‚ਆਤੀ ਹੈ +Comment[pl]=Uruchamianie programów, które nie znajdujÄ… siÄ™ w menu K +Comment[pt]=Um lançador de programas que não estejam no Menu K +Comment[pt_BR]=Um lançador para programas que não estão no Menu K +Comment[ro]=Lansator de programe ce nu se află în meniul K +Comment[ru]=ЗапуÑк приложений, не входÑщих в меню KDE +Comment[rw]=Mutangiza w'amaporogaramu atari muri K Ibikubiyemo +Comment[sk]=SpúštaÄ programov, ktoré nie sú v KDE Menu +Comment[sl]=Zaganjalnik programov, ki se ne nahajajo v meniju KDE-ja +Comment[sr]=Покретач за програме којих нема у K-менију +Comment[sr@Latn]=PokretaÄ za programe kojih nema u K-meniju +Comment[sv]=Start av program som inte finns i K-menyn +Comment[th]=ตัวเรียà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹‚ปรà¹à¸à¸£à¸¡à¸—ี่ไม่ได้à¸à¸¢à¸¹à¹ˆà¹ƒà¸™ K menu +Comment[tr]=KDE menüsünde bulunmayan programlar için bir baÅŸlatıcı +Comment[tt]=K-Saylaqta bulmaÄŸan yazılımnar cibärgeçe +Comment[uk]=ЗапуÑк програм, Ñких немає в K Меню +Comment[uz]=K-menyuga qoÊ»shilmagan dasturlarni ishga tushirish +Comment[uz@cyrillic]=К-менюга қўшилмаган даÑтурларни ишга тушириш +Comment[vi]=Trình khởi Ä‘á»™ng các chÆ°Æ¡ng trình không có trong thá»±c Ä‘Æ¡n của KDE +Comment[wa]=On enondeu po les programes ki n' sont nén dins l' dressêye K +Comment[zh_CN]=å¯åŠ¨ä¸åœ¨ K èœå•ä¸çš„ç¨‹åº +Comment[zh_TW]=用於ä¸åœ¨ K é¸å–®ä¸çš„程å¼å•Ÿå‹•å™¨ +Icon=exec +X-KDE-Library=ExecButton diff --git a/kicker/kicker/buttons/extensionbutton.cpp b/kicker/kicker/buttons/extensionbutton.cpp new file mode 100644 index 000000000..004e0d47b --- /dev/null +++ b/kicker/kicker/buttons/extensionbutton.cpp @@ -0,0 +1,79 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> + +#include <kconfig.h> +#include <kpanelmenu.h> + +#include "menuinfo.h" + +#include "extensionbutton.h" +#include "extensionbutton.moc" + +ExtensionButton::ExtensionButton( const QString& desktopFile, QWidget* parent ) + : PanelPopupButton( parent, "ExtensionButton" ) + , info( 0 ) + , menu( 0 ) +{ + initialize( desktopFile ); +} + +ExtensionButton::ExtensionButton( const KConfigGroup& config, QWidget* parent ) + : PanelPopupButton( parent, "extensionbuttton" ) +{ + initialize( config.readPathEntry("DesktopFile") ); +} + +void ExtensionButton::initialize( const QString& desktopFile ) +{ + info = new MenuInfo(desktopFile); + if (!info->isValid()) + { + m_valid = false; + return; + } + menu = info->load(this); + setPopup(menu); + + QToolTip::add(this, info->comment()); + setTitle(info->name()); + setIcon(info->icon()); +} + +ExtensionButton::~ExtensionButton() +{ + delete info; +} + +void ExtensionButton::saveConfig( KConfigGroup& config ) const +{ + config.writePathEntry("DesktopFile", info->desktopFile()); +} + +void ExtensionButton::initPopup() +{ + if( !menu->initialized() ) { + menu->reinitialize(); + } +} diff --git a/kicker/kicker/buttons/extensionbutton.h b/kicker/kicker/buttons/extensionbutton.h new file mode 100644 index 000000000..0d489f706 --- /dev/null +++ b/kicker/kicker/buttons/extensionbutton.h @@ -0,0 +1,52 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __extensionbutton_h__ +#define __extensionbutton_h__ + +#include "panelbutton.h" + +class MenuInfo; +class KPanelMenu; + +class ExtensionButton : public PanelPopupButton +{ + Q_OBJECT + +public: + ExtensionButton( const QString& desktopFile, QWidget* parent ); + ExtensionButton( const KConfigGroup& config, QWidget* parent ); + ~ExtensionButton(); + + void saveConfig( KConfigGroup& config ) const; + +protected: + void initialize( const QString& desktopFile ); + virtual QString tileName() { return "URL"; } + virtual void initPopup(); + + MenuInfo* info; + KPanelMenu* menu; +}; + +#endif diff --git a/kicker/kicker/buttons/kbutton.cpp b/kicker/kicker/buttons/kbutton.cpp new file mode 100644 index 000000000..071d15981 --- /dev/null +++ b/kicker/kicker/buttons/kbutton.cpp @@ -0,0 +1,78 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> + +#include <klocale.h> +#include <kapplication.h> +#include <kdebug.h> + +#include "kickerSettings.h" + +#include "config.h" + +#include "menumanager.h" +#include "k_mnu.h" + +#include "kbutton.h" +#include "kbutton.moc" + +KButton::KButton( QWidget* parent ) + : PanelPopupButton( parent, "KButton" ) +{ + QToolTip::add(this, i18n("Applications, tasks and desktop sessions")); + setTitle(i18n("K Menu")); + + setPopup(MenuManager::the()->kmenu()); + MenuManager::the()->registerKButton(this); + setIcon("kmenu"); + + if (KickerSettings::showKMenuText()) + { + setButtonText(KickerSettings::kMenuText()); + setFont(KickerSettings::buttonFont()); + setTextColor(KickerSettings::buttonTextColor()); + } +} + +KButton::~KButton() +{ + MenuManager::the()->unregisterKButton(this); +} + +void KButton::properties() +{ + KApplication::startServiceByDesktopName("kmenuedit", QStringList(), + 0, 0, 0, "", true); +} + +void KButton::initPopup() +{ +// kdDebug(1210) << "KButton::initPopup()" << endl; + + // this hack is required to ensure the correct popup position + // when the size of the recent application part of the menu changes + // please don't remove this _again_ + MenuManager::the()->kmenu()->initialize(); +} + diff --git a/kicker/kicker/buttons/kbutton.h b/kicker/kicker/buttons/kbutton.h new file mode 100644 index 000000000..6de61181f --- /dev/null +++ b/kicker/kicker/buttons/kbutton.h @@ -0,0 +1,50 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __kbutton_h__ +#define __kbutton_h__ + +#include "panelbutton.h" + +/** + * Button that contains the PanelKMenu and client menu manager. + */ +class KButton : public PanelPopupButton +{ + Q_OBJECT + +public: + KButton( QWidget *parent ); + ~KButton(); + + void loadConfig( const KConfigGroup& config ); + + virtual void properties(); + +protected: + virtual QString tileName() { return "KMenu"; } + virtual void initPopup(); + virtual QString defaultIcon() const { return "go"; } +}; + +#endif diff --git a/kicker/kicker/buttons/kmenu.desktop b/kicker/kicker/buttons/kmenu.desktop new file mode 100644 index 000000000..be9a0aa68 --- /dev/null +++ b/kicker/kicker/buttons/kmenu.desktop @@ -0,0 +1,132 @@ +[Desktop Entry] +Name=K Menu +Name[af]=K-Kieslys +Name[ar]=قائمة K +Name[be]=Меню KDE +Name[bg]=Главно меню +Name[bn]=কে মেনৠ+Name[br]=Meuziad K +Name[bs]=K meni +Name[ca]=Menú K +Name[cs]=NabÃdka KDE +Name[cy]=Y Ddewislen K +Name[da]=K-Menu +Name[de]=K-Menü +Name[el]=ÎœÎµÎ½Î¿Ï K +Name[eo]=KDEa Menuo +Name[es]=Menú de KDE +Name[et]=K menüü +Name[eu]=K menua +Name[fa]=گزینگان K +Name[fi]=K-valikko +Name[fr]=Menu K +Name[fy]=K-menu +Name[ga]=Roghchlár K +Name[gl]=Menu de KDE +Name[he]=תפריט K +Name[hr]=KDE izbornik +Name[hu]=KDE menü +Name[is]=K valmynd +Name[it]=Menu K +Name[ja]=K メニュー +Name[ka]=K მენიუ +Name[kk]=K мәзірі +Name[km]=ម៉ឺនុយ K +Name[ko]=KDE 메뉴 +Name[lt]=K meniu +Name[mk]=К-мени +Name[nb]=KDE-meny +Name[nds]=K-Menü +Name[ne]=के मेनॠ+Name[nl]=K-menu +Name[nn]=K-meny +Name[pa]=K ਮੇਨੂ +Name[pl]=Menu K +Name[pt]=Menu K +Name[pt_BR]=Menu K +Name[ro]=Meniu K +Name[ru]=Меню KDE +Name[rw]=K Ibikubiyemo +Name[se]=K-fállu +Name[sk]=Menu KDE +Name[sl]=Meni KDE-ja +Name[sr]=K-мени +Name[sr@Latn]=K-meni +Name[sv]=K-meny +Name[te]=కె పటà±à°Ÿà°¿ +Name[tg]=Менюи KDE +Name[th]=เมนู KDE +Name[tr]=KDE Menüsü +Name[tt]=K-Saylaq +Name[uk]=K Меню +Name[uz]=K-menyu +Name[uz@cyrillic]=К-меню +Name[vi]=Thá»±c Ä‘Æ¡n KDE +Name[wa]=Dressêye K +Name[zh_CN]=K èœå• +Name[zh_TW]=K é¸å–® +Comment=Applications and common actions +Comment[af]=Programme en algemene aksies +Comment[ar]=تطبيقات Ùˆ أعمال شائعة +Comment[be]=Праграмы Ñ– аÑÐ½Ð¾ÑžÐ½Ñ‹Ñ Ð´Ð·ÐµÑнні +Comment[bg]=Главното меню Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸Ñ‚Ðµ, ÑиÑтемните наÑтройки и вÑичко оÑтанало +Comment[bn]=অà§à¦¯à¦¾à¦ªà¦²à¦¿à¦•à§‡à¦¶à¦¨ à¦à¦¬à¦‚ সাধারণ কà§à¦°à¦¿à§Ÿà¦¾à¦¸à¦®à§‚হ +Comment[bs]=Programi i standardne akcije +Comment[ca]=Aplicacions i accions comunes +Comment[cs]=Aplikace a Äasté Äinnosti +Comment[csb]=Programë ë pòpùlarné dzejania +Comment[da]=Programmer og sædvanlige handlinger +Comment[de]=Enthält Programme und häufig verwendete Aktionen +Comment[el]=ΕφαÏμογÎÏ‚ και τυπικÎÏ‚ ενÎÏγειες +Comment[eo]=Aplikaĵoj kaj komunaj agoj +Comment[es]=Aplicaciones y acciones comunes +Comment[et]=Rakendused ja levinumad toimingud +Comment[eu]=Aplikazioak eta ohiko ekintzak +Comment[fa]=کاربردها Ùˆ کنشهای مشترک +Comment[fi]=Sovellukset ja yleiset toiminnot +Comment[fr]=Applications et actions communes +Comment[fy]=Applikaasjes en folle foarkommende aksjes +Comment[ga]=Feidhmchláir agus gnÃomhartha coitianta +Comment[gl]=Aplicacións e accións comuns +Comment[he]=×™×™×©×•×ž×™× ×•×¤×¢×•×œ×•×ª ×ž×–×“×ž× ×•×ª +Comment[hr]=Aplikacije i zajedniÄke aktivnosti +Comment[hu]=Alkalmazások és általános műveletek +Comment[is]=Forrit og algengar aðgerðir +Comment[it]=Applicazioni e azioni comuni +Comment[ja]=アプリケーションã¨ä¸€èˆ¬çš„ãªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=პრáƒáƒ’რáƒáƒ›áƒ”ბი დრსáƒáƒ–áƒáƒ’áƒáƒ“რქმედებები +Comment[kk]=Қолданбалар мен жалпы амалдар +Comment[km]=កម្មវិធី និង​អំពើ​ទូទៅ +Comment[lt]=Programos ir įprasti veiksmai +Comment[mk]=Ðпликации и општи дејÑтва +Comment[nb]=Programmer og vanlige handlinger +Comment[nds]=Programmen un allgemeen Akschonen +Comment[ne]=अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤— र साà¤à¤¾ कारà¥à¤¯ +Comment[nl]=Programma's en veelvoorkomende acties +Comment[nn]=Program og vanlege handlingar +Comment[pa]=ਕਾਰਜ ਅਤੇ ਆਮ ਕਾਰਵਾਈਆਂ +Comment[pl]=Programy i popularne czynnoÅ›ci +Comment[pt]=Aplicações e acções comuns +Comment[pt_BR]=Aplicativos e ações comuns +Comment[ro]=AplicaÈ›ii È™i acÈ›iuni uzuale +Comment[ru]=ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ дейÑÑ‚Ð²Ð¸Ñ +Comment[rw]=Porogaramu n'ibikorwa rusange +Comment[se]=Prográmmat ja dábálaÅ¡ doaimmat +Comment[sk]=Programy a vÅ¡eobecné akcie +Comment[sl]=KDE-jev meni s programi in pogostimi dejanji +Comment[sr]=Програми и уобичајене акције +Comment[sr@Latn]=Programi i uobiÄajene akcije +Comment[sv]=Program och vanliga Ã¥tgärder +Comment[tg]=Барномаҳо ва амалҳои умумӣ +Comment[th]=à¹à¸à¸žà¸žà¸¥à¸´à¹€à¸„ชั่น à¹à¸¥à¸°à¸à¸²à¸£à¸à¸£à¸°à¸—ำทั่วๆไป +Comment[tr]=Uygulamalar ve ortak eylemler +Comment[tt]=Yazılımnar belän töp ğämällär +Comment[uk]=Програми Ñ– загальні дії +Comment[uz]=Dasturlar va umumiy amallar +Comment[uz@cyrillic]=ДаÑтурлар ва умумий амаллар +Comment[vi]=Ứng dụng và thao tác thÆ°á»ng là m +Comment[wa]=Programes et comones accions +Comment[zh_CN]=应用程åºå’Œå…¬å…±æ“作 +Comment[zh_TW]=應用程å¼èˆ‡ä¸€èˆ¬å‹•ä½œ +Icon=kmenu +X-KDE-Library=KMenuButton diff --git a/kicker/kicker/buttons/nonkdeappbutton.cpp b/kicker/kicker/buttons/nonkdeappbutton.cpp new file mode 100644 index 000000000..9413e8aaa --- /dev/null +++ b/kicker/kicker/buttons/nonkdeappbutton.cpp @@ -0,0 +1,287 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> +#include <qdragobject.h> + +#include <kconfig.h> +#include <kdesktopfile.h> +#include <kapplication.h> +#include <kglobal.h> +#include <krun.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kiconeffect.h> +#include <kdebug.h> + +// the header where the configuration dialog is defined. +#include "exe_dlg.h" + +// our own definition +#include "nonkdeappbutton.h" + +// we include the "moc" file so that the KDE build system knows to create it +#include "nonkdeappbutton.moc" + +// this is one of the two constructors. gets called when creating a new button +// e.g. via the "non-KDE Application" dialog, not one that was saved and then +// restored. +NonKDEAppButton::NonKDEAppButton(const QString& name, + const QString& description, + const QString& filePath, const QString& icon, + const QString &cmdLine, bool inTerm, + QWidget* parent) + : PanelButton(parent, "NonKDEAppButton") // call our superclass's constructor +{ + // call the initialization method + initialize(name, description, filePath, icon, cmdLine, inTerm); + + // and connect the clicked() signal (emitted when the button is activated) + // to the slotExec() slot + // we do this here instead of in initialize(...) since initialize(...) may + // get called later, e.g after reconfiguring it + connect(this, SIGNAL(clicked()), SLOT(slotExec())); +} + +// this constructor is used when restoring a button, usually at startup +NonKDEAppButton::NonKDEAppButton( const KConfigGroup& config, QWidget* parent ) + : PanelButton(parent, "NonKDEAppButton") // call our superclass's constructor +{ + // call the initialization method, this time with values from a config file + initialize(config.readEntry("Name"), + config.readEntry("Description"), + config.readPathEntry("Path"), + config.readEntry("Icon"), + config.readPathEntry("CommandLine"), + config.readBoolEntry("RunInTerminal")); + + // see comment on connect in above constructor + connect(this, SIGNAL(clicked()), SLOT(slotExec())); +} + +void NonKDEAppButton::initialize(const QString& name, + const QString& description, + const QString& filePath, const QString& icon, + const QString &cmdLine, bool inTerm ) +{ + // and now we actually set up most of the member variables with the + // values passed in here. by doing this all in an initialize() method + // we avoid duplicating this code all over the place + nameStr = name; + descStr = description; + pathStr = filePath; + iconStr = icon; + cmdStr = cmdLine; + term = inTerm; + + // now we set the buttons tooltip, title and icon using the appropriate + // set*() methods from the PanelButton class from which we subclass + + // assign the name or the description to a QString called tooltip + QString tooltip = description.isEmpty() ? nameStr : descStr; + + if (tooltip.isEmpty()) + { + // we had nothing, so let's try the path + tooltip = pathStr; + + // and add the command if we have one. + if (!cmdStr.isEmpty()) + { + tooltip += " " + cmdStr; + } + + // set the title to the pathStr + setTitle(pathStr); + } + else + { + // since we have a name or a description (assigned by the user) let's + // use that as the title + setTitle(nameStr.isEmpty() ? descStr : nameStr); + } + + // set the tooltip + QToolTip::add(this, tooltip); + + // set the icon + setIcon(iconStr); +} + +void NonKDEAppButton::saveConfig( KConfigGroup& config ) const +{ + // this is called whenever we change something + // the config object sent in will already be set to the + // right group and file, so we can just start writing + config.writeEntry("Name", nameStr); + config.writeEntry("Description", descStr); + config.writeEntry("RunInTerminal", term); + config.writePathEntry("Path", pathStr); + config.writeEntry("Icon", iconStr); + config.writePathEntry("CommandLine", cmdStr); +} + +void NonKDEAppButton::dragEnterEvent(QDragEnterEvent *ev) +{ + // when something is dragged onto this button, we'll accept it + // if we aren't dragged onto ourselves, and if it's a URL + if ((ev->source() != this) && KURLDrag::canDecode(ev)) + { + ev->accept(rect()); + } + else + { + ev->ignore(rect()); + } + + // and now let the PanelButton do as it wishes with it... + PanelButton::dragEnterEvent(ev); +} + +void NonKDEAppButton::dropEvent(QDropEvent *ev) +{ + // something has been droped on us! + KURL::List fileList; + QString execStr; + if (KURLDrag::decode(ev, fileList)) + { + // according to KURLDrag, we've successfully retrieved + // one or more URLs! now we iterate over them one by + // one .... + for (KURL::List::ConstIterator it = fileList.begin(); + it != fileList.end(); + ++it) + { + const KURL &url(*it); + if (KDesktopFile::isDesktopFile(url.path())) + { + // this URL is actually a .desktop file, so let's grab + // the URL it actually points to ... + KDesktopFile deskFile(url.path()); + deskFile.setDesktopGroup(); + + // ... and add it to the exec string + execStr += KProcess::quote(deskFile.readURL()) + " "; + } + else + { + // it's just a URL of some sort, add it directly to the exec + execStr += KProcess::quote(url.path()) + " "; + } + } + + // and now run the command + runCommand(execStr); + } + + // and let PanelButton clean up + PanelButton::dropEvent(ev); +} + +void NonKDEAppButton::slotExec() +{ + // the button was clicked, let's take some action + runCommand(); +} + +void NonKDEAppButton::runCommand(const QString& execStr) +{ + // run our command! this method is used both by the drag 'n drop + // facilities as well as when the button is activated (usualy w/a click) + + // we'll use the "result" variable to record our success/failure + bool result; + + // since kicker doesn't listen to or use the session manager, we have + // to make sure that our environment is set up correctly. this is + // accomlplished by doing: + kapp->propagateSessionManager(); + + if (term) + { + // run in a terminal? ok! we find this in the config file in the + // [misc] group (this will usually be in kdeglobal, actually, which + // get merged into the application config automagically for us + KConfig *config = KGlobal::config(); + config->setGroup("misc"); + QString termStr = config->readPathEntry("Terminal", "konsole"); + + // and now we run the darn thing and store how we fared in result + result = KRun::runCommand(termStr + " -e " + pathStr + " " + + cmdStr + " " + execStr, + pathStr, iconStr); + } + else + { + // just run it... + result = KRun::runCommand(pathStr + " " + cmdStr + " " + execStr, + pathStr, iconStr); + } + + if (!result) + { + // something went wrong, so let's show an error msg to the user + KMessageBox::error(this, i18n("Cannot execute non-KDE application."), + i18n("Kicker Error")); + return; + } +} + +void NonKDEAppButton::updateSettings(PanelExeDialog* dlg) +{ + // we were reconfigured via the confiugration dialog + // re-setup our member variables using initialize(...), + // this time using values from the dlg + initialize(dlg->title(), dlg->description(), dlg->command(), + dlg->iconPath(), dlg->commandLine(), dlg->useTerminal()); + + // now delete the dialog so that it doesn't leak memory + delete dlg; + + // and emit a signal that the container that houses us + // listens for so it knows when to start the process to + // save our configuration + emit requestSave(); +} + +void NonKDEAppButton::properties() +{ + // the user has requested to configure this button + // this method gets called by the ButtonContainer that houses the button + // see ButtonContainer::eventFilter(QObject *o, QEvent *e), where the + // context menu is created and dealt with. + + // so we create a new config dialog .... + PanelExeDialog* dlg = new PanelExeDialog(nameStr, descStr, pathStr, + iconStr, cmdStr, term, this); + + // ... connect the signal it emits when it has data for us to save + // to our updateSettings slot (see above) ... + connect(dlg, SIGNAL(updateSettings(PanelExeDialog*)), this, + SLOT(updateSettings(PanelExeDialog*))); + + // ... and then show it to the user + dlg->show(); +} + diff --git a/kicker/kicker/buttons/nonkdeappbutton.h b/kicker/kicker/buttons/nonkdeappbutton.h new file mode 100644 index 000000000..bbb74c892 --- /dev/null +++ b/kicker/kicker/buttons/nonkdeappbutton.h @@ -0,0 +1,92 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __nonkdeappbutton_h__ +#define __nonkdeappbutton_h__ + +// pull in the superclass's definition +#include "panelbutton.h" + +// forward declare this class +// lets the compiler know it exists without have to know all the gory details +class PanelExeDialog; + +/** + * Button that contains a non-KDE application + * subclass of PanelButton + */ +class NonKDEAppButton : public PanelButton +{ + // the Q_OBJECT macro provides the magic glue for signals 'n slots + Q_OBJECT + +public: + // define our two constructors, one used for creating new buttons... + NonKDEAppButton(const QString& name, const QString& description, + const QString& filePath, const QString& icon, + const QString& cmdLine, bool inTerm, QWidget* parent); + + // ... and once for restoring them at start up + NonKDEAppButton(const KConfigGroup& config, QWidget* parent); + + // reimplemented from PanelButton + virtual void saveConfig(KConfigGroup& config) const; + virtual void properties(); + +protected slots: + // called when the button is activated + void slotExec(); + + // called after the user reconfigures something + void updateSettings(PanelExeDialog* dlg); + +protected: + // used to set up our internal state, either when creating the button + // or after reconfiguration + void initialize(const QString& name, const QString& description, + const QString& filePath, const QString& icon, + const QString& cmdLine, bool inTerm); + + // run the command! + // the execStr parameter, which default to an empty string, + // is used to provide additional command line options aside + // from the ones in our config file; for instance a URL drag'd onto us + void runCommand(const QString& execStr = QString::null); + + // reimplemented from PanelButton + virtual QString tileName() { return "URL"; } + QString defaultIcon() const { return "exec"; }; + + // handle drag and drop actions + virtual void dropEvent(QDropEvent *ev); + virtual void dragEnterEvent(QDragEnterEvent *ev); + + QString nameStr; // the name given this button by the user + QString descStr; // the description given this button by the user + QString pathStr; // the path to the command + QString iconStr; // the path to the icon for this button + QString cmdStr; // command line flags, if any + bool term; // whether to run this in a terminal or not +}; // all done defining the class! + +#endif diff --git a/kicker/kicker/buttons/servicebutton.cpp b/kicker/kicker/buttons/servicebutton.cpp new file mode 100644 index 000000000..a5ec7c9a2 --- /dev/null +++ b/kicker/kicker/buttons/servicebutton.cpp @@ -0,0 +1,262 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qdragobject.h> +#include <qtooltip.h> + +#include <kdesktopfile.h> +#include <klocale.h> +#include <kiconeffect.h> +#include <kicontheme.h> +#include <kpropertiesdialog.h> +#include <krun.h> +#include <kstandarddirs.h> +#include <kurl.h> + +#include "global.h" +#include "kicker.h" + +#include "servicebutton.h" +#include "servicebutton.moc" + +ServiceButton::ServiceButton(const QString& desktopFile, QWidget* parent) + : PanelButton(parent, "ServiceButton"), + _service(0) +{ + loadServiceFromId(desktopFile); + initialize(); +} + +ServiceButton::ServiceButton(const KService::Ptr &service, QWidget* parent) + : PanelButton(parent, "ServiceButton"), + _service(service), + _id(service->storageId()) +{ + if (_id.startsWith("/")) + { + QString tmp = KGlobal::dirs()->relativeLocation("appdata", _id); + if (!tmp.startsWith("/")) + _id = ":"+tmp; + } + initialize(); +} + +ServiceButton::ServiceButton( const KConfigGroup& config, QWidget* parent ) + : PanelButton(parent, "ServiceButton"), + _service(0) +{ + QString id; + if (config.hasKey("StorageId")) + id = config.readPathEntry("StorageId"); + else + id = config.readPathEntry("DesktopFile"); + loadServiceFromId(id); + initialize(); +} + +ServiceButton::~ServiceButton() +{ +} + +void ServiceButton::loadServiceFromId(const QString &id) +{ + _id = id; + /* this is a KService::Ptr + don't need to delete it + delete _service; + */ + _service = 0; + + if (_id.startsWith(":")) + { + _id = locate("appdata", id.mid(1)); + if (!_id.isEmpty()) + { + KDesktopFile df(_id, true); + _service = new KService(&df); + } + } + else + { + _service = KService::serviceByStorageId(_id); + if (_service) + { + _id = _service->storageId(); + } + } + + if (_service) + { + backedByFile(_service->desktopEntryPath()); + } + + if (_id.startsWith("/")) + { + QString tmp = KGlobal::dirs()->relativeLocation("appdata", _id); + if (!tmp.startsWith("/")) + _id = ":"+tmp; + } +} + +void ServiceButton::initialize() +{ + readDesktopFile(); + connect(this, SIGNAL(clicked()), SLOT(slotExec())); +} + +void ServiceButton::readDesktopFile() +{ + if ( !_service || !_service->isValid() ) + { + m_valid = false; + return; + } + + if (!_service->genericName().isEmpty()) + { + QToolTip::add(this, _service->genericName()); + } + else if (_service->comment().isEmpty()) + { + QToolTip::add(this, _service->name()); + } + else + { + QToolTip::add(this, _service->name() + " - " + _service->comment()); + } + + setTitle( _service->name() ); + setIcon( _service->icon() ); +} + +void ServiceButton::saveConfig( KConfigGroup& config ) const +{ + config.writePathEntry("StorageId", _id ); + if (!config.hasKey("DesktopFile") && _service) + config.writePathEntry("DesktopFile", _service->desktopEntryPath()); +} + +void ServiceButton::dragEnterEvent(QDragEnterEvent *ev) +{ + if ((ev->source() != this) && KURLDrag::canDecode(ev)) + ev->accept(rect()); + else + ev->ignore(rect()); + PanelButton::dragEnterEvent(ev); +} + +void ServiceButton::dropEvent( QDropEvent* ev ) +{ + KURL::List uriList; + if( KURLDrag::decode( ev, uriList ) && _service ) { + kapp->propagateSessionManager(); + KRun::run( *_service, uriList ); + } + PanelButton::dropEvent(ev); +} + +void ServiceButton::startDrag() +{ + QString path = _service->desktopEntryPath(); + + // If the path to the desktop file is relative, try to get the full + // path from KStdDirs. + path = locate("apps", path); + + KURL url; + url.setPath(path); + emit dragme(KURL::List(url), labelIcon()); +} + +void ServiceButton::slotExec() +{ + // this allows the button to return to a non-pressed state + // before launching + QTimer::singleShot(0, this, SLOT(performExec())); +} + +void ServiceButton::performExec() +{ + if (!_service) return; + + KURL::List uriList; + kapp->propagateSessionManager(); + KRun::run( *_service, uriList ); +} + +void ServiceButton::properties() +{ + if (!_service) + { + return; + } + + QString path = _service->desktopEntryPath(); + + // If the path to the desktop file is relative, try to get the full + // path from KStdDirs. + path = locate("apps", path); + KURL serviceURL; + serviceURL.setPath(path); + + // the KPropertiesDialog deletes itself, so this isn't a memory leak + KPropertiesDialog* dialog = new KPropertiesDialog(serviceURL, 0, 0, + false, false); + dialog->setFileNameReadOnly(true); + connect(dialog, SIGNAL(saveAs(const KURL &, KURL &)), + this, SLOT(slotSaveAs(const KURL &, KURL &))); + connect(dialog, SIGNAL(propertiesClosed()), + this, SLOT(slotUpdate())); + dialog->show(); +} + +void ServiceButton::slotUpdate() +{ + loadServiceFromId(_id); + readDesktopFile(); + emit requestSave(); +} + +void ServiceButton::slotSaveAs(const KURL &oldUrl, KURL &newUrl) +{ + QString oldPath = oldUrl.path(); + if (locateLocal("appdata", oldUrl.fileName()) != oldPath) + { + QString path = KickerLib::newDesktopFile(oldUrl); + newUrl.setPath(path); + _id = path; + } +} + +bool ServiceButton::checkForBackingFile() +{ + QString id = _id; + loadServiceFromId(_id); + + // we need to reset the _id back to whatever it was + // so that when we get called again to check on it we + // know still know what to be looking for. + _id = id; + + return _service != 0; +} diff --git a/kicker/kicker/buttons/servicebutton.h b/kicker/kicker/buttons/servicebutton.h new file mode 100644 index 000000000..26f32791a --- /dev/null +++ b/kicker/kicker/buttons/servicebutton.h @@ -0,0 +1,66 @@ +/***************************************************************** + +Copyright (c) 2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __ServiceButton_h__ +#define __ServiceButton_h__ + +#include "panelbutton.h" + +#include <kservice.h> + +class ServiceButton : public PanelButton +{ + Q_OBJECT + +public: + ServiceButton( const QString& desktopFile, QWidget* parent ); + ServiceButton( const KService::Ptr& service, QWidget* parent ); + ServiceButton( const KConfigGroup& config, QWidget* parent ); + + ~ServiceButton(); + + virtual void saveConfig(KConfigGroup& config) const; + virtual void properties(); + +protected slots: + void slotUpdate(); + void slotSaveAs(const KURL&, KURL&); + void slotExec(); + void performExec(); + +protected: + void initialize(); + void loadServiceFromId(const QString &id); + void readDesktopFile(); + virtual QString tileName() { return "URL"; } + virtual void startDrag(); + virtual void dropEvent(QDropEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + QString defaultIcon() const { return "exec"; }; + bool checkForBackingFile(); + + KService::Ptr _service; + QString _id; +}; + +#endif diff --git a/kicker/kicker/buttons/servicemenubutton.cpp b/kicker/kicker/buttons/servicemenubutton.cpp new file mode 100644 index 000000000..e3fc41185 --- /dev/null +++ b/kicker/kicker/buttons/servicemenubutton.cpp @@ -0,0 +1,96 @@ +/***************************************************************** + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> + +#include <kconfig.h> +#include <kservicegroup.h> +#include <klocale.h> + +#include "service_mnu.h" + +#include "servicemenubutton.h" +#include "servicemenubutton.moc" + +ServiceMenuButton::ServiceMenuButton( const QString& relPath, QWidget* parent ) + : PanelPopupButton( parent, "ServiceMenuButton" ) + , topMenu( 0 ) +{ + initialize( relPath ); +} + +ServiceMenuButton::ServiceMenuButton( const KConfigGroup& config, QWidget* parent ) + : PanelPopupButton( parent, "ServiceMenuButton" ) + , topMenu( 0 ) +{ + initialize( config.readPathEntry("RelPath") ); +} + +void ServiceMenuButton::initialize( const QString& relPath ) +{ + KServiceGroup::Ptr group = KServiceGroup::group( relPath ); + + if (!group || !group->isValid()) + { + m_valid = false; + return; + } + + QString caption = group->caption(); + if (caption.isEmpty()) + { + caption = i18n("Applications"); + } + + QString comment = group->comment(); + if (comment.isEmpty()) + { + comment = caption; + } + + topMenu = new PanelServiceMenu(caption, relPath); + setPopup(topMenu); + QToolTip::add(this, comment); + setTitle(caption); + setIcon(group->icon()); +} + +void ServiceMenuButton::saveConfig( KConfigGroup& config ) const +{ + if (topMenu) + config.writePathEntry("RelPath", topMenu->relPath()); +} + +void ServiceMenuButton::initPopup() +{ + if( !topMenu->initialized() ) { + topMenu->reinitialize(); + } +} + +void ServiceMenuButton::startDrag() +{ + KURL url("programs:/" + topMenu->relPath()); + emit dragme(KURL::List(url), labelIcon()); +} + diff --git a/kicker/kicker/buttons/servicemenubutton.h b/kicker/kicker/buttons/servicemenubutton.h new file mode 100644 index 000000000..1bd9d1885 --- /dev/null +++ b/kicker/kicker/buttons/servicemenubutton.h @@ -0,0 +1,54 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __servicemenubutton_h__ +#define __servicemenubutton_h__ + +#include "panelbutton.h" + +class PanelServiceMenu; + +/** + * Button that contains a Service menu + */ +class ServiceMenuButton : public PanelPopupButton +{ + Q_OBJECT + +public: + ServiceMenuButton( const QString& relPath, QWidget* parent ); + ServiceMenuButton( const KConfigGroup& config, QWidget* parent ); + + void saveConfig( KConfigGroup& config ) const; + +protected: + void initialize( const QString& relPath ); + virtual QString tileName() { return "Browser"; } + virtual QString defaultIcon() const { return "folder"; } + virtual void startDrag(); + virtual void initPopup(); + + PanelServiceMenu* topMenu; +}; + +#endif diff --git a/kicker/kicker/buttons/urlbutton.cpp b/kicker/kicker/buttons/urlbutton.cpp new file mode 100644 index 000000000..007b0cc00 --- /dev/null +++ b/kicker/kicker/buttons/urlbutton.cpp @@ -0,0 +1,201 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> +#include <qfile.h> + +#include <kdesktopfile.h> +#include <kfileitem.h> +#include <konq_operations.h> +#include <kicontheme.h> +#include <kglobal.h> +#include <kiconeffect.h> +#include <kpropertiesdialog.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <krun.h> +#include <klocale.h> + +#include <kdebug.h> + +#include "global.h" +#include "kicker.h" + +#include "urlbutton.h" +#include "urlbutton.moc" + +URLButton::URLButton( const QString& url, QWidget* parent ) + : PanelButton( parent, "URLButton" ) + , fileItem( 0 ) + , pDlg( 0 ) +{ + initialize( url ); +} + +URLButton::URLButton( const KConfigGroup& config, QWidget* parent ) + : PanelButton( parent, "URLButton" ) + , fileItem( 0 ) + , pDlg( 0 ) +{ + initialize( config.readPathEntry("URL") ); +} + +URLButton::~URLButton() +{ + delete fileItem; +} + +void URLButton::initialize( const QString& _url ) +{ + KURL url(_url); + if (!url.isLocalFile() || !url.path().endsWith(".desktop")) + { + QString file = KickerLib::newDesktopFile(url); + KDesktopFile df(file); + df.writeEntry("Encoding", "UTF-8"); + df.writeEntry("Type","Link"); + df.writeEntry("Name", url.prettyURL()); + if (url.isLocalFile()) + { + KFileItem item( KFileItem::Unknown, KFileItem::Unknown, url ); + df.writeEntry("Icon", item.iconName() ); + } + else + { + df.writeEntry("Icon", KMimeType::favIconForURL(url)); + } + df.writeEntry("URL", url.url()); + url = KURL(); + url.setPath(file); + } + fileItem = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, url ); + setIcon( fileItem->iconName() ); + connect( this, SIGNAL(clicked()), SLOT(slotExec()) ); + setToolTip(); + + if (url.isLocalFile()) + { + backedByFile(url.path()); + } +} + +void URLButton::saveConfig( KConfigGroup& config ) const +{ + config.writePathEntry("URL", fileItem->url().prettyURL()); +} + +void URLButton::setToolTip() +{ + if (fileItem->isLocalFile() + && KDesktopFile::isDesktopFile(fileItem->url().path())) + { + KDesktopFile df(fileItem->url().path()); + + if (df.readComment().isEmpty()) + { + QToolTip::add(this, df.readName()); + } + else + { + QToolTip::add(this, df.readName() + " - " + df.readComment()); + } + + setTitle(df.readName()); + } + else + { + QToolTip::add(this, fileItem->url().prettyURL()); + setTitle(fileItem->url().prettyURL()); + } +} + +void URLButton::dragEnterEvent(QDragEnterEvent *ev) +{ + if ((ev->source() != this) && fileItem->acceptsDrops() && KURLDrag::canDecode(ev)) + ev->accept(rect()); + else + ev->ignore(rect()); + PanelButton::dragEnterEvent(ev); +} + +void URLButton::dropEvent(QDropEvent *ev) +{ + kapp->propagateSessionManager(); + KURL::List execList; + if(KURLDrag::decode(ev, execList)){ + KURL url( fileItem->url() ); + if(!execList.isEmpty()) { + if (KDesktopFile::isDesktopFile(url.path())){ + KApplication::startServiceByDesktopPath(url.path(), execList.toStringList(), + 0, 0, 0, "", true); + } + else // attempt to interpret path as directory + { + KonqOperations::doDrop( fileItem, url, ev, this ); + } + } + } + PanelButton::dropEvent(ev); +} + +void URLButton::startDrag() +{ + emit dragme(KURL::List(fileItem->url()), labelIcon()); +} + +void URLButton::slotExec() +{ + kapp->propagateSessionManager(); + fileItem->run(); +} + +void URLButton::updateURL() +{ + if (pDlg->kurl() != fileItem->url()) { + fileItem->setURL(pDlg->kurl()); + setIcon(fileItem->iconName()); + setToolTip(); + emit requestSave(); + } else { + setIcon(fileItem->iconName()); + setToolTip(); + } + + pDlg = 0L; +} + +void URLButton::properties() +{ + if ( (fileItem->isLocalFile() && !QFile::exists(fileItem->url().path()) ) + || !fileItem->url().isValid()) + { + KMessageBox::error( 0L, i18n("The file %1 does not exist") + .arg(fileItem->url().prettyURL()) ); + return; + } + + pDlg = new KPropertiesDialog(fileItem, 0L, 0L, false, false); // will delete itself + pDlg->setFileNameReadOnly(true); + connect(pDlg, SIGNAL(applied()), SLOT(updateURL())); + pDlg->show(); +} diff --git a/kicker/kicker/buttons/urlbutton.h b/kicker/kicker/buttons/urlbutton.h new file mode 100644 index 000000000..e6f6b12e0 --- /dev/null +++ b/kicker/kicker/buttons/urlbutton.h @@ -0,0 +1,65 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __urlbutton_h__ +#define __urlbutton_h__ + +#include "panelbutton.h" + +class KFileItem; +class KPropertiesDialog; + +/** + * Simple URL button (files, whatever) + */ +class URLButton : public PanelButton +{ + Q_OBJECT + +public: + URLButton( const QString& url, QWidget* parent ); + URLButton( const KConfigGroup& config, QWidget* parent ); + + virtual ~URLButton(); + + void saveConfig( KConfigGroup& config ) const; + + virtual void properties(); + +protected slots: + void slotExec(); + void updateURL(); + +protected: + void initialize( const QString& url ); + virtual QString tileName() { return "URL"; } + virtual void startDrag(); + virtual void dropEvent(QDropEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + void setToolTip(); + + KFileItem *fileItem; + KPropertiesDialog *pDlg; +}; + +#endif diff --git a/kicker/kicker/buttons/windowlist.desktop b/kicker/kicker/buttons/windowlist.desktop new file mode 100644 index 000000000..c4b7c9579 --- /dev/null +++ b/kicker/kicker/buttons/windowlist.desktop @@ -0,0 +1,130 @@ +[Desktop Entry] +Name=Window List Menu +Name[af]=Venster Lys Kieslys +Name[ar]=قائمة عرض النواÙØ° +Name[be]=Меню ÑпіÑа вокнаў +Name[bg]=СпиÑък Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€Ñ†Ð¸Ñ‚Ðµ +Name[bn]=উইণà§à¦¡à§‹ তালিকা মেনৠ+Name[br]=Meuziad listenn ar prenester +Name[bs]=Meni sa spiskom prozora +Name[ca]=Menú de la llista de finestres +Name[cs]=NabÃdka seznamu oken +Name[csb]=Menu z lëstÄ… òknów +Name[cy]=Dewislen Rhestr Ffenestri +Name[da]=Vindueslistemenu +Name[de]=Fensterliste +Name[el]=ÎœÎµÎ½Î¿Ï Î»Î¯ÏƒÏ„Î±Ï‚ παÏαθÏÏων +Name[eo]=Fenestrolista Menuo +Name[es]=Menú de la lista de ventanas +Name[et]=Akende nimekirja menüü +Name[eu]=Leiho zerrendaren menua +Name[fa]=گزینگان Ùهرست پنجره +Name[fi]=Ikkunaluettelovalikko +Name[fr]=Liste des fenêtres +Name[fy]=Finsterlistmenu +Name[gl]=Lista de Fiestras +Name[he]=תפריט רשימת ×—×œ×•× ×•×ª +Name[hr]=Izbornik popisa prozora +Name[hu]=Ablaklista menü +Name[is]=Gluggalista valmynd +Name[it]=Menu elenco delle finestre +Name[ja]=ウィンドウリストメニュー +Name[ka]=ფáƒáƒœáƒ¯áƒ ების სიის მენიუ +Name[kk]=Терезелер тізімінің мәзірі +Name[km]=ម៉ឺនុយ​បញ្ជី​បង្អួច +Name[lt]=Langų sÄ…raÅ¡o meniu +Name[mk]=Мени Ñо лиÑта на прозорци +Name[nb]=Vinduslistemeny +Name[nds]=Finsterlist +Name[ne]=सञà¥à¤à¥à¤¯à¤¾à¤² सूची मेनॠ+Name[nl]=Vensterlijstmenu +Name[nn]=Vindaugslistemeny +Name[pa]=à¨à¨°à©‹à¨–ਾ ਸੂਚੀ ਮੇਨੂ +Name[pl]=Menu z listÄ… okien +Name[pt]=Menu da Lista de Janelas +Name[pt_BR]=Menu de Lista de Janelas +Name[ro]=Meniu listă de ferestre +Name[ru]=СпиÑок окон +Name[rw]=Ibikubiyemo Rutonde by'Idirishya +Name[se]=Láselistofállu +Name[sk]=Menu zoznamu okien +Name[sl]=Meni s seznamom oken +Name[sr]=Мени лиÑте прозора +Name[sr@Latn]=Meni liste prozora +Name[sv]=Fönsterlistmeny +Name[te]=విండొల జాబితా పటà±à°Ÿà°¿ +Name[tg]=Менюи рӯйхати равзанаҳо +Name[th]=เมนูà¹à¸ªà¸”งรายà¸à¸²à¸£à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡ +Name[tr]=Pencere Listeleme Menüsü +Name[tt]=Täräzä Tezmäse Saylağı +Name[uk]=Меню ÑпиÑку вікон +Name[uz]=Oynalar roÊ»yxati +Name[uz@cyrillic]=Ойналар рўйхати +Name[vi]=Thá»±c Ä‘Æ¡n Liệt kê Cá»a sổ +Name[wa]=Dressêye del djivêye des purneas +Name[zh_CN]=窗å£åˆ—表èœå• +Name[zh_TW]=視窗列表é¸å–® +Comment=A menu that lists all open windows +Comment[af]='n Kieslys wat al die oop vensters vertoon +Comment[ar]=قائمة لعرض كل النواÙØ° المÙتوØØ© +Comment[be]=Меню, Ñкое паказвае уÑе Ð°Ð´ÐºÑ€Ñ‹Ñ‚Ñ‹Ñ Ð²Ð¾ÐºÐ½Ñ‹ +Comment[bg]=Меню-ÑпиÑък, което Ñъдържа вÑички отворени прозорци +Comment[bn]=à¦à¦•à¦Ÿà¦¿ মেনৠযা সমসà§à¦¤ খোলা উইণà§à¦¡à§‹ তালিকাবদà§à¦§ করে +Comment[bs]=Meni u kojem su navedeni svi trenutno otvoreni prozori +Comment[ca]=Un menú que llista totes les finestres obertes +Comment[cs]=NabÃdka se seznamem otevÅ™ených oken +Comment[csb]=Menu pòkazëwôjÄ…cé wszëstczé otemkłé òkna +Comment[da]=En menu der lister alle Ã¥bne vinduer +Comment[de]=Dieses Menü zeigt alle geöffneten Fenster an +Comment[el]=Ένα Î¼ÎµÎ½Î¿Ï Ï€Î¿Ï… εμφανίζει όλα τα ανοικτά παÏάθυÏα +Comment[eo]=Menuo kiu listigas ĉiujn malfermitajn fenestrojn +Comment[es]=Un menú que muestra todas las ventanas abiertas +Comment[et]=Menüü, mis näitab kõiki avatud aknaid +Comment[eu]=Leiho irekien zerrenda bistaratzen duen menua +Comment[fa]=گزینگانی Ú©Ù‡ همۀ پنجره‌های باز را Ùهرست می‌کند +Comment[fi]=Valikko, jossa on luettelo kaikista avoimista ikkunoista +Comment[fr]=Un menu affichant l'ensemble des fenêtres ouvertes +Comment[fy]=In menu mei in list fan alle iepensteande finsters +Comment[ga]=Roghchlár le gach fuinneog atá oscailte +Comment[gl]=Un menu que lista todas as fiestras abertas +Comment[he]=תפריט המציג ×ת רשימת כל ×”×—×œ×•× ×•×ª ×”×¤×ª×•×—×™× +Comment[hr]=Izbornik s popisom svih otvorenih prozora +Comment[hu]=Menü a nyitott ablakok kilistázásához +Comment[is]=Valmynd sem sýnir alla opna glugga +Comment[it]=Un menu che mostra tutte le finestre aperte +Comment[ja]=é–‹ã„ã¦ã„ã‚‹ã™ã¹ã¦ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®ãƒªã‚¹ãƒˆã‚’表示ã™ã‚‹ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=ყველრგáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜ ფáƒáƒœáƒ¯áƒ ის სიის მენიუ +Comment[kk]=Барлық ашық терезелердің мәзір тізімі +Comment[km]=ម៉ឺនុយ​ដែល​រាយ​បង្អួច​បើក​ទាំងអស់ +Comment[lt]=Visų atvertų langų sÄ…raÅ¡Ä… pateikiantis meniu +Comment[mk]=Мени што ги лиÑта Ñите отворени прозорци +Comment[nb]=En meny som viser alle Ã¥pne vinduer +Comment[nds]=En Menü, dat all apen Finstern oplist +Comment[ne]=सबै खà¥à¤²à¤¾ सञà¥à¤à¥à¤¯à¤¾à¤²à¤¹à¤°à¥‚ सूचीकृत गरà¥à¤¨à¥‡ मेनॠ+Comment[nl]=Een menu met een lijst van alle geopende vensters +Comment[nn]=Ein meny som viser alle opne vindauge +Comment[pa]=ਸਠਖà©à©±à¨²à©‡ à¨à¨°à©‹à¨–ਿਆਂ ਦੀ ਸੂਚੀ ਲਈ ਇੱਕ ਮੇਨੂ ਹੈ +Comment[pl]=Menu pokazujÄ…ce wszystkie otwarte okna +Comment[pt]=Um menu que mostra todas as janelas abertas +Comment[pt_BR]=Um menu que lista todas as janelas abertas +Comment[ro]=Un meniu ce listează toate ferestrele deschise +Comment[ru]=СпиÑок вÑех открытых окон +Comment[rw]=Ibikubiyemo bitanga urutonde w'amadirishya yose afunguye +Comment[se]=Fállu mas oidnot buot rabas láset +Comment[sk]=Menu, ktoré zobrazà zoznam okien +Comment[sl]=Meni, ki prikazuje seznam vseh odprtih oken +Comment[sr]=Мени који лиÑта Ñве отворене прозоре +Comment[sr@Latn]=Meni koji lista sve otvorene prozore +Comment[sv]=En meny som listar alla öppna fönster +Comment[th]=เมนูที่à¹à¸ªà¸”งรายà¸à¸²à¸£à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡à¸—ี่เปิดà¸à¸¢à¸¹à¹ˆà¸—ั้งหมด +Comment[tr]=Bütün Pencereleri listeleyen bir menü +Comment[tt]=Bar açıq täräzä tezmäse belän saylaq +Comment[uk]=Меню, Ñке дає перелік вÑÑ–Ñ… відкритих вікон +Comment[uz]=Hamma ochiq oynalar roÊ»yxati +Comment[uz@cyrillic]=Ҳамма очиқ ойналар рўйхати +Comment[vi]=Má»™t thá»±c Ä‘Æ¡n liệt kê tất cả các cá»a sổ Ä‘ang mở +Comment[wa]=Ene dressêye ki fwait l' djivêye di tos les drovîs purneas +Comment[zh_CN]=列出打开的全部窗å£çš„èœå• +Comment[zh_TW]=一個列出所有開啟視窗的é¸å–® +Icon=window_list +X-KDE-Library=WindowListButton diff --git a/kicker/kicker/buttons/windowlistbutton.cpp b/kicker/kicker/buttons/windowlistbutton.cpp new file mode 100644 index 000000000..8a60ca5e8 --- /dev/null +++ b/kicker/kicker/buttons/windowlistbutton.cpp @@ -0,0 +1,47 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtooltip.h> + +#include <kwindowlistmenu.h> +#include <klocale.h> + +#include "windowlistbutton.h" +#include "windowlistbutton.moc" + +WindowListButton::WindowListButton( QWidget* parent ) + : PanelPopupButton( parent, "WindowListButton" ) + , topMenu( 0 ) +{ + topMenu = new KWindowListMenu( this ); + setPopup(topMenu); + + setTitle(i18n("Window List")); + QToolTip::add(this, i18n("Window list")); + setIcon("window_list"); +} + +void WindowListButton::initPopup() +{ + topMenu->init(); +} diff --git a/kicker/kicker/buttons/windowlistbutton.h b/kicker/kicker/buttons/windowlistbutton.h new file mode 100644 index 000000000..23dc26c19 --- /dev/null +++ b/kicker/kicker/buttons/windowlistbutton.h @@ -0,0 +1,48 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __windowlistbutton_h__ +#define __windowlistbutton_h__ + +#include "panelbutton.h" + +class KWindowListMenu; + +/** + * Button that contains a windowlist menu + */ +class WindowListButton : public PanelPopupButton +{ + Q_OBJECT + +public: + WindowListButton( QWidget* parent ); + +protected: + virtual QString tileName() { return "WindowList"; } + virtual void initPopup(); + + KWindowListMenu* topMenu; +}; + +#endif diff --git a/kicker/kicker/core/Makefile.am b/kicker/kicker/core/Makefile.am new file mode 100644 index 000000000..6986af604 --- /dev/null +++ b/kicker/kicker/core/Makefile.am @@ -0,0 +1,33 @@ +INCLUDES = -I$(srcdir)/../../libkicker -I../../libkicker \ + -I$(srcdir)/../ui -I$(srcdir)/../buttons -I$(top_srcdir)/libkonq \ + $(all_includes) + +noinst_LTLIBRARIES = libkicker_core.la + +libkicker_core_la_SOURCES = extensionSettings.kcfgc \ + main.cpp kicker.cpp kicker.skel \ + userrectsel.cpp containerarea.cpp \ + applethandle.cpp container_base.cpp container_button.cpp \ + container_applet.cpp container_extension.cpp extensionmanager.cpp \ + menumanager.cpp pluginmanager.cpp showdesktop.cpp \ + unhidetrigger.cpp containerarealayout.cpp \ + panelextension.cpp panelextension.skel + + +libkicker_core_la_LDFLAGS = $(all_libraries) +libkicker_core_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(LIB_KDEUI) +libkicker_core_la_METASOURCES = AUTO +libkicker_core_la_COMPILE_FIRST = ../../libkicker/kickerSettings.h + +kicker_core_data_DATA = default-apps +kicker_core_datadir = $(kde_datadir)/kicker + +lnkdir = $(kde_datadir)/kicker/extensions +lnk_DATA = childpanelextension.desktop + +kicker.lo: ../../libkicker/kickerSettings.h +showdesktop.lo: ../../libkicker/kickerSettings.h +container_applet.lo: ../../libkicker/kickerSettings.h +containerarea.lo: ../../libkicker/kickerSettings.h +container_extension.lo: ../../libkicker/kickerSettings.h + diff --git a/kicker/kicker/core/applethandle.cpp b/kicker/kicker/core/applethandle.cpp new file mode 100644 index 000000000..cd9de3c62 --- /dev/null +++ b/kicker/kicker/core/applethandle.cpp @@ -0,0 +1,402 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qstyle.h> +#include <qpixmapcache.h> +#include <qtimer.h> +#include <qtooltip.h> +#include <qimage.h> + +#include <kpushbutton.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> + +#include "global.h" +#include "container_applet.h" +#include "kickerSettings.h" + +#include "applethandle.h" + +AppletHandle::AppletHandle(AppletContainer* parent) + : QWidget(parent), + m_applet(parent), + m_menuButton(0), + m_drawHandle(false), + m_popupDirection(KPanelApplet::Up), + m_handleHoverTimer(0) +{ + setBackgroundOrigin(AncestorOrigin); + setMinimumSize(widthForHeight(0), heightForWidth(0)); + m_layout = new QBoxLayout(this, QBoxLayout::BottomToTop, 0, 0); + + m_dragBar = new AppletHandleDrag(this); + m_dragBar->installEventFilter(this); + m_layout->addWidget(m_dragBar); + + if (kapp->authorizeKAction("kicker_rmb")) + { + m_menuButton = new AppletHandleButton( this ); + m_menuButton->installEventFilter(this); + m_layout->addWidget(m_menuButton); + + connect(m_menuButton, SIGNAL(pressed()), + this, SLOT(menuButtonPressed())); + QToolTip::add(m_menuButton, i18n("%1 menu").arg(parent->info().name())); + } + + QToolTip::add(this, i18n("%1 applet handle").arg(parent->info().name())); + resetLayout(); +} + +int AppletHandle::heightForWidth( int /* w */ ) const +{ + int size = style().pixelMetric(QStyle::PM_DockWindowHandleExtent, this); + + return size; +} + +int AppletHandle::widthForHeight( int /* h */ ) const +{ + int size = style().pixelMetric(QStyle::PM_DockWindowHandleExtent, this); + + return size; +} + +void AppletHandle::setPopupDirection(KPanelApplet::Direction d) +{ + Qt::ArrowType a = Qt::UpArrow; + + if (d == m_popupDirection || !m_menuButton) + { + return; + } + + m_popupDirection = d; + + switch (m_popupDirection) + { + case KPanelApplet::Up: + m_layout->setDirection(QBoxLayout::BottomToTop); + a = Qt::UpArrow; + break; + case KPanelApplet::Down: + m_layout->setDirection(QBoxLayout::TopToBottom); + a = Qt::DownArrow; + break; + case KPanelApplet::Left: + m_layout->setDirection(QBoxLayout::RightToLeft); + a = Qt::LeftArrow; + break; + case KPanelApplet::Right: + m_layout->setDirection(QBoxLayout::LeftToRight); + a = Qt::RightArrow; + break; + } + + m_menuButton->setArrowType(a); + m_layout->activate(); +} + +void AppletHandle::resetLayout() +{ + if (m_handleHoverTimer && !m_drawHandle) + { + m_dragBar->hide(); + + if (m_menuButton) + { + m_menuButton->hide(); + } + } + else + { + m_dragBar->show(); + + if (m_menuButton) + { + m_menuButton->show(); + } + } +} + +void AppletHandle::setFadeOutHandle(bool fadeOut) +{ + if (fadeOut) + { + if (!m_handleHoverTimer) + { + m_handleHoverTimer = new QTimer(this); + connect(m_handleHoverTimer, SIGNAL(timeout()), + this, SLOT(checkHandleHover())); + m_applet->installEventFilter(this); + } + } + else + { + delete m_handleHoverTimer; + m_handleHoverTimer = 0; + m_applet->removeEventFilter(this); + } + + resetLayout(); +} + +bool AppletHandle::eventFilter(QObject *o, QEvent *e) +{ + if (o == parent()) + { + switch (e->type()) + { + case QEvent::Enter: + { + m_drawHandle = true; + resetLayout(); + + if (m_handleHoverTimer) + { + m_handleHoverTimer->start(250); + } + break; + } + + case QEvent::Leave: + { + if (m_menuButton && m_menuButton->isOn()) + { + break; + } + + QWidget* w = dynamic_cast<QWidget*>(o); + + bool nowDrawIt = false; + if (w) + { + // a hack for applets that have out-of-process + // elements (e.g the systray) so that the handle + // doesn't flicker when moving over those elements + if (w->rect().contains(w->mapFromGlobal(QCursor::pos()))) + { + nowDrawIt = true; + } + } + + if (nowDrawIt != m_drawHandle) + { + if (m_handleHoverTimer) + { + m_handleHoverTimer->stop(); + } + + m_drawHandle = nowDrawIt; + resetLayout(); + } + break; + } + + default: + break; + } + + return QWidget::eventFilter( o, e ); + } + else if (o == m_dragBar) + { + if (e->type() == QEvent::MouseButtonPress) + { + QMouseEvent* ev = static_cast<QMouseEvent*>(e); + if (ev->button() == LeftButton || ev->button() == MidButton) + { + emit moveApplet(m_applet->mapFromGlobal(ev->globalPos())); + } + } + } + + if (m_menuButton && e->type() == QEvent::MouseButtonPress) + { + QMouseEvent* ev = static_cast<QMouseEvent*>(e); + if (ev->button() == RightButton) + { + if (!m_menuButton->isDown()) + { + m_menuButton->setDown(true); + menuButtonPressed(); + } + + return true; + } + } + + return QWidget::eventFilter(o, e); // standard event processing +} + +void AppletHandle::menuButtonPressed() +{ + if (!kapp->authorizeKAction("kicker_rmb")) + { + return; + } + + emit showAppletMenu(); + + if (!onMenuButton(QCursor::pos())) + { + toggleMenuButtonOff(); + } +} + +void AppletHandle::checkHandleHover() +{ + if (!m_handleHoverTimer || + (m_menuButton && m_menuButton->isOn()) || + m_applet->geometry().contains(m_applet->mapToParent( + m_applet->mapFromGlobal(QCursor::pos())))) + { + return; + } + + m_handleHoverTimer->stop(); + m_drawHandle = false; + resetLayout(); +} + +bool AppletHandle::onMenuButton(const QPoint& point) const +{ + return m_menuButton && (childAt(mapFromGlobal(point)) == m_menuButton); +} + +void AppletHandle::toggleMenuButtonOff() +{ + if (!m_menuButton) + { + return; + } + + m_menuButton->setDown(false); +} + +AppletHandleDrag::AppletHandleDrag(AppletHandle* parent) + : QWidget(parent), + m_parent(parent), + m_inside(false) +{ + setBackgroundOrigin( AncestorOrigin ); +} + +QSize AppletHandleDrag::minimumSizeHint() const +{ + int wh = style().pixelMetric(QStyle::PM_DockWindowHandleExtent, this); + + if (m_parent->orientation() == Horizontal) + { + return QSize(wh, 0); + } + + return QSize(0, wh); +} + +QSizePolicy AppletHandleDrag::sizePolicy() const +{ + if (m_parent->orientation() == Horizontal) + { + return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ); + } + + return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); +} + +void AppletHandleDrag::enterEvent( QEvent *e ) +{ + m_inside = true; + QWidget::enterEvent( e ); + update(); +} + +void AppletHandleDrag::leaveEvent( QEvent *e ) +{ + m_inside = false; + QWidget::enterEvent( e ); + update(); +} + +void AppletHandleDrag::paintEvent(QPaintEvent *) +{ + QPainter p(this); + + if (!KickerSettings::transparent()) + { + if (paletteBackgroundPixmap()) + { + QPoint offset = backgroundOffset(); + int ox = offset.x(); + int oy = offset.y(); + p.drawTiledPixmap( 0, 0, width(), height(),*paletteBackgroundPixmap(), ox, oy); + } + + QStyle::SFlags flags = QStyle::Style_Default; + flags |= QStyle::Style_Enabled; + if (m_parent->orientation() == Horizontal) + { + flags |= QStyle::Style_Horizontal; + } + + QRect r = rect(); + + style().drawPrimitive(QStyle::PE_DockWindowHandle, &p, r, + colorGroup(), flags); + } + else + { + KickerLib::drawBlendedRect(&p, QRect(0, 0, width(), height()), paletteForegroundColor(), m_inside ? 0x40 : 0x20); + } +} + +AppletHandleButton::AppletHandleButton(AppletHandle *parent) + : SimpleArrowButton(parent), + m_parent(parent) +{ +} + +QSize AppletHandleButton::minimumSizeHint() const +{ + int height = style().pixelMetric(QStyle::PM_DockWindowHandleExtent, this); + int width = height; + + if (m_parent->orientation() == Horizontal) + { + return QSize(width, height); + } + + return QSize(height, width); +} + +QSizePolicy AppletHandleButton::sizePolicy() const +{ + return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); +} + +#include "applethandle.moc" diff --git a/kicker/kicker/core/applethandle.h b/kicker/kicker/core/applethandle.h new file mode 100644 index 000000000..2158756cb --- /dev/null +++ b/kicker/kicker/core/applethandle.h @@ -0,0 +1,126 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __applethandle_h__ +#define __applethandle_h__ + +#include <qwidget.h> +#include <qpushbutton.h> + +#include "container_applet.h" +#include "simplebutton.h" + +class QBoxLayout; +class QTimer; +class AppletHandleDrag; +class AppletHandleButton; + +class AppletHandle : public QWidget +{ + Q_OBJECT + + public: + AppletHandle(AppletContainer* parent); + + void resetLayout(); + void setFadeOutHandle(bool); + + bool eventFilter (QObject *, QEvent *); + + int widthForHeight( int h ) const; + int heightForWidth( int w ) const; + + void setPopupDirection(KPanelApplet::Direction); + KPanelApplet::Direction popupDirection() const + { + return m_popupDirection; + } + + KPanelApplet::Orientation orientation() const + { + return m_applet->orientation(); + } + + bool onMenuButton(const QPoint& point) const; + + signals: + void moveApplet( const QPoint& moveOffset ); + void showAppletMenu(); + + public slots: + void toggleMenuButtonOff(); + + protected slots: + void menuButtonPressed(); + void checkHandleHover(); + + private: + AppletContainer* m_applet; + QBoxLayout* m_layout; + AppletHandleDrag* m_dragBar; + AppletHandleButton* m_menuButton; + bool m_drawHandle; + KPanelApplet::Direction m_popupDirection; + QTimer* m_handleHoverTimer; + bool m_inside; +}; + +class AppletHandleDrag : public QWidget +{ + Q_OBJECT + + public: + AppletHandleDrag(AppletHandle* parent); + + QSize minimumSizeHint() const; + QSize minimumSize() const { return minimumSizeHint(); } + QSize sizeHint() const { return minimumSize(); } + QSizePolicy sizePolicy() const; + + protected: + void paintEvent( QPaintEvent* ); + void enterEvent( QEvent* ); + void leaveEvent( QEvent* ); + const AppletHandle* m_parent; + + private: + bool m_inside; +}; + +class AppletHandleButton : public SimpleArrowButton +{ + Q_OBJECT + + public: + AppletHandleButton(AppletHandle *parent); + QSize minimumSizeHint() const; + QSize minimumSize() const { return minimumSizeHint(); } + QSize sizeHint() const { return minimumSize(); } + QSizePolicy sizePolicy() const; + + private: + bool m_moveMouse; + const AppletHandle* m_parent; +}; + +#endif diff --git a/kicker/kicker/core/childpanelextension.desktop b/kicker/kicker/core/childpanelextension.desktop new file mode 100644 index 000000000..edad98d50 --- /dev/null +++ b/kicker/kicker/core/childpanelextension.desktop @@ -0,0 +1,145 @@ +[Desktop Entry] +Name=Panel +Name[af]=Paneel +Name[ar]=Ø§Ù„Ù„ÙˆØ +Name[be]=ПанÑль +Name[bg]=СиÑтемен панел +Name[bn]=পà§à¦¯à¦¾à¦¨à§‡à¦² +Name[br]=Panell +Name[ca]=Plafó +Name[de]=Kontrollleiste +Name[el]=Πίνακας +Name[eo]=Panelo +Name[et]=Paneel +Name[eu]=Panela +Name[fa]=تابلو +Name[fi]=Paneeli +Name[fo]=Bróst +Name[fr]=Tableau de bord +Name[fy]=Paniel +Name[ga]=Painéal +Name[gl]=Painel +Name[he]=לוח +Name[hi]=फलक +Name[hr]=PloÄa +Name[is]=Spjald +Name[it]=Pannello +Name[ja]=パãƒãƒ« +Name[ka]=პáƒáƒœáƒ”ლი +Name[kk]=Панель +Name[km]=បន្ទះ +Name[ko]=íŒ¨ë„ +Name[lo]=ถาดพาเนล +Name[lt]=Pultas +Name[lv]=Panelis +Name[mk]=Панел +Name[nds]=Paneel +Name[ne]=पà¥à¤¯à¤¾à¤¨à¤² +Name[nl]=Paneel +Name[oc]=Panèu de contròle +Name[pa]=ਪੈਨਲ +Name[pt]=Painel +Name[pt_BR]=Painel +Name[ro]=Panou +Name[ru]=Панель +Name[rw]=Umwanya +Name[se]=Panela +Name[sl]=Pult +Name[sr]=Панел +Name[ta]=பலகம௠+Name[te]=పెనలౠ+Name[tg]=Панел +Name[th]=พาเนล +Name[tt]=Tirä +Name[uk]=Панель +Name[uz@cyrillic]=Панел +Name[ven]=Phanele +Name[vi]=Bảng Ä‘iá»u khiển +Name[wa]=Scriftôr +Name[xh]=Iqela lenjongo ethile +Name[zh_CN]=é¢æ¿ +Name[zh_TW]=é¢æ¿ +Name[zu]=Iwindi lemininingwane +Comment=Child panel extension. +Comment[af]=Kind paneel uitbreiding. +Comment[ar]=إمتداد Ù„ÙˆØ Ø§Ù„Ù…Ù‡Ø§Ù… الإبن. +Comment[az]=TörÉ™mÉ™ panel uzantısı. +Comment[be]=ПашырÑнне дадатковай панÑлі. +Comment[bg]=Разширение на ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð¿Ð°Ð½ÐµÐ» +Comment[bn]=চাইলà§à¦¡ পà§à¦¯à¦¾à¦¨à§‡à¦² à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨ +Comment[bs]=ProÅ¡irenje osnovnog panela. +Comment[ca]=Una extensió del plafó petitet. +Comment[cs]=RozÅ¡ÃÅ™enà závislého panelu. +Comment[csb]=Rozszérzenié òtrokòwégò panelu. +Comment[cy]=Estyniad panel plentyn +Comment[da]=Udvidelse med underpanel. +Comment[de]=Abhängige Kontrollleiste +Comment[el]=ΕπÎκταση θυγατÏÎ¹ÎºÎ¿Ï Ï€Î¯Î½Î±ÎºÎ±. +Comment[eo]=Ido-panelaldono. +Comment[es]=Extensión Panel hijo. +Comment[et]=Paneeli laiendus alampaneelide loomiseks +Comment[eu]=Panel semearen hedapena +Comment[fa]=پسوند تابلوی Ùرزند. +Comment[fi]=Lapsipaaneelilaajennus +Comment[fr]=Extension du tableau de bord +Comment[fy]=Dochterpanielekstinsje +Comment[gl]=Extensión de painel fillo. +Comment[he]=הרחבת לוח צ×צ×. +Comment[hi]=शिशॠफलक विसà¥à¤¤à¤¾à¤°. +Comment[hr]=ProÅ¡irenje za dodatnu ploÄu +Comment[hu]=Gyermek-panel. +Comment[is]=ÚtvÃkkun undirspjalds. +Comment[it]=Estensione del pannello +Comment[ja]=åパãƒãƒ«æ‹¡å¼µ +Comment[ka]=შვილეული პáƒáƒœáƒ”ლის გáƒáƒ¤áƒáƒ თáƒáƒ•áƒ”ბრ+Comment[kk]=Ð•Ð½ÑˆÑ–Ð»ÐµÑ Ð¿Ð°Ð½ÐµÐ»ÑŒ. +Comment[km]=ផ្នែក​បន្ážáŸ‚ម​បន្ទះ​កូន ។ +Comment[lo]=ສ່ວນຂະຫàºàº²àºàºžàº²à»€àº™àº¥àº¥àº¹àº +Comment[lt]=Priklausomo pulto iÅ¡plÄ—timas. +Comment[lv]=PalÄ«g paneļa paplaÅ¡inÄjums. +Comment[mk]=ЕкÑтензија - дете панел. +Comment[mn]=Ð¥Ò¯Ò¯ удирдах Ñамбарын өргөтгөл +Comment[ms]=Lanjutan panel anak. +Comment[mt]=Estensjoni sotto-pannell. +Comment[nb]=Barnepanelutvidelse +Comment[nds]=Verwiedern för en ünnerornt Paneel. +Comment[ne]=शाखा पà¥à¤¯à¤¾à¤¨à¤² विसà¥à¤¤à¤¾à¤° +Comment[nl]=Dochterpaneelextensie. +Comment[nn]=Barnepanelutviding +Comment[nso]=Koketso ya Panel ya Ngwana +Comment[pa]=ਅੱਗੇ ਪੈਨਲ ਵਧਾਰਾ ਹੈ। +Comment[pl]=Rozszerzenie panelu potomnego. +Comment[pt]=Extensão painel filho. +Comment[pt_BR]=Extensão de painel-filho. +Comment[ro]=Extensie panou fiu. +Comment[ru]=РаÑширение дочерней панели +Comment[rw]=Umugereka w'umwanya mwana. +Comment[se]=Vuollepanela viiddádus +Comment[sk]=RozÅ¡Ãrenie pre potomkov panelu. +Comment[sl]=RazÅ¡iritev za podrejeni pult. +Comment[sr]=Дечји панел, проширење панела. +Comment[sr@Latn]=DeÄji panel, proÅ¡irenje panela. +Comment[sv]=Underpanelutbyggnad +Comment[ta]=சிறà¯à®µà®°à¯ பலக விரிவாகà¯à®•à®®à¯. +Comment[tg]=БаÑти Ñафҳаи контроли кӯдак +Comment[th]=ส่วนขยายพาเนลลูภ+Comment[tr]=Çocuk Panel uzantısı. +Comment[tt]=Bala taqta östämäse. +Comment[uk]=Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°Ð½ÐµÐ»Ñ–-нащадка. +Comment[uz]=Ikkilamchi panel kengaytmasi +Comment[uz@cyrillic]=Иккиламчи панел кенгайтмаÑи +Comment[ven]=Thumanyo ya phanele ya nwana +Comment[vi]=Các bảng Ä‘iá»u khiển con mở rá»™ng +Comment[wa]=Module do scriftôr +Comment[xh]=Ulwandiso lweqela lenjongo ethile yomntwana. +Comment[zh_CN]=åé¢æ¿æ‰©å±•ã€‚ +Comment[zh_TW]=åé¢æ¿å»¶ä¼¸ã€‚ +Comment[zu]=Isandiso sewindi lemininingwane elingumntwana. + +Icon=kicker +X-KDE-Library=childpanel_panelextension +X-KDE-PanelExt-Resizeable=true +X-KDE-PanelExt-StdSizes=true +X-KDE-PanelExt-CustomSizeMin=24 +X-KDE-PanelExt-CustomSizeMax=300 +X-KDE-PanelExt-CustomSizeDefault=58 diff --git a/kicker/kicker/core/container_applet.cpp b/kicker/kicker/core/container_applet.cpp new file mode 100644 index 000000000..390b934d3 --- /dev/null +++ b/kicker/kicker/core/container_applet.cpp @@ -0,0 +1,478 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qxembed.h> +#include <qframe.h> +#include <qlayout.h> +#include <qhbox.h> +#include <qfile.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpanelapplet.h> +#include <kpopupmenu.h> +#include <kprocess.h> +#include <kstandarddirs.h> + +#include "applethandle.h" +#include "appletinfo.h" +#include "appletop_mnu.h" +#include "containerarea.h" +#include "global.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "pluginmanager.h" + +#include "container_applet.h" +#include "container_applet.moc" + +#define APPLET_MARGIN 1 + +AppletContainer::AppletContainer(const AppletInfo& info, + QPopupMenu* opMenu, + bool immutable, + QWidget* parent ) + : BaseContainer(opMenu, + parent, + QString(info.library() + "container").latin1()), + _info(info), + _handle(0), + _layout(0), + _type(KPanelApplet::Normal), + _widthForHeightHint(0), + _heightForWidthHint(0), + _firstuse(true) +{ + setBackgroundOrigin(AncestorOrigin); + + //setup appletframe + _appletframe = new QHBox(this); + _appletframe->setBackgroundOrigin( AncestorOrigin ); + _appletframe->setFrameStyle(QFrame::NoFrame); + _appletframe->installEventFilter(this); + + if (orientation() == Horizontal) + { + _layout = new QBoxLayout(this, QBoxLayout::LeftToRight, 0, 0); + } + else + { + _layout = new QBoxLayout(this, QBoxLayout::TopToBottom, 0, 0); + } + + _layout->setResizeMode( QLayout::FreeResize ); + + _layout->addSpacing(APPLET_MARGIN); + _handle = new AppletHandle(this); + _layout->addWidget(_handle, 0); + connect(_handle, SIGNAL(moveApplet(const QPoint&)), + this, SLOT(moveApplet(const QPoint&))); + connect(_handle, SIGNAL(showAppletMenu()), this, SLOT(showAppletMenu())); + + _layout->addWidget(_appletframe, 1); + _layout->activate(); + + _deskFile = info.desktopFile(); + _configFile = info.configFile(); + _applet = PluginManager::the()->loadApplet( info, _appletframe ); + + if (!_applet) + { + _valid = false; + KMessageBox::error(this, + i18n("The %1 applet could not be loaded. Please check your installation.") + .arg(info.name().isEmpty() ? _deskFile : info.name()), + i18n("Applet Loading Error")); + return; + } + + _valid = true; + + _applet->setPosition((KPanelApplet::Position)KickerLib::directionToPosition(popupDirection())); + _applet->setAlignment((KPanelApplet::Alignment)alignment()); + + _actions = _applet->actions(); + _type = _applet->type(); + + setImmutable(immutable); + + connect(_applet, SIGNAL(updateLayout()), SLOT(slotUpdateLayout())); + connect(_applet, SIGNAL(requestFocus()), SLOT(activateWindow())); + connect(_applet, SIGNAL(requestFocus(bool)), SLOT(focusRequested(bool))); + + connect(Kicker::the(), SIGNAL(configurationChanged()), + this, SLOT(slotReconfigure())); +} + +void AppletContainer::configure() +{ + _handle->setPopupDirection(popupDirection()); + _handle->setFadeOutHandle(KickerSettings::fadeOutAppletHandles()); + + if (isImmutable() || + KickerSettings::hideAppletHandles() || + !kapp->authorizeKAction("kicker_rmb")) + { + if (_handle->isVisibleTo(this)) + { + _handle->hide(); + setBackground(); + } + } + else if (!_handle->isVisibleTo(this)) + { + _handle->show(); + setBackground(); + } +} + +void AppletContainer::slotReconfigure() +{ + configure(); +} + +void AppletContainer::setPopupDirection(KPanelApplet::Direction d) +{ + if (!_firstuse && _dir == d) + { + return; + } + + _firstuse = false; + + BaseContainer::setPopupDirection(d); + _handle->setPopupDirection(d); + resetLayout(); + + if (_applet) + { + _applet->setPosition((KPanelApplet::Position)KickerLib::directionToPosition(d)); + } +} + +void AppletContainer::setOrientation(KPanelExtension::Orientation o) +{ + if (_orient == o) return; + + BaseContainer::setOrientation(o); + setBackground(); + resetLayout(); +} + +void AppletContainer::resetLayout() +{ + _handle->resetLayout(); + + if (orientation() == Horizontal) + { + _layout->setDirection( QBoxLayout::LeftToRight ); + } + else + { + _layout->setDirection( QBoxLayout::TopToBottom ); + } + + _layout->activate(); +} + +void AppletContainer::moveApplet( const QPoint& moveOffset ) +{ + _moveOffset = moveOffset; + emit moveme(this); +} + +void AppletContainer::signalToBeRemoved() +{ + emit removeme(this); +} + +void AppletContainer::showAppletMenu() +{ + if (!kapp->authorizeKAction("kicker_rmb")) + { + return; + } + + QPopupMenu *menu = opMenu(); + + Kicker::the()->setInsertionPoint(_handle->mapToGlobal(_handle->rect().center())); + + switch(menu->exec(KickerLib::popupPosition(popupDirection(), menu, _handle))) + { + case PanelAppletOpMenu::Move: + moveApplet(_handle->mapToParent(_handle->rect().center())); + break; + case PanelAppletOpMenu::Remove: + Kicker::the()->setInsertionPoint(QPoint()); + emit removeme(this); + return; // Above signal will cause this to be deleted. + break; + case PanelAppletOpMenu::Help: + help(); + break; + case PanelAppletOpMenu::About: + about(); + break; + case PanelAppletOpMenu::Preferences: + preferences(); + break; + case PanelAppletOpMenu::ReportBug: + reportBug(); + break; + default: + break; + } + + Kicker::the()->setInsertionPoint(QPoint()); + clearOpMenu(); +} + +void AppletContainer::slotRemoved(KConfig* config) +{ + BaseContainer::slotRemoved(config); + + // we must delete the applet first since it may write out a config file + // in its dtor which can foil out plans to remove it's config file below + delete _applet; + _applet = 0; + + if (_configFile.isEmpty() || + _info.isUniqueApplet()) + { + return; + } + + QFile::remove(locateLocal("config", _configFile)); +} + +void AppletContainer::activateWindow() +{ + KWin::forceActiveWindow(topLevelWidget()->winId()); +} + +void AppletContainer::focusRequested(bool focus) +{ + if (focus) + { + KWin::forceActiveWindow(topLevelWidget()->winId()); + } + + emit maintainFocus(focus); +} + +void AppletContainer::doLoadConfiguration( KConfigGroup& config ) +{ + setWidthForHeightHint(config.readNumEntry("WidthForHeightHint", 0)); + setHeightForWidthHint(config.readNumEntry("HeightForWidthHint", 0)); +} + +void AppletContainer::doSaveConfiguration( KConfigGroup& config, + bool layoutOnly ) const +{ + // immutability is checked by ContainerBase + if (orientation() == Horizontal) + { + config.writeEntry( "WidthForHeightHint", widthForHeight(height()) ); + } + else + { + config.writeEntry( "HeightForWidthHint", heightForWidth(width()) ); + } + + if (!layoutOnly) + { + config.writePathEntry( "ConfigFile", _configFile ); + config.writePathEntry( "DesktopFile", _deskFile ); + } +} + +QPopupMenu* AppletContainer::createOpMenu() +{ + QPopupMenu* opMenu = new PanelAppletOpMenu(_actions, appletOpMenu(), + appletsOwnMenu(), + _info.name(), _info.icon(), + this); + + connect(opMenu, SIGNAL(escapePressed()), + _handle, SLOT(toggleMenuButtonOff())); + + return opMenu; +} + +void AppletContainer::slotRemoveApplet() +{ + emit removeme(this); +} + +void AppletContainer::slotUpdateLayout() +{ + updateGeometry(); + emit updateLayout(); +} + + +const QPopupMenu* AppletContainer::appletsOwnMenu() const +{ + if (!_applet) + { + return 0; + } + + return _applet->customMenu(); +} + +void AppletContainer::slotDelayedDestruct() +{ + delete this; +} + +void AppletContainer::alignmentChange(KPanelExtension::Alignment a) +{ + if (!_applet) + { + return; + } + + _applet->setAlignment( (KPanelApplet::Alignment)a ); +} + +int AppletContainer::widthForHeight(int h) const +{ + int handleSize = (_handle->isVisibleTo(const_cast<AppletContainer*>(this))? + _handle->widthForHeight(h) : 0); + + if (!_applet) + { + if (_widthForHeightHint > 0) + { + return _widthForHeightHint + handleSize; + } + else + { + return h + handleSize; + } + } + + return _applet->widthForHeight(h) + handleSize + APPLET_MARGIN; +} + +int AppletContainer::heightForWidth(int w) const +{ + int handleSize = (_handle->isVisibleTo(const_cast<AppletContainer*>(this))? + _handle->heightForWidth(w) : 0); + + if (!_applet) + { + if (_heightForWidthHint > 0) + { + return _heightForWidthHint + handleSize; + } + else + { + return w + handleSize; + } + } + + return _applet->heightForWidth(w) + handleSize + APPLET_MARGIN; +} + +void AppletContainer::about() +{ + if (!_applet) return; + _applet->action( KPanelApplet::About ); +} + +void AppletContainer::help() +{ + if (!_applet) return; + _applet->action( KPanelApplet::Help ); +} + +void AppletContainer::preferences() +{ + if (!_applet) return; + _applet->action( KPanelApplet::Preferences ); +} + +void AppletContainer::reportBug() +{ + if (!_applet) return; + _applet->action( KPanelApplet::ReportBug ); +} + +void AppletContainer::setBackground() +{ + // can happen in perverse moments when an applet isn't loaded but the contanier + // get's asked to update it's bground anyways + if (!_applet) + { + return; + } + + _applet->unsetPalette(); + _handle->unsetPalette(); + + setBackgroundOrigin(AncestorOrigin); + _applet->update(); + _handle->update(); + + if (KickerSettings::transparent()) + { + // Trick to tell applets that they must refresh their transparent background if they need. + QMoveEvent e(_applet->pos(), _applet->pos()); + QApplication::sendEvent(_applet, &e); + } +} + +void AppletContainer::setImmutable(bool immutable) +{ + // The menu applet must be kept immutable + if (_deskFile == "menuapplet.desktop" && !immutable) + return; + + BaseContainer::setImmutable(immutable); + if (isImmutable() || + KickerSettings::hideAppletHandles() || + !kapp->authorizeKAction("kicker_rmb")) + { + if (_handle->isVisibleTo(this)) + { + _handle->hide(); + setBackground(); + } + } + else if (!_handle->isVisibleTo(this)) + { + QToolTip::add(_handle, _info.name()); + _handle->show(); + setBackground(); + } +} diff --git a/kicker/kicker/core/container_applet.h b/kicker/kicker/core/container_applet.h new file mode 100644 index 000000000..8c364c09f --- /dev/null +++ b/kicker/kicker/core/container_applet.h @@ -0,0 +1,113 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __container_applet_h__ +#define __container_applet_h__ + +#include <kpanelapplet.h> +#include <dcopobject.h> +#include <kwin.h> + +#include "appletinfo.h" +#include "container_base.h" + +class QHBox; +class QXEmbed; +class QBoxLayout; +class KConfig; + +class AppletHandle; + +class AppletContainer : public BaseContainer +{ + Q_OBJECT + +public: + AppletContainer(const AppletInfo& info, QPopupMenu* opMenu, bool isImmutable = false, QWidget* parent = 0); + + KPanelApplet::Type type() const { return _type; } + const AppletInfo& info() const { return _info; } + const QPopupMenu* appletsOwnMenu() const; + bool isStretch() const { return type() == KPanelApplet::Stretch; } + void resetLayout(); + + virtual void configure(); + virtual void about(); + virtual void help(); + virtual void preferences(); + virtual void reportBug(); + virtual void setBackground(); + virtual bool isValid() const { return _valid; } + virtual QString appletType() const { return "Applet"; } + virtual QString icon() const { return _info.icon(); } + virtual QString visibleName() const { return _info.name(); } + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + + void setWidthForHeightHint(int w) { _widthForHeightHint = w; } + void setHeightForWidthHint(int h) { _heightForWidthHint = h; } + +signals: + void updateLayout(); + +public slots: + virtual void slotRemoved(KConfig* config); + virtual void setPopupDirection(KPanelApplet::Direction d); + virtual void setOrientation(KPanelExtension::Orientation o); + virtual void setImmutable(bool immutable); + void moveApplet( const QPoint& moveOffset ); + void showAppletMenu(); + void slotReconfigure(); + void activateWindow(); + +protected: + virtual void doLoadConfiguration( KConfigGroup& ); + virtual void doSaveConfiguration( KConfigGroup&, bool layoutOnly ) const; + virtual void alignmentChange(KPanelExtension::Alignment a); + + virtual QPopupMenu* createOpMenu(); + + AppletInfo _info; + AppletHandle *_handle; + QHBox *_appletframe; + QBoxLayout *_layout; + KPanelApplet::Type _type; + int _widthForHeightHint; + int _heightForWidthHint; + QString _deskFile, _configFile; + bool _firstuse; + QCString _id; + KPanelApplet * _applet; + bool _valid; + +protected slots: + void slotRemoveApplet(); + void slotUpdateLayout(); + void signalToBeRemoved(); + void slotDelayedDestruct(); + void focusRequested(bool); +}; + +#endif + diff --git a/kicker/kicker/core/container_base.cpp b/kicker/kicker/core/container_base.cpp new file mode 100644 index 000000000..cadbe592a --- /dev/null +++ b/kicker/kicker/core/container_base.cpp @@ -0,0 +1,139 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qpopupmenu.h> + +#include <kglobal.h> +#include <kconfig.h> +#include <kdebug.h> + +#include "global.h" +#include "appletop_mnu.h" +#include "kicker.h" + +#include "container_base.h" +#include "container_base.moc" + +BaseContainer::BaseContainer( QPopupMenu* appletOpMenu, QWidget* parent, const char * name ) + : QWidget( parent, name ) + , _dir(KPanelApplet::Up) + , _orient(Horizontal) + , _alignment(KPanelExtension::LeftTop) + , _fspace(0) + , _moveOffset(QPoint(0,0)) + , _aid(QString::null) + , _actions(0) + , m_immutable(false) + , _opMnu(0) + , _appletOpMnu(appletOpMenu) +{} + +BaseContainer::~BaseContainer() +{ + delete _opMnu; +} + +void BaseContainer::reparent(QWidget* parent, WFlags f, const QPoint& p, bool showIt) +{ + emit takeme(this); + QWidget::reparent(parent, f, p, showIt); +} + +bool BaseContainer::isImmutable() const +{ + return m_immutable || Kicker::the()->isImmutable(); +} + +void BaseContainer::setImmutable(bool immutable) +{ + m_immutable = immutable; + clearOpMenu(); +} + +void BaseContainer::loadConfiguration( KConfigGroup& group ) +{ + setFreeSpace( QMIN( group.readDoubleNumEntry( "FreeSpace2", 0 ), 1 ) ); + doLoadConfiguration( group ); +} + +void BaseContainer::saveConfiguration(KConfigGroup& group, + bool layoutOnly) const +{ + if (isImmutable()) + { + return; + } + + // write positioning info + group.writeEntry( "FreeSpace2", freeSpace() ); + // write type specific info + doSaveConfiguration( group, layoutOnly ); +} + +void BaseContainer::configure(KPanelExtension::Orientation o, + KPanelApplet::Direction d) +{ + setBackgroundOrigin(AncestorOrigin); + setOrientation(o); + setPopupDirection(d); + configure(); +} + +void BaseContainer::slotRemoved(KConfig* config) +{ + if (!config) + { + config = KGlobal::config(); + } + + config->deleteGroup(appletId().latin1()); + config->sync(); +} + +void BaseContainer::setAlignment(KPanelExtension::Alignment a) +{ + if (_alignment == a) + { + return; + } + + _alignment = a; + alignmentChange(a); +} + +QPopupMenu* BaseContainer::opMenu() +{ + if (_opMnu == 0) + { + _opMnu = createOpMenu(); + } + + return KickerLib::reduceMenu(_opMnu); +} + +void BaseContainer::clearOpMenu() +{ + delete _opMnu; + _opMnu = 0; +} + diff --git a/kicker/kicker/core/container_base.h b/kicker/kicker/core/container_base.h new file mode 100644 index 000000000..aa3efeb98 --- /dev/null +++ b/kicker/kicker/core/container_base.h @@ -0,0 +1,134 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __container_base_h__ +#define __container_base_h__ + +#include <qwidget.h> +#include <qpoint.h> +#include <qvaluelist.h> + +#include <kpanelextension.h> +#include <kpanelapplet.h> + +class KConfigGroup; +class QPopupMenu; + +class BaseContainer : public QWidget +{ + Q_OBJECT + +public: + typedef QValueList<BaseContainer*> List; + typedef QValueListIterator<BaseContainer*> Iterator; + typedef QValueListConstIterator<BaseContainer*> ConstIterator; + + BaseContainer( QPopupMenu* appletOpMenu, QWidget* parent = 0, const char * name = 0 ); + ~BaseContainer(); + + virtual void reparent(QWidget * parent, WFlags f, const QPoint & p, bool showIt = false); + + virtual int widthForHeight(int height) const = 0; + virtual int heightForWidth(int width) const = 0; + + virtual bool isStretch() const { return false; } + + virtual void completeMoveOperation() {} + virtual void about() {} + virtual void help() {} + virtual void preferences() {} + virtual void reportBug() {} + + virtual bool isValid() const { return true; } + bool isImmutable() const; + virtual void setImmutable(bool immutable); + + double freeSpace() const { return _fspace; } + void setFreeSpace(double f) { _fspace = f; } + + QString appletId() const { return _aid; } + void setAppletId(const QString& s) { _aid = s; } + + virtual int actions() const { return _actions; } + + KPanelApplet::Direction popupDirection() const { return _dir; } + KPanelExtension::Orientation orientation() const { return _orient; } + KPanelExtension::Alignment alignment() const { return _alignment; } + + virtual void setBackground() {} + + QPopupMenu* opMenu(); + void clearOpMenu(); + + void loadConfiguration( KConfigGroup& ); + void saveConfiguration( KConfigGroup&, bool layoutOnly = false ) const; + + void configure(KPanelExtension::Orientation, KPanelApplet::Direction); + virtual void configure() {} + + QPoint moveOffset() const { return _moveOffset; } + + virtual QString appletType() const = 0; + virtual QString icon() const { return "unknown"; } + virtual QString visibleName() const = 0; + +public slots: + virtual void slotRemoved(KConfig* config); + virtual void setPopupDirection(KPanelApplet::Direction d) { _dir = d; } + virtual void setOrientation(KPanelExtension::Orientation o) { _orient = o; } + + void setAlignment(KPanelExtension::Alignment a); + +signals: + void removeme(BaseContainer*); + void takeme(BaseContainer*); + void moveme(BaseContainer*); + void maintainFocus(bool); + void requestSave(); + void focusReqested(bool); + +protected: + virtual void doLoadConfiguration( KConfigGroup& ) {} + virtual void doSaveConfiguration( KConfigGroup&, + bool /* layoutOnly */ ) const {} + virtual void alignmentChange(KPanelExtension::Alignment) {} + + virtual QPopupMenu* createOpMenu() = 0; + QPopupMenu *appletOpMenu() const { return _appletOpMnu; } + + KPanelApplet::Direction _dir; + KPanelExtension::Orientation _orient; + KPanelExtension::Alignment _alignment; + double _fspace; + QPoint _moveOffset; + QString _aid; + int _actions; + bool m_immutable; + +private: + QPopupMenu *_opMnu; + QPopupMenu *_appletOpMnu; +}; + +#endif + diff --git a/kicker/kicker/core/container_button.cpp b/kicker/kicker/core/container_button.cpp new file mode 100644 index 000000000..b050f371d --- /dev/null +++ b/kicker/kicker/core/container_button.cpp @@ -0,0 +1,542 @@ +/***************************************************************** + +Copyright (c) 1996-2003 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <algorithm> + +#include <qlayout.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kmultipledrag.h> +#include <kpanelapplet.h> +#include <kurldrag.h> + +#include "global.h" +#include "appletop_mnu.h" + +#include "containerarea.h" +#include "panelbutton.h" +#include "bookmarksbutton.h" +#include "browserbutton.h" +#include "desktopbutton.h" +#include "extensionbutton.h" +#include "kbutton.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "kickertip.h" +#include "nonkdeappbutton.h" +#include "paneldrag.h" +#include "servicebutton.h" +#include "servicemenubutton.h" +#include "urlbutton.h" +#include "windowlistbutton.h" + +#include "container_button.h" +#include "container_button.moc" + +ButtonContainer::ButtonContainer(QPopupMenu* opMenu, QWidget* parent) + : BaseContainer(opMenu, parent) + , _button(0) + , _layout(0) + , _oldpos(0,0) +{ + setBackgroundOrigin(AncestorOrigin); +} + +bool ButtonContainer::isValid() const +{ + if (_button) + { + return _button->isValid(); + } + + return false; // Can this happen? +} + +// Buttons Shouldn't be square when larger than a certain size. +int ButtonContainer::widthForHeight(int height) const +{ + if (isValid()) + { + return _button->widthForHeight(height); + } + + return height; +} + +int ButtonContainer::heightForWidth(int width) const +{ + if (isValid()) + { + return _button->heightForWidth(width); + } + + return width; +} + +void ButtonContainer::setBackground() +{ + PanelButton* b = button(); + if (!b) + return; + + b->unsetPalette(); +} + +void ButtonContainer::configure() +{ + if (_button) + { + _button->configure(); + } +} + +void ButtonContainer::doSaveConfiguration(KConfigGroup& config, bool layoutOnly) const +{ + // immutability is checked by ContainerBase + if (_button && !layoutOnly) + { + _button->saveConfig(config); + } +} + +void ButtonContainer::setPopupDirection(KPanelApplet::Direction d) +{ + BaseContainer::setPopupDirection(d); + + if (_button) + { + _button->setPopupDirection(d); + } +} + +void ButtonContainer::setOrientation(Orientation o) +{ + BaseContainer::setOrientation(o); + + if(_button) + _button->setOrientation(o); +} + +void ButtonContainer::embedButton(PanelButton* b) +{ + if (!b) return; + + delete _layout; + _layout = new QVBoxLayout(this); + _button = b; + + _button->installEventFilter(this); + _layout->add(_button); + connect(_button, SIGNAL(requestSave()), SIGNAL(requestSave())); + connect(_button, SIGNAL(hideme(bool)), SLOT(hideRequested(bool))); + connect(_button, SIGNAL(removeme()), SLOT(removeRequested())); + connect(_button, SIGNAL(dragme(const QPixmap)), + SLOT(dragButton(const QPixmap))); + connect(_button, SIGNAL(dragme(const KURL::List, const QPixmap)), + SLOT(dragButton(const KURL::List, const QPixmap))); +} + +QPopupMenu* ButtonContainer::createOpMenu() +{ + return new PanelAppletOpMenu(_actions, appletOpMenu(), 0, _button->title(), + _button->icon(), this); +} + +void ButtonContainer::removeRequested() +{ + if (isImmutable()) + { + return; + } + + emit removeme(this); +} + +void ButtonContainer::hideRequested(bool shouldHide) +{ + if (shouldHide) + { + hide(); + } + else + { + show(); + } +} + +void ButtonContainer::dragButton(const KURL::List urls, const QPixmap icon) +{ + if (isImmutable()) + { + return; + } + + KMultipleDrag* dd = new KMultipleDrag(this); + dd->addDragObject(new KURLDrag(urls, 0)); + dd->addDragObject(new PanelDrag(this, 0)); + dd->setPixmap(icon); + grabKeyboard(); + dd->dragMove(); + releaseKeyboard(); +} + +void ButtonContainer::dragButton(const QPixmap icon) +{ + PanelDrag* dd = new PanelDrag(this, this); + dd->setPixmap(icon); + grabKeyboard(); + dd->drag(); + releaseKeyboard(); +} + +bool ButtonContainer::eventFilter(QObject *o, QEvent *e) +{ + if (o == _button && e->type() == QEvent::MouseButtonPress) + { + static bool sentinal = false; + + if (sentinal) + { + return false; + } + + sentinal = true; + QMouseEvent* me = static_cast<QMouseEvent*>(e); + switch (me->button()) + { + case MidButton: + { + if (isImmutable()) + { + break; + } + + _button->setDown(true); + _moveOffset = me->pos(); + emit moveme(this); + sentinal = false; + return true; + } + + case RightButton: + { + if (!kapp->authorizeKAction("kicker_rmb") || + isImmutable()) + { + break; + } + + QPopupMenu* menu = opMenu(); + connect( menu, SIGNAL( aboutToHide() ), this, SLOT( slotMenuClosed() ) ); + QPoint pos = KickerLib::popupPosition(popupDirection(), menu, this, + (orientation() == Horizontal) ? + QPoint(0, 0) : me->pos()); + + Kicker::the()->setInsertionPoint(me->globalPos()); + + KickerTip::enableTipping(false); + switch (menu->exec(pos)) + { + case PanelAppletOpMenu::Move: + _moveOffset = rect().center(); + emit moveme(this); + break; + case PanelAppletOpMenu::Remove: + emit removeme(this); + break; + case PanelAppletOpMenu::Help: + help(); + break; + case PanelAppletOpMenu::About: + about(); + break; + case PanelAppletOpMenu::Preferences: + if (_button) + { + _button->properties(); + } + break; + default: + break; + } + KickerTip::enableTipping(true); + + Kicker::the()->setInsertionPoint(QPoint()); + clearOpMenu(); + sentinal = false; + return true; + } + + default: + break; + } + + sentinal = false; + } + return false; +} + +void ButtonContainer::completeMoveOperation() +{ + if (_button) + { + _button->setDown(false); + setBackground(); + } +} + +void ButtonContainer::slotMenuClosed() +{ + if (_button) + _button->setDown(false); +} + +void ButtonContainer::checkImmutability(const KConfigGroup& config) +{ + m_immutable = config.groupIsImmutable() || + config.entryIsImmutable("ConfigFile") || + config.entryIsImmutable("FreeSpace2"); +} + +// KMenuButton containerpan +KMenuButtonContainer::KMenuButtonContainer(const KConfigGroup& config, QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new KButton(this) ); + _actions = PanelAppletOpMenu::KMenuEditor; +} + +KMenuButtonContainer::KMenuButtonContainer(QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new KButton(this) ); + _actions = PanelAppletOpMenu::KMenuEditor; +} + +int KMenuButtonContainer::heightForWidth( int width ) const +{ + if ( width < 32 ) + return width + 10; + else + return ButtonContainer::heightForWidth(width); +} + +// DesktopButton container +DesktopButtonContainer::DesktopButtonContainer(QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new DesktopButton(this) ); +} + +DesktopButtonContainer::DesktopButtonContainer(const KConfigGroup& config, + QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new DesktopButton(this) ); +} + +// ServiceButton container +ServiceButtonContainer::ServiceButtonContainer( const QString& desktopFile, + QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new ServiceButton( desktopFile, this ) ); + _actions = KPanelApplet::Preferences; +} + +ServiceButtonContainer::ServiceButtonContainer( const KService::Ptr &service, + QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new ServiceButton( service, this ) ); + _actions = KPanelApplet::Preferences; +} + +ServiceButtonContainer::ServiceButtonContainer( const KConfigGroup& config, + QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new ServiceButton( config, this ) ); + _actions = KPanelApplet::Preferences; +} + +QString ServiceButtonContainer::icon() const +{ + return button()->icon(); +} + +QString ServiceButtonContainer::visibleName() const +{ + return button()->title(); +} + +// URLButton container +URLButtonContainer::URLButtonContainer( const QString& url, QPopupMenu* opMenu, QWidget* parent ) + : ButtonContainer(opMenu, parent) +{ + embedButton( new URLButton( url, this ) ); + _actions = KPanelApplet::Preferences; +} + +URLButtonContainer::URLButtonContainer( const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new URLButton( config, this ) ); + _actions = KPanelApplet::Preferences; +} + +QString URLButtonContainer::icon() const +{ + return button()->icon(); +} + +QString URLButtonContainer::visibleName() const +{ + return button()->title(); +} + +// BrowserButton container +BrowserButtonContainer::BrowserButtonContainer(const QString &startDir, QPopupMenu* opMenu, const QString& icon, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new BrowserButton(icon, startDir, this) ); + _actions = KPanelApplet::Preferences; +} + +BrowserButtonContainer::BrowserButtonContainer( const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new BrowserButton(config, this) ); + _actions = KPanelApplet::Preferences; +} + +// ServiceMenuButton container +ServiceMenuButtonContainer::ServiceMenuButtonContainer(const QString& relPath, QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new ServiceMenuButton(relPath, this) ); +} + +ServiceMenuButtonContainer::ServiceMenuButtonContainer( const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new ServiceMenuButton(config, this) ); +} + +QString ServiceMenuButtonContainer::icon() const +{ + return button()->icon(); +} + +QString ServiceMenuButtonContainer::visibleName() const +{ + return button()->title(); +} + +// WindowListButton container +WindowListButtonContainer::WindowListButtonContainer(const KConfigGroup& config, QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new WindowListButton(this) ); +} + +WindowListButtonContainer::WindowListButtonContainer(QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new WindowListButton(this) ); +} + +// BookmarkButton container +BookmarksButtonContainer::BookmarksButtonContainer(const KConfigGroup& config, QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new BookmarksButton(this) ); + _actions = PanelAppletOpMenu::BookmarkEditor; +} + +BookmarksButtonContainer::BookmarksButtonContainer(QPopupMenu *opMenu, QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new BookmarksButton(this) ); + _actions = PanelAppletOpMenu::BookmarkEditor; +} + +// NonKDEAppButton container +NonKDEAppButtonContainer::NonKDEAppButtonContainer(const QString &name, + const QString &description, + const QString &filePath, + const QString &icon, + const QString &cmdLine, + bool inTerm, + QPopupMenu* opMenu, + QWidget* parent) + : ButtonContainer(opMenu, parent) +{ + embedButton(new NonKDEAppButton(name, description, filePath, icon, cmdLine, + inTerm, this)); + _actions = KPanelApplet::Preferences; +} + +NonKDEAppButtonContainer::NonKDEAppButtonContainer( const KConfigGroup& config, QPopupMenu* opMenu, QWidget *parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new NonKDEAppButton(config, this) ); + _actions = KPanelApplet::Preferences; +} + +// ExtensionButton container +ExtensionButtonContainer::ExtensionButtonContainer(const QString& df, QPopupMenu* opMenu, QWidget *parent) + : ButtonContainer(opMenu, parent) +{ + embedButton( new ExtensionButton(df, this) ); +} + +ExtensionButtonContainer::ExtensionButtonContainer( const KConfigGroup& config, QPopupMenu* opMenu, QWidget *parent) + : ButtonContainer(opMenu, parent) +{ + checkImmutability(config); + embedButton( new ExtensionButton(config, this) ); +} + +QString ExtensionButtonContainer::icon() const +{ + return button()->icon(); +} + +QString ExtensionButtonContainer::visibleName() const +{ + return button()->title(); +} + diff --git a/kicker/kicker/core/container_button.h b/kicker/kicker/core/container_button.h new file mode 100644 index 000000000..737271216 --- /dev/null +++ b/kicker/kicker/core/container_button.h @@ -0,0 +1,195 @@ +/***************************************************************** + +Copyright (c) 1996-2003 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __container_button_h__ +#define __container_button_h__ + +#include <klocale.h> +#include <kservice.h> +#include <kurl.h> + +#include "container_base.h" + +class QLayout; +class PanelButton; +class KConfigGroup; + +class ButtonContainer : public BaseContainer +{ + Q_OBJECT + +public: + ButtonContainer(QPopupMenu* opMenu, QWidget* parent = 0); + + virtual bool isValid() const; + virtual bool isAMenu() const { return false; } + + virtual int widthForHeight(int height) const; + virtual int heightForWidth(int width) const; + + virtual void setBackground(); + + virtual void configure(); + + bool eventFilter (QObject *, QEvent *); + virtual void completeMoveOperation(); + + PanelButton* button() const { return _button; } + +public slots: + void setPopupDirection(KPanelApplet::Direction d); + void setOrientation(KPanelExtension::Orientation o); + +protected slots: + void slotMenuClosed(); + void removeRequested(); + void hideRequested(bool); + void dragButton(const KURL::List urls, const QPixmap icon); + void dragButton(const QPixmap icon); + +protected: + virtual void doSaveConfiguration( KConfigGroup&, bool layoutOnly ) const; + void embedButton(PanelButton* p); + QPopupMenu* createOpMenu(); + void checkImmutability(const KConfigGroup&); + +protected: + PanelButton *_button; + QLayout *_layout; + QPoint _oldpos; +}; + +class KMenuButtonContainer : public ButtonContainer +{ +public: + KMenuButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + KMenuButtonContainer(QPopupMenu* opMenu, QWidget* parent = 0); + virtual QString appletType() const { return "KMenuButton"; } + virtual QString icon() const { return "kmenu"; } + virtual QString visibleName() const { return i18n("K Menu"); } + + virtual int heightForWidth( int width ) const; + bool isAMenu() const { return true; } +}; + +class DesktopButtonContainer : public ButtonContainer +{ +public: + DesktopButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + DesktopButtonContainer(QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "DesktopButton"; } + virtual QString icon() const { return "desktop"; } + virtual QString visibleName() const { return i18n("Desktop Access"); } +}; + +class ServiceButtonContainer : public ButtonContainer +{ +public: + ServiceButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + ServiceButtonContainer(const KService::Ptr & service, QPopupMenu* opMenu,QWidget* parent = 0); + ServiceButtonContainer(const QString& desktopFile, QPopupMenu* opMenu,QWidget* parent = 0); + QString appletType() const { return "ServiceButton"; } + virtual QString icon() const; + virtual QString visibleName() const; +}; + +class URLButtonContainer : public ButtonContainer +{ +public: + URLButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + URLButtonContainer(const QString& url, QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "URLButton"; } + virtual QString icon() const; + virtual QString visibleName() const; +}; + +class BrowserButtonContainer : public ButtonContainer +{ +public: + BrowserButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + BrowserButtonContainer(const QString& startDir, QPopupMenu* opMenu, const QString& icon = "kdisknav", QWidget* parent = 0); + QString appletType() const { return "BrowserButton"; } + virtual QString icon() const { return "kdisknav"; } + virtual QString visibleName() const { return i18n("Quick Browser"); } + bool isAMenu() const { return true; } +}; + +class ServiceMenuButtonContainer : public ButtonContainer +{ +public: + ServiceMenuButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + ServiceMenuButtonContainer(const QString& relPath, QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "ServiceMenuButton"; } + virtual QString icon() const; + virtual QString visibleName() const; + bool isAMenu() const { return true; } +}; + +class WindowListButtonContainer : public ButtonContainer +{ +public: + WindowListButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + WindowListButtonContainer(QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "WindowListButton"; } + virtual QString icon() const { return "window_list"; } + virtual QString visibleName() const { return i18n("Windowlist"); } + bool isAMenu() const { return true; } +}; + +class BookmarksButtonContainer : public ButtonContainer +{ +public: + BookmarksButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget* parent = 0); + BookmarksButtonContainer(QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "BookmarksButton"; } + virtual QString icon() const { return "bookmark"; } + virtual QString visibleName() const { return i18n("Bookmarks"); } + bool isAMenu() const { return true; } +}; + +class NonKDEAppButtonContainer : public ButtonContainer +{ +public: + NonKDEAppButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget *parent=0); + NonKDEAppButtonContainer(const QString &name, const QString &description, + const QString &filePath, const QString &icon, + const QString &cmdLine, bool inTerm, + QPopupMenu* opMenu, QWidget* parent = 0); + QString appletType() const { return "ExecButton"; } + virtual QString icon() const { return "exec"; } + virtual QString visibleName() const { return i18n("Non-KDE Application"); } +}; + +class ExtensionButtonContainer : public ButtonContainer +{ +public: + ExtensionButtonContainer(const KConfigGroup& config, QPopupMenu* opMenu, QWidget *parent=0); + ExtensionButtonContainer(const QString& desktopFile, QPopupMenu* opMenu, QWidget *parent= 0); + QString appletType() const { return "ExtensionButton"; } + virtual QString icon() const; + virtual QString visibleName() const; + bool isAMenu() const { return true; } +}; + +#endif + diff --git a/kicker/kicker/core/container_extension.cpp b/kicker/kicker/core/container_extension.cpp new file mode 100644 index 000000000..694513109 --- /dev/null +++ b/kicker/kicker/core/container_extension.cpp @@ -0,0 +1,2067 @@ +/***************************************************************** + +Copyright (c) 2004-2005 Aaron J. Seigo <aseigo@kde.org> +Copyright (c) 2000-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ +#include <stdlib.h> +#include <math.h> + +#include <qcursor.h> +#include <qfile.h> +#include <qlayout.h> +#include <qmovie.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qtooltip.h> +#include <qvbox.h> +#include <qxembed.h> +#include <qcolor.h> + +#include <dcopclient.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kglobal.h> +#include <kicker.h> +#include <kstandarddirs.h> +#include <kwin.h> +#include <klocale.h> +#include <kglobalsettings.h> +#include <kapplication.h> +#include <netwm.h> +#include <fixx11h.h> +#include <kwinmodule.h> + +#include "container_base.h" +#include "extensionmanager.h" +#include "extensionop_mnu.h" +#include "hidebutton.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "kickertip.h" +#include "pluginmanager.h" +#include "userrectsel.h" + +#include "container_extension.h" + +/* 1 is the initial speed, hide_show_animation is the top speed. */ +#define PANEL_SPEED(x, c) (int)((1.0-2.0*fabs((x)-(c)/2.0)/c)*m_settings.hideAnimationSpeed()+1.0) + +ExtensionContainer::ExtensionContainer(const AppletInfo& info, + const QString& extensionId, + QWidget *parent) + : QFrame(parent, ("ExtensionContainer#" + extensionId).latin1(), WStyle_Customize | WStyle_NoBorder), + m_settings(KSharedConfig::openConfig(info.configFile())), + m_hideMode(ManualHide), + m_unhideTriggeredAt(UnhideTrigger::None), + _autoHidden(false), + _userHidden(Unhidden), + _block_user_input(false), + _is_lmb_down(false), + _in_autohide(false), + _id(extensionId), + _opMnu(0), + _info(info), + _ltHB(0), + _rbHB(0), + m_extension(0), + m_maintainFocus(0), + m_panelOrder(ExtensionManager::the()->nextPanelOrder()) +{ + // now actually try to load the extension + m_extension = PluginManager::the()->loadExtension(info, this); + init(); +} + +ExtensionContainer::ExtensionContainer(KPanelExtension* extension, + const AppletInfo& info, + const QString& extensionId, + QWidget *parent) + : QFrame(parent, ("ExtensionContainer#" + extensionId).latin1(), WStyle_Customize | WStyle_NoBorder), + m_settings(KSharedConfig::openConfig(info.configFile())), + _autoHidden(false), + _userHidden(Unhidden), + _block_user_input(false), + _is_lmb_down(false), + _in_autohide(false), + _id(extensionId), + _opMnu(0), + _info(info), + _ltHB(0), + _rbHB(0), + m_extension(extension), + m_maintainFocus(0), + m_panelOrder(ExtensionManager::the()->nextPanelOrder()) +{ + m_extension->reparent(this, QPoint(0, 0)); + init(); +} + +void ExtensionContainer::init() +{ + // panels live in the dock + KWin::setType(winId(), NET::Dock); + KWin::setState(winId(), NET::Sticky); + KWin::setOnAllDesktops(winId(), true); + + connect(Kicker::the()->kwinModule(), SIGNAL(strutChanged()), this, SLOT(strutChanged())); + connect(Kicker::the()->kwinModule(), SIGNAL(currentDesktopChanged(int)), + this, SLOT( currentDesktopChanged(int))); + + setBackgroundOrigin(AncestorOrigin); + setFrameStyle(NoFrame); + setLineWidth(0); + setMargin(0); + + connect(UnhideTrigger::the(), SIGNAL(triggerUnhide(UnhideTrigger::Trigger,int)), + this, SLOT(unhideTriggered(UnhideTrigger::Trigger,int))); + + _popupWidgetFilter = new PopupWidgetFilter( this ); + connect(_popupWidgetFilter, SIGNAL(popupWidgetHiding()), SLOT(maybeStartAutoHideTimer())); + + // layout + _layout = new QGridLayout(this, 3, 3, 0, 0); + _layout->setResizeMode(QLayout::FreeResize); + _layout->setRowStretch(1,10); + _layout->setColStretch(1,10); + + // instantiate the autohide timer + _autohideTimer = new QTimer(this, "_autohideTimer"); + connect(_autohideTimer, SIGNAL(timeout()), SLOT(autoHideTimeout())); + + // instantiate the updateLayout event compressor timer + _updateLayoutTimer = new QTimer(this, "_updateLayoutTimer"); + connect(_updateLayoutTimer, SIGNAL(timeout()), SLOT(actuallyUpdateLayout())); + + installEventFilter(this); // for mouse event handling + + connect(Kicker::the(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(updateHighlightColor())); + updateHighlightColor(); + + // if we were hidden when kicker quit, let's start out hidden as well! + KConfig *config = KGlobal::config(); + config->setGroup(extensionId()); + int tmp = config->readNumEntry("UserHidden", Unhidden); + if (tmp > Unhidden && tmp <= RightBottom) + { + _userHidden = static_cast<UserHidden>(tmp); + } + + if (m_extension) + { + // if we have an extension, we need to grab the extension-specific + // defaults for position, size and custom size and override the + // defaults in the settings object since the extension may differ + // from the "normal" panels. for example, the universal sidebar's + // preferred position is the left, not the bottom/top + KConfigSkeleton::ItemInt* item = dynamic_cast<KConfigSkeleton::ItemInt*>(m_settings.findItem("Position")); + if (item) + { + KPanelExtension::Position p = m_extension->preferedPosition(); + item->setDefaultValue(p); + item->readConfig(m_settings.config()); + } + + item = dynamic_cast<KConfigSkeleton::ItemInt*>(m_settings.findItem("Size")); + if (item) + { + item->setDefaultValue(m_extension->sizeSetting()); + } + + item = dynamic_cast<KConfigSkeleton::ItemInt*>(m_settings.findItem("CustomSize")); + if (item) + { + item->setDefaultValue(m_extension->customSize()); + } + + connect(m_extension, SIGNAL(updateLayout()), SLOT(updateLayout())); + connect(m_extension, SIGNAL(maintainFocus(bool)), + SLOT(maintainFocus(bool))); + + _layout->addWidget(m_extension, 1, 1); + } + + if (!m_settings.iExist()) + { + m_settings.setIExist(true); + m_settings.writeConfig(); + } +} + +ExtensionContainer::~ExtensionContainer() +{ +} + +QSize ExtensionContainer::sizeHint(KPanelExtension::Position p, const QSize &maxSize) const +{ + int width = 0; + int height = 0; + if (p == KPanelExtension::Top || p == KPanelExtension::Bottom) + { + if (needsBorder()) + { + height += 1; // border + } + + if (m_settings.showLeftHideButton()) + { + width += m_settings.hideButtonSize(); + } + + if (m_settings.showRightHideButton()) + { + width += m_settings.hideButtonSize(); + } + + // don't forget we might have a border! + width += _layout->colSpacing(0) + _layout->colSpacing(2); + } + else + { + if (needsBorder()) + { + width += 1; // border + } + + if (m_settings.showLeftHideButton()) + { + height += m_settings.hideButtonSize(); + } + + if (m_settings.showRightHideButton()) + { + height += m_settings.hideButtonSize(); + } + + // don't forget we might have a border! + height += _layout->rowSpacing(0) + _layout->rowSpacing(2); + } + + QSize size(width, height); + size = size.boundedTo(maxSize); + + if (m_extension) + { + size = m_extension->sizeHint(p, maxSize - size) + size; + } + + return size.boundedTo(maxSize); +} + +static bool isnetwm12_below() +{ + NETRootInfo info( qt_xdisplay(), NET::Supported ); + return info.supportedProperties()[ NETRootInfo::STATES ] & NET::KeepBelow; +} + +void ExtensionContainer::readConfig() +{ +// kdDebug(1210) << "ExtensionContainer::readConfig()" << endl; + m_settings.readConfig(); + + if (m_settings.autoHidePanel()) + { + m_hideMode = AutomaticHide; + } + else if (m_settings.backgroundHide()) + { + m_hideMode = BackgroundHide; + } + else + { + m_hideMode = ManualHide; + } + + positionChange(position()); + alignmentChange(alignment()); + setSize(static_cast<KPanelExtension::Size>(m_settings.size()), + m_settings.customSize()); + + if (m_hideMode != AutomaticHide) + { + autoHide(false); + } + + static bool netwm12 = isnetwm12_below(); + if (netwm12) // new netwm1.2 compliant way + { + if (m_hideMode == BackgroundHide) + { + KWin::setState( winId(), NET::KeepBelow ); + UnhideTrigger::the()->setEnabled( true ); + } + else + { + KWin::clearState( winId(), NET::KeepBelow ); + } + } + else if (m_hideMode == BackgroundHide) + { + // old way + KWin::clearState( winId(), NET::StaysOnTop ); + UnhideTrigger::the()->setEnabled( true ); + } + else + { + // the other old way + KWin::setState( winId(), NET::StaysOnTop ); + } + + actuallyUpdateLayout(); + maybeStartAutoHideTimer(); +} + +void ExtensionContainer::writeConfig() +{ +// kdDebug(1210) << "ExtensionContainer::writeConfig()" << endl; + KConfig *config = KGlobal::config(); + config->setGroup(extensionId()); + + config->writePathEntry("ConfigFile", _info.configFile()); + config->writePathEntry("DesktopFile", _info.desktopFile()); + config->writeEntry("UserHidden", userHidden()); + + m_settings.writeConfig(); +} + +void ExtensionContainer::showPanelMenu( const QPoint& globalPos ) +{ + if (!kapp->authorizeKAction("kicker_rmb")) + { + return; + } + + if (m_extension && m_extension->customMenu()) + { + // use the extenion's own custom menu + Kicker::the()->setInsertionPoint(globalPos); + m_extension->customMenu()->exec(globalPos); + Kicker::the()->setInsertionPoint(QPoint()); + return; + } + + if (!_opMnu) + { + KDesktopFile f(KGlobal::dirs()->findResource("extensions", _info.desktopFile())); + _opMnu = new PanelExtensionOpMenu(f.readName(), + m_extension ? m_extension->actions() : 0, + this); + } + + QPopupMenu *menu = KickerLib::reduceMenu(_opMnu); + + Kicker::the()->setInsertionPoint(globalPos); + + switch (menu->exec(globalPos)) + { + case PanelExtensionOpMenu::Remove: + emit removeme(this); + break; + case PanelExtensionOpMenu::About: + about(); + break; + case PanelExtensionOpMenu::Help: + help(); + break; + case PanelExtensionOpMenu::Preferences: + preferences(); + break; + case PanelExtensionOpMenu::ReportBug: + reportBug(); + break; + default: + break; + } + Kicker::the()->setInsertionPoint(QPoint()); +} + +void ExtensionContainer::about() +{ + if (!m_extension) + { + return; + } + + m_extension->action(KPanelExtension::About); +} + +void ExtensionContainer::help() +{ + if (!m_extension) + { + return; + } + + m_extension->action(KPanelExtension::Help); +} + +void ExtensionContainer::preferences() +{ + if (!m_extension) + { + return; + } + + m_extension->action(KPanelExtension::Preferences); +} + +void ExtensionContainer::reportBug() +{ + if (!m_extension) + { + return; + } + + m_extension->action(KPanelExtension::ReportBug); +} + +void ExtensionContainer::removeSessionConfigFile() +{ + if (_info.configFile().isEmpty() || _info.isUniqueApplet()) + { + return; + } + + if (QFile::exists(locate("config", _info.configFile()))) + { + QFile::remove(locate("config", _info.configFile())); + } +} + +void ExtensionContainer::moveMe() +{ + int screen = xineramaScreen(); + if (screen < 0) + { + screen = kapp->desktop()->screenNumber(this); + } + + if (screen < 0) + { + // we aren't on any screen? um. ok. + return; + } + + stopAutoHideTimer(); + + QApplication::syncX(); + UserRectSel::RectList rects; + + KPanelExtension::Position positions[] = { KPanelExtension::Left, + KPanelExtension::Right, + KPanelExtension::Top, + KPanelExtension::Bottom }; + KPanelExtension::Alignment alignments[] = { KPanelExtension::LeftTop, + KPanelExtension::Center, + KPanelExtension::RightBottom }; + + for (int s = 0; s < QApplication::desktop()->numScreens(); s++) + { + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 3; j++) + { + // FIXME: + // asking for initial geometry here passes bogus heightForWidth + // and widthForHeight requests to applets and buttons. if they + // need to make layout adjustments or need to calculate based + // on other parameters this can lead to Bad Things(tm) + // + // we need to find a way to do this that doesn't result in + // sizeHint's getting called on the extension =/ + // + // or else we need to change the semantics for applets so that + // they don't get their "you're changing position" signals through + // heightForWidth/widthForHeight + rects.append(UserRectSel::PanelStrut(initialGeometry(positions[i], + alignments[j], s), + s, positions[i], alignments[j])); + } + } + } + + UserRectSel::PanelStrut newStrut = UserRectSel::select(rects, rect().center(), m_highlightColor); + arrange(newStrut.m_pos, newStrut.m_alignment, newStrut.m_screen); + + _is_lmb_down = false; + + // sometimes the HB's are not reset correctly + if (_ltHB) + { + _ltHB->setDown(false); + } + + if (_rbHB) + { + _rbHB->setDown(false); + } + + maybeStartAutoHideTimer(); +} + +void ExtensionContainer::updateLayout() +{ + /* + m_extension == 0 can happen for example if the constructor of a panel + extension calls adjustSize(), resulting in a sendPostedEvents on the parent (us) and + therefore this call. Happens with ksim for example. One can argue about ksim here, but + kicker shouldn't crash in any case. + */ + if (!m_extension || _updateLayoutTimer->isActive()) + { + return; + } + + // don't update our layout more than once every half a second... + if (_in_autohide) + { + // ... unless we are autohiding + _updateLayoutTimer->start(0,true); + } + else + { + _updateLayoutTimer->start(500,true); + } +} + +void ExtensionContainer::actuallyUpdateLayout() +{ +// kdDebug(1210) << "PanelContainer::updateLayout()" << endl; + resetLayout(); + updateWindowManager(); +} + +void ExtensionContainer::enableMouseOverEffects() +{ + KickerTip::enableTipping(true); + QPoint globalPos = QCursor::pos(); + QPoint localPos = mapFromGlobal(globalPos); + QWidget* child = childAt(localPos); + + if (child) + { + QMouseEvent* e = new QMouseEvent(QEvent::Enter, localPos, globalPos, 0, 0); + qApp->sendEvent(child, e); + } +} + +bool ExtensionContainer::shouldUnhideForTrigger(UnhideTrigger::Trigger t) const +{ + int loc = m_settings.unhideLocation(); + + if (loc == t) + { + return true; + } + + if (loc == UnhideTrigger::Bottom) + { + return t == UnhideTrigger::BottomLeft || + t == UnhideTrigger::BottomRight; + } + else if (loc == UnhideTrigger::Top) + { + return t == UnhideTrigger::TopLeft || + t == UnhideTrigger::TopRight; + } + else if (loc == UnhideTrigger::Left) + { + return t == UnhideTrigger::TopLeft || + t == UnhideTrigger::BottomLeft; + } + else if (loc == UnhideTrigger::Right) + { + return t == UnhideTrigger::TopRight || + t == UnhideTrigger::BottomRight; + } + + return false; +} + +void ExtensionContainer::unhideTriggered(UnhideTrigger::Trigger tr, int XineramaScreen) +{ + if (m_hideMode == ManualHide) + { + return; + } + else if (tr == UnhideTrigger::None) + { + if (m_settings.unhideLocation() != UnhideTrigger::None && _autoHidden) + { + UnhideTrigger::the()->setEnabled(false); + } + + m_unhideTriggeredAt = UnhideTrigger::None; + return; + } + + if (xineramaScreen() != XineramaAllScreens && + XineramaScreen != xineramaScreen()) + { + if (m_settings.unhideLocation() != UnhideTrigger::None) + { + m_unhideTriggeredAt = tr; + } + return; + } + + // here we handle the case where the user has defined WHERE + // the pannel can be popped up from. + if (m_settings.unhideLocation() != UnhideTrigger::None) + { + if (_autoHidden) + { + UnhideTrigger::the()->setEnabled(true); + } + + m_unhideTriggeredAt = tr; + if (shouldUnhideForTrigger(tr)) + { + UnhideTrigger::the()->triggerAccepted(tr, XineramaScreen); + + if (m_hideMode == BackgroundHide) + { + KWin::raiseWindow(winId()); + } + else if (_autoHidden) + { + autoHide(false); + maybeStartAutoHideTimer(); + } + } + + return; + } + + m_unhideTriggeredAt = UnhideTrigger::None; + + // Otherwise hide mode is automatic. The code below is slightly + // complex so as to keep the same behavior as it has always had: + // only unhide when the cursor position is within the widget geometry. + // We can't just do geometry().contains(QCursor::pos()) because + // now we hide the panel completely off screen. + + int x = QCursor::pos().x(); + int y = QCursor::pos().y(); + int t = geometry().top(); + int b = geometry().bottom(); + int r = geometry().right(); + int l = geometry().left(); + if (((tr == UnhideTrigger::Top || + tr == UnhideTrigger::TopLeft || + tr == UnhideTrigger::TopRight) && + position() == KPanelExtension::Top && x >= l && x <= r) || + ((tr == UnhideTrigger::Left || + tr == UnhideTrigger::TopLeft || + tr == UnhideTrigger::BottomLeft) && + position() == KPanelExtension::Left && y >= t && y <= b) || + ((tr == UnhideTrigger::Bottom || + tr == UnhideTrigger::BottomLeft || + tr == UnhideTrigger::BottomRight) && + position() == KPanelExtension::Bottom && x >= l && x <= r ) || + ((tr == UnhideTrigger::Right || + tr == UnhideTrigger::TopRight || + tr == UnhideTrigger::BottomRight) && + position() == KPanelExtension::Right && y >= t && y <= b )) + { + UnhideTrigger::the()->triggerAccepted(tr, XineramaScreen); + + if (_autoHidden) + { + autoHide(false); + maybeStartAutoHideTimer(); + } + else if (m_hideMode == BackgroundHide) + { + KWin::raiseWindow(winId()); + } + } +} + +void ExtensionContainer::autoHideTimeout() +{ +// kdDebug(1210) << "PanelContainer::autoHideTimeout() " << name() << endl; + // Hack: If there is a popup open, don't autohide until it closes. + QWidget* popup = QApplication::activePopupWidget(); + if (popup) + { + + // kdDebug(1210) << "popup detected" << endl; + + // Remove it first in case it was already installed. + // Does nothing if it wasn't installed. + popup->removeEventFilter( _popupWidgetFilter ); + + // We will get a signal from the filter after the + // popup is hidden. At that point, maybeStartAutoHideTimer() + // will get called again. + popup->installEventFilter( _popupWidgetFilter ); + + // Stop the timer. + stopAutoHideTimer(); + return; + } + + if (m_hideMode != AutomaticHide || + _autoHidden || + _userHidden || + m_maintainFocus > 0) + { + return; + } + + QRect r = geometry(); + QPoint p = QCursor::pos(); + if (!r.contains(p) && + (m_settings.unhideLocation() == UnhideTrigger::None || + !shouldUnhideForTrigger(m_unhideTriggeredAt))) + { + stopAutoHideTimer(); + autoHide(true); + UnhideTrigger::the()->resetTriggerThrottle(); + } +} + +void ExtensionContainer::hideLeft() +{ + animatedHide(true); +} + +void ExtensionContainer::hideRight() +{ + animatedHide(false); +} + +void ExtensionContainer::autoHide(bool hide) +{ +// kdDebug(1210) << "PanelContainer::autoHide( " << hide << " )" << endl; + + if (_in_autohide || hide == _autoHidden) + { + return; + } + + // kdDebug(1210) << "entering autohide for real" << endl; + + blockUserInput(true); + + QPoint oldpos = pos(); + QRect newextent = initialGeometry( position(), alignment(), xineramaScreen(), hide, Unhidden ); + QPoint newpos = newextent.topLeft(); + + if (hide) + { + /* bail out if we are unable to hide */ + + for (int s=0; s < QApplication::desktop()->numScreens(); s++) + { + /* don't let it intersect with any screen in the hidden position + * that it doesn't intesect in the shown position. Should prevent + * panels from hiding by sliding onto other screens, while still + * letting them show reveal buttons onscreen */ + QRect desktopGeom = QApplication::desktop()->screenGeometry(s); + if (desktopGeom.intersects(newextent) && + !desktopGeom.intersects(geometry())) + { + blockUserInput( false ); + return; + } + } + } + + _in_autohide = true; + _autoHidden = hide; + UnhideTrigger::the()->setEnabled(_autoHidden); + KickerTip::enableTipping(false); + + if (hide) + { + // So we don't cover other panels + lower(); + } + else + { + // So we aren't covered by other panels + raise(); + } + + if (m_settings.hideAnimation()) + { + if (position() == KPanelExtension::Left || position() == KPanelExtension::Right) + { + for (int i = 0; i < abs(newpos.x() - oldpos.x()); + i += PANEL_SPEED(i,abs(newpos.x() - oldpos.x()))) + { + if (newpos.x() > oldpos.x()) + { + move(oldpos.x() + i, newpos.y()); + } + else + { + move(oldpos.x() - i, newpos.y()); + } + + qApp->syncX(); + qApp->processEvents(); + } + } + else + { + for (int i = 0; i < abs(newpos.y() - oldpos.y()); + i += PANEL_SPEED(i,abs(newpos.y() - oldpos.y()))) + { + if (newpos.y() > oldpos.y()) + { + move(newpos.x(), oldpos.y() + i); + } + else + { + move(newpos.x(), oldpos.y() - i); + } + + qApp->syncX(); + qApp->processEvents(); + } + } + } + + blockUserInput(false); + + updateLayout(); + + // Sometimes tooltips don't get hidden + QToolTip::hide(); + + _in_autohide = false; + + QTimer::singleShot(100, this, SLOT(enableMouseOverEffects())); +} + +void ExtensionContainer::animatedHide(bool left) +{ +// kdDebug(1210) << "PanelContainer::animatedHide()" << endl; + KickerTip::enableTipping(false); + blockUserInput(true); + + UserHidden newState; + if (_userHidden != Unhidden) + { + newState = Unhidden; + } + else if (left) + { + newState = LeftTop; + } + else + { + newState = RightBottom; + } + + QPoint oldpos = pos(); + QRect newextent = initialGeometry(position(), alignment(), xineramaScreen(), false, newState); + QPoint newpos(newextent.topLeft()); + + if (newState != Unhidden) + { + /* bail out if we are unable to hide */ + for(int s=0; s < QApplication::desktop()->numScreens(); s++) + { + /* don't let it intersect with any screen in the hidden position + * that it doesn't intesect in the shown position. Should prevent + * panels from hiding by sliding onto other screens, while still + * letting them show reveal buttons onscreen */ + if (QApplication::desktop()->screenGeometry(s).intersects(newextent) && + !QApplication::desktop()->screenGeometry(s).intersects(geometry())) + { + blockUserInput(false); + QTimer::singleShot(100, this, SLOT(enableMouseOverEffects())); + return; + } + } + + _userHidden = newState; + + // So we don't cover the mac-style menubar + lower(); + } + + if (m_settings.hideAnimation()) + { + if (position() == KPanelExtension::Left || position() == KPanelExtension::Right) + { + for (int i = 0; i < abs(newpos.y() - oldpos.y()); + i += PANEL_SPEED(i, abs(newpos.y() - oldpos.y()))) + { + if (newpos.y() > oldpos.y()) + { + move(newpos.x(), oldpos.y() + i); + } + else + { + move(newpos.x(), oldpos.y() - i); + } + qApp->syncX(); + qApp->processEvents(); + } + } + else + { + for (int i = 0; i < abs(newpos.x() - oldpos.x()); + i += PANEL_SPEED(i, abs(newpos.x() - oldpos.x()))) + { + if (newpos.x() > oldpos.x()) + { + move(oldpos.x() + i, newpos.y()); + } + else + { + move(oldpos.x() - i, newpos.y()); + } + qApp->syncX(); + qApp->processEvents(); + } + } + } + + blockUserInput( false ); + + _userHidden = newState; + + actuallyUpdateLayout(); + qApp->syncX(); + qApp->processEvents(); + + // save our hidden status so that when kicker starts up again + // we'll come back in the same state + KConfig *config = KGlobal::config(); + config->setGroup(extensionId()); + config->writeEntry("UserHidden", userHidden()); + + QTimer::singleShot(100, this, SLOT(enableMouseOverEffects())); +} + +bool ExtensionContainer::reserveStrut() const +{ + return !m_extension || m_extension->reserveStrut(); +} + +KPanelExtension::Alignment ExtensionContainer::alignment() const +{ + // KConfigXT really needs to get support for vars that are enums that + // are defined in other classes + return static_cast<KPanelExtension::Alignment>(m_settings.alignment()); +} + +void ExtensionContainer::updateWindowManager() +{ + NETExtendedStrut strut; + + if (reserveStrut()) + { + // kdDebug(1210) << "PanelContainer::updateWindowManager()" << endl; + // Set the relevant properties on the window. + int w = 0; + int h = 0; + + QRect geom = initialGeometry(position(), alignment(), xineramaScreen()); + QRect virtRect(QApplication::desktop()->geometry()); + QRect screenRect(QApplication::desktop()->screenGeometry(xineramaScreen())); + + if (m_hideMode == ManualHide && !userHidden()) + { + w = width(); + h = height(); + } + + switch (position()) + { + case KPanelExtension::Top: + strut.top_width = geom.y() + h; + strut.top_start = x(); + strut.top_end = x() + width() - 1; + break; + + case KPanelExtension::Bottom: + // also claim the non-visible part at the bottom + strut.bottom_width = (virtRect.bottom() - geom.bottom()) + h; + strut.bottom_start = x(); + strut.bottom_end = x() + width() - 1; + break; + + case KPanelExtension::Right: + strut.right_width = (virtRect.right() - geom.right()) + w; + strut.right_start = y(); + strut.right_end = y() + height() - 1; + break; + + case KPanelExtension::Left: + strut.left_width = geom.x() + w; + strut.left_start = y(); + strut.left_end = y() + height() - 1; + break; + + case KPanelExtension::Floating: + // should never be reached, anyways + break; + } + } + + if (strut.left_width != _strut.left_width || + strut.left_start != _strut.left_start || + strut.left_end != _strut.left_end || + strut.right_width != _strut.right_width || + strut.right_start != _strut.right_start || + strut.right_end != _strut.right_end || + strut.top_width != _strut.top_width || + strut.top_start != _strut.top_start || + strut.top_end != _strut.top_end || + strut.bottom_width != _strut.bottom_width || + strut.bottom_start != _strut.bottom_start || + strut.bottom_end != _strut.bottom_end) + { + /*kdDebug(1210) << " === Panel sets new strut for pos " << position() << " ===" << endl; + + kdDebug(1210) << "strut for " << winId() << ": " << endl << + "\tleft : " << strut.left_width << " " << strut.left_start << " " << strut.left_end << endl << + "\tright : " << strut.right_width << " " << strut.right_start << " " << strut.right_end << endl << + "\ttop : " << strut.top_width << " " << strut.top_start << " " << strut.top_end << endl << + "\tbottom: " << strut.bottom_width << " " << strut.bottom_start << " " << strut.bottom_end << endl; */ + _strut = strut; + + KWin::setExtendedStrut(winId(), + strut.left_width, strut.left_start, strut.left_end, + strut.right_width, strut.right_start, strut.right_end, + strut.top_width, strut.top_start, strut.top_end, + strut.bottom_width, strut.bottom_start, strut.bottom_end); + KWin::setStrut(winId(), strut.left_width, strut.right_width, strut.top_width, strut.bottom_width); + } + /*else + { + kdDebug(1210) << "Panel strut did NOT change!" << endl; + }*/ +} + +void ExtensionContainer::currentDesktopChanged(int) +{ + // kdDebug(1210) << "PanelContainer::currentDesktopChanged" << endl; + if (m_settings.autoHideSwitch()) + { + if (m_hideMode == AutomaticHide) + { + autoHide(false); + } + else if (m_hideMode == BackgroundHide) + { + KWin::raiseWindow(winId()); + } + } + + // For some reason we don't always get leave events when the user + // changes desktops and moves the cursor out of the panel at the + // same time. Maybe always calling this will help. + maybeStartAutoHideTimer(); +} + +void ExtensionContainer::strutChanged() +{ + //kdDebug(1210) << "PanelContainer::strutChanged()" << endl; + QRect ig = currentGeometry(); + + if (ig != geometry()) + { + setGeometry(ig); + updateLayout(); + } +} + +void ExtensionContainer::blockUserInput( bool block ) +{ + if (block == _block_user_input) + { + return; + } + + // If we don't want any user input to be possible we should catch mouse + // events and such. Therefore we install an eventfilter and let the + // eventfilter discard those events. + if ( block ) + { + qApp->installEventFilter( this ); + } + else + { + qApp->removeEventFilter( this ); + } + + _block_user_input = block; +} + +void ExtensionContainer::maybeStartAutoHideTimer() +{ + if (m_hideMode != ManualHide && + !_autoHidden && + !_userHidden) + { + // kdDebug(1210) << "starting auto hide timer for " << name() << endl; + if (m_settings.autoHideDelay() == 0) + { + _autohideTimer->start(250); + } + else + { + _autohideTimer->start(m_settings.autoHideDelay() * 1000); + } + } +} + +void ExtensionContainer::stopAutoHideTimer() +{ + if (_autohideTimer->isActive()) + { + //kdDebug(1210) << "stopping auto hide timer for " << name() << endl; + _autohideTimer->stop(); + } +} + +void ExtensionContainer::maintainFocus(bool maintain) +{ + if (maintain) + { + ++m_maintainFocus; + + if (_autoHidden) + { + autoHide(false); + } + else if (_userHidden == LeftTop) + { + animatedHide(true); + } + else if (_userHidden == RightBottom) + { + animatedHide(false); + } + } + else if (m_maintainFocus > 0) + { + --m_maintainFocus; + } +} + +int ExtensionContainer::arrangeHideButtons() +{ + bool layoutEnabled = _layout->isEnabled(); + + if (layoutEnabled) + { + _layout->setEnabled(false); + } + + if (orientation() == Vertical) + { + int maxWidth = width(); + + if (needsBorder()) + { + --maxWidth; + } + + if (_ltHB) + { + _ltHB->setMaximumWidth(maxWidth); + _ltHB->setMaximumHeight(14); + _layout->remove(_ltHB); + _layout->addWidget(_ltHB, 0, 1, Qt::AlignBottom | Qt::AlignLeft); + } + + if (_rbHB) + { + _rbHB->setMaximumWidth(maxWidth); + _rbHB->setMaximumHeight(14); + _layout->remove(_rbHB); + _layout->addWidget(_rbHB, 2, 1); + } + } + else + { + int maxHeight = height(); + + if (needsBorder()) + { + --maxHeight; + } + + int vertAlignment = (position() == KPanelExtension::Top) ? Qt::AlignTop : 0; + int leftAlignment = Qt::AlignRight; + + if (_ltHB) + { + _ltHB->setMaximumHeight(maxHeight); + _ltHB->setMaximumWidth(14); + _layout->remove(_ltHB); + if (kapp->reverseLayout()) + { + _layout->addWidget(_ltHB, 1, 2, vertAlignment); + } + else + { + _layout->addWidget(_ltHB, 1, 0, leftAlignment | vertAlignment); + } + } + + if (_rbHB) + { + _rbHB->setMaximumHeight(maxHeight); + _rbHB->setMaximumWidth(14); + _layout->remove(_rbHB); + if (kapp->reverseLayout()) + { + _layout->addWidget(_rbHB, 1, 0, leftAlignment | vertAlignment); + } + else + { + _layout->addWidget(_rbHB, 1, 2, vertAlignment); + } + } + } + + int layoutOffset = setupBorderSpace(); + if (layoutEnabled) + { + _layout->setEnabled(true); + } + + return layoutOffset; +} + +int ExtensionContainer::setupBorderSpace() +{ + _layout->setRowSpacing(0, 0); + _layout->setRowSpacing(2, 0); + _layout->setColSpacing(0, 0); + _layout->setColSpacing(2, 0); + + if (!needsBorder()) + { + return 0; + } + + int layoutOffset = 0; + QRect r = QApplication::desktop()->screenGeometry(xineramaScreen()); + QRect h = geometry(); + + if (orientation() == Vertical) + { + if (h.top() > 0) + { + int topHeight = (_ltHB && _ltHB->isVisibleTo(this)) ? _ltHB->height() + 1 : 1; + _layout->setRowSpacing(0, topHeight); + ++layoutOffset; + } + + if (h.bottom() < r.bottom()) + { + int bottomHeight = (_rbHB && _rbHB->isVisibleTo(this)) ? _rbHB->height() + 1 : 1; + _layout->setRowSpacing(1, bottomHeight); + ++layoutOffset; + } + } + else + { + if (h.left() > 0) + { + int leftWidth = (_ltHB && _ltHB->isVisibleTo(this)) ? _ltHB->width() + 1 : 1; + _layout->setColSpacing(0, leftWidth); + ++layoutOffset; + } + + if (h.right() < r.right()) + { + int rightWidth = (_rbHB && _rbHB->isVisibleTo(this)) ? _rbHB->width() + 1 : 1; + _layout->setColSpacing(1, rightWidth); + ++layoutOffset; + } + } + + switch (position()) + { + case KPanelExtension::Left: + _layout->setColSpacing(2, 1); + break; + + case KPanelExtension::Right: + _layout->setColSpacing(0, 1); + break; + + case KPanelExtension::Top: + _layout->setRowSpacing(2, 1); + break; + + case KPanelExtension::Bottom: + default: + _layout->setRowSpacing(0, 1); + break; + } + + return layoutOffset; +} + +void ExtensionContainer::positionChange(KPanelExtension::Position p) +{ + arrangeHideButtons(); + + if (m_extension) + { + m_extension->setPosition(p); + } + + update(); +} + +void ExtensionContainer::updateHighlightColor() +{ + KConfig *config = KGlobal::config(); + config->setGroup("WM"); + QColor color = QApplication::palette().active().highlight(); + m_highlightColor = config->readColorEntry("activeBackground", &color); + update(); +} + +void ExtensionContainer::paintEvent(QPaintEvent *e) +{ + QFrame::paintEvent(e); + + if (needsBorder()) + { + // draw border + QPainter p(this); + if (KickerSettings::useBackgroundTheme() && KickerSettings::colorizeBackground()) + p.setPen(m_highlightColor); + else + p.setPen(palette().color(QPalette::Active, QColorGroup::Mid)); + p.drawRect(0, 0, width(), height()); + } +} + +void ExtensionContainer::leaveEvent(QEvent*) +{ + maybeStartAutoHideTimer(); +} + +void ExtensionContainer::alignmentChange(KPanelExtension::Alignment a) +{ + if (!m_extension) + { + return; + } + + m_extension->setAlignment(a); +} + +void ExtensionContainer::setSize(KPanelExtension::Size size, int custom) +{ + if (!m_extension) + { + return; + } + + m_settings.setSize(size); + m_settings.setCustomSize(custom); + m_extension->setSize(size, custom); +} + +KPanelExtension::Size ExtensionContainer::size() const +{ + // KConfigXT really needs to get support for vars that are enums that + // are defined in other classes + return static_cast<KPanelExtension::Size>(m_settings.size()); +} + +ExtensionContainer::HideMode ExtensionContainer::hideMode() const +{ + return m_hideMode; +} + +void ExtensionContainer::unhideIfHidden(int showForAtLeastHowManyMS) +{ + if (_autoHidden) + { + autoHide(false); + QTimer::singleShot(showForAtLeastHowManyMS, + this, SLOT(maybeStartAutoHideTimer())); + return; + } + + if (_userHidden == LeftTop) + { + animatedHide(true); + } + else if (_userHidden == RightBottom) + { + animatedHide(false); + } +} + +void ExtensionContainer::setHideButtons(bool showLeft, bool showRight) +{ + if (m_settings.showLeftHideButton() == showLeft && + m_settings.showRightHideButton() == showRight) + { + return; + } + + m_settings.setShowLeftHideButton(showLeft); + m_settings.setShowRightHideButton(showRight); + resetLayout(); +} + +bool ExtensionContainer::event(QEvent* e) +{ + // Update the layout when we receive a LayoutHint. This way we can adjust + // to changes of the layout of the main widget. + if (e->type() == QEvent::LayoutHint) + { + updateLayout(); + } + + return QFrame::event(e); +} + +void ExtensionContainer::closeEvent(QCloseEvent* e) +{ + // Prevent being closed via Alt-F4 + e->ignore(); +} + +void ExtensionContainer::arrange(KPanelExtension::Position p, + KPanelExtension::Alignment a, + int XineramaScreen) +{ + if (p == m_settings.position() && + a == m_settings.alignment() && + XineramaScreen == xineramaScreen()) + { + return; + } + + bool positionChanged = p != m_settings.position(); + if (positionChanged) + { + m_settings.setPosition(p); + } + else if (!needsBorder()) + { + // this ensures that the layout gets rejigged + // even if position doesn't change + _layout->setRowSpacing(0, 0); + _layout->setRowSpacing(2, 0); + _layout->setColSpacing(0, 0); + _layout->setColSpacing(2, 0); + } + + if (a != m_settings.alignment()) + { + m_settings.setAlignment(a); + setAlignment(a); + } + + if (XineramaScreen != xineramaScreen()) + { + m_settings.setXineramaScreen(XineramaScreen); + xineramaScreenChange(XineramaScreen); + } + + actuallyUpdateLayout(); + + if (positionChanged) + { + positionChange(p); + } + writeConfig(); +} + +KPanelExtension::Orientation ExtensionContainer::orientation() const +{ + if (position() == KPanelExtension::Top || position() == KPanelExtension::Bottom) + { + return Horizontal; + } + else + { + return Vertical; + } +} + +KPanelExtension::Position ExtensionContainer::position() const +{ + // KConfigXT really needs to get support for vars that are enums that + // are defined in other classes + return static_cast<KPanelExtension::Position>(m_settings.position()); +} + +void ExtensionContainer::resetLayout() +{ + QRect g = initialGeometry(position(), alignment(), xineramaScreen(), + autoHidden(), userHidden()); + + // Disable the layout while we rearrange the panel. + // Necessary because the children may be + // relayouted with the wrong size. + + _layout->setEnabled(false); + + if (geometry() != g) + { + setGeometry(g); + ExtensionManager::the()->extensionSizeChanged(this); + } + + // layout + bool haveToArrangeButtons = false; + bool showLeftHideButton = m_settings.showLeftHideButton() || userHidden() == RightBottom; + bool showRightHideButton = m_settings.showRightHideButton() || userHidden() == LeftTop; + + // left/top hide button + if (showLeftHideButton) + { + if (!_ltHB) + { + _ltHB = new HideButton(this); + _ltHB->installEventFilter(this); + _ltHB->setEnabled(true); + connect(_ltHB, SIGNAL(clicked()), this, SLOT(hideLeft())); + haveToArrangeButtons = true; + } + + if (orientation() == Horizontal) + { + _ltHB->setArrowType(Qt::LeftArrow); + _ltHB->setFixedSize(m_settings.hideButtonSize(), height()); + } + else + { + _ltHB->setArrowType(Qt::UpArrow); + _ltHB->setFixedSize(width(), m_settings.hideButtonSize()); + } + + _ltHB->show(); + } + else if (_ltHB) + { + _ltHB->hide(); + } + + // right/bottom hide button + if (showRightHideButton) + { + if (!_rbHB) + { + // right/bottom hide button + _rbHB = new HideButton(this); + _rbHB->installEventFilter(this); + _rbHB->setEnabled(true); + connect(_rbHB, SIGNAL(clicked()), this, SLOT(hideRight())); + haveToArrangeButtons = true; + } + + if ( orientation() == Horizontal) + { + _rbHB->setArrowType(Qt::RightArrow); + _rbHB->setFixedSize(m_settings.hideButtonSize(), height()); + } + else + { + _rbHB->setArrowType(Qt::DownArrow); + _rbHB->setFixedSize(width(), m_settings.hideButtonSize()); + } + + _rbHB->show(); + } + else if (_rbHB) + { + _rbHB->hide(); + } + + if (_ltHB) + { + QToolTip::remove(_ltHB); + if (userHidden()) + { + QToolTip::add(_ltHB, i18n("Show panel")); + } + else + { + QToolTip::add(_ltHB, i18n("Hide panel")); + } + } + + if (_rbHB) + { + QToolTip::remove( _rbHB ); + if (userHidden()) + { + QToolTip::add(_rbHB, i18n("Show panel")); + } + else + { + QToolTip::add(_rbHB, i18n("Hide panel")); + } + } + + updateGeometry(); + int endBorderWidth = haveToArrangeButtons ? arrangeHideButtons() : setupBorderSpace(); + + if (orientation() == Horizontal) + { + if (m_extension) + { + int maxWidth = width() - endBorderWidth; + + if (showLeftHideButton) + { + maxWidth -= _ltHB->width(); + } + + if (showRightHideButton) + { + maxWidth -= _rbHB->width(); + } + + m_extension->setMaximumWidth(maxWidth); + + if (needsBorder()) + { + m_extension->setFixedHeight(height() - 1); + } + else + { + m_extension->setFixedHeight(height()); + } + } + } + else if (m_extension) + { + int maxHeight = height() - endBorderWidth; + + if (showLeftHideButton) + { + maxHeight -= _ltHB->height(); + } + + if (showRightHideButton) + { + maxHeight -= _rbHB->height(); + } + + m_extension->setMaximumHeight(maxHeight); + + if (needsBorder()) + { + m_extension->setFixedWidth(width() - 1); + } + else + { + m_extension->setFixedWidth(width()); + } + } + + _layout->setEnabled(true); +} + +bool ExtensionContainer::needsBorder() const +{ + return !KickerSettings::transparent(); + //&& !KickerSettings::useBackgroundTheme(); +} + +QSize ExtensionContainer::initialSize(KPanelExtension::Position p, QRect workArea) const +{ + /*kdDebug(1210) << "initialSize() Work Area: (" << workArea.topLeft().x() << + ", " << workArea.topLeft().y() << ") to (" << workArea.bottomRight().x() << + ", " << workArea.bottomRight().y() << ")" << endl;*/ + + QSize hint = sizeHint(p, workArea.size()).boundedTo(workArea.size()); + int width = 0; + int height = 0; + + if (p == KPanelExtension::Left || p == KPanelExtension::Right) + { + width = hint.width(); + height = (workArea.height() * m_settings.sizePercentage()) / 100; + + if (m_settings.expandSize()) + { + height = QMAX(height, hint.height()); + } + } + else + { + width = (workArea.width() * m_settings.sizePercentage()) / 100; + height = hint.height(); + + if (m_settings.expandSize()) + { + width = QMAX( width, hint.width() ); + } + } + + return QSize(width, height); +} + +QPoint ExtensionContainer::initialLocation(KPanelExtension::Position p, + KPanelExtension::Alignment a, + int XineramaScreen, + const QSize &s, + QRect workArea, + bool autohidden, + UserHidden userHidden) const +{ + QRect wholeScreen; + if (XineramaScreen == XineramaAllScreens) + { + wholeScreen = QApplication::desktop()->geometry(); + } + else + { + wholeScreen = QApplication::desktop()->screenGeometry(XineramaScreen); + } + + /*kdDebug(1210) << "initialLocation() Work Area: (" << + workArea.topLeft().x() << ", " << + area.topLeft().y() << ") to (" << + workArea.bottomRight().x() << ", " << + workArea.bottomRight().y() << ")" << endl;*/ + + int left; + int top; + + // If the panel is horizontal + if (p == KPanelExtension::Top || p == KPanelExtension::Bottom) + { + // Get the X coordinate + switch (a) + { + case KPanelExtension::LeftTop: + left = workArea.left(); + break; + + case KPanelExtension::Center: + { + left = wholeScreen.left() + ( wholeScreen.width() - s.width() ) / 2; + int right = left + s.width(); + if (right > workArea.right()) + { + left = left - (right - workArea.right()); + } + + if (left < workArea.left()) + { + left = workArea.left(); + } + + break; + } + + case KPanelExtension::RightBottom: + left = workArea.right() - s.width() + 1; + break; + + default: + left = workArea.left(); + break; + } + + // Get the Y coordinate + if (p == KPanelExtension::Top) + { + top = workArea.top(); + } + else + { + top = workArea.bottom() - s.height() + 1; + } + } + else // vertical panel + { + // Get the Y coordinate + switch (a) + { + case KPanelExtension::LeftTop: + top = workArea.top(); + break; + + case KPanelExtension::Center: + { + top = wholeScreen.top() + ( wholeScreen.height() - s.height() ) / 2; + int bottom = top + s.height(); + if (bottom > workArea.bottom()) + { + top = top - (bottom - workArea.bottom()); + } + + if (top < workArea.top()) + { + top = workArea.top(); + } + break; + } + + case KPanelExtension::RightBottom: + top = workArea.bottom() - s.height() + 1; + break; + + default: + top = workArea.top(); + } + + // Get the X coordinate + if (p == KPanelExtension::Left) + { + left = workArea.left(); + } + else + { + left = workArea.right() - s.width() + 1; + } + } + + // Correct for auto hide + if (autohidden) + { + switch (position()) + { + case KPanelExtension::Left: + left -= s.width(); + break; + + case KPanelExtension::Right: + left += s.width(); + break; + + case KPanelExtension::Top: + top -= s.height(); + break; + + case KPanelExtension::Bottom: + default: + top += s.height(); + break; + } + // Correct for user hide + } + else if (userHidden == LeftTop) + { + if (position() == KPanelExtension::Left || position() == KPanelExtension::Right) + { + top = workArea.top() - s.height() + m_settings.hideButtonSize(); + } + else + { + left = workArea.left() - s.width() + m_settings.hideButtonSize(); + } + } + else if (userHidden == RightBottom) + { + if (position() == KPanelExtension::Left || position() == KPanelExtension::Right) + { + top = workArea.bottom() - m_settings.hideButtonSize() + 1; + } + else + { + left = workArea.right() - m_settings.hideButtonSize() + 1; + } + } + + return QPoint( left, top ); +} + +int ExtensionContainer::xineramaScreen() const +{ + // sanitize at runtime only, since many Xinerama users + // turn it on and off and don't want kicker to lose their configs + + /* -2 means all screens, -1 primary screens, the rest are valid screen numbers */ + if (XineramaAllScreens <= m_settings.xineramaScreen() && + m_settings.xineramaScreen() < QApplication::desktop()->numScreens()) + { + return m_settings.xineramaScreen(); + } + else + { + /* force invalid screen locations onto the primary screen */ + return QApplication::desktop()->primaryScreen(); + } +} + +void ExtensionContainer::setXineramaScreen(int screen) +{ + if (m_settings.isImmutable("XineramaScreen")) + { + return; + } + + arrange(position(),alignment(), screen); +} + +QRect ExtensionContainer::currentGeometry() const +{ + return initialGeometry(position(), alignment(), xineramaScreen(), + autoHidden(), userHidden()); +} + +QRect ExtensionContainer::initialGeometry(KPanelExtension::Position p, + KPanelExtension::Alignment a, + int XineramaScreen, + bool autoHidden, + UserHidden userHidden) const +{ + //RESEARCH: is there someway to cache the results of the repeated calls to this method? + + /*kdDebug(1210) << "initialGeometry() Computing geometry for " << name() << + " on screen " << XineramaScreen << endl;*/ + QRect workArea = ExtensionManager::the()->workArea(XineramaScreen, this); + QSize size = initialSize(p, workArea); + QPoint point = initialLocation(p, a, XineramaScreen, + size, workArea, + autoHidden, userHidden); + + //kdDebug(1210) << "Size: " << size.width() << " x " << size.height() << endl; + //kdDebug(1210) << "Pos: (" << point.x() << ", " << point.y() << ")" << endl; + + return QRect(point, size); +} + +bool ExtensionContainer::eventFilter( QObject*, QEvent * e) +{ + if (autoHidden()) + { + switch ( e->type() ) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + return true; // ignore; + default: + break; + } + } + + QEvent::Type eventType = e->type(); + if (_block_user_input) + { + return (eventType == QEvent::MouseButtonPress || + eventType == QEvent::MouseButtonRelease || + eventType == QEvent::MouseButtonDblClick || + eventType == QEvent::MouseMove || + eventType == QEvent::KeyPress || + eventType == QEvent::KeyRelease || + eventType == QEvent::Enter || + eventType == QEvent::Leave); + } + + switch (eventType) + { + case QEvent::MouseButtonPress: + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if ( me->button() == LeftButton ) + { + _last_lmb_press = me->globalPos(); + _is_lmb_down = true; + } + else if (me->button() == RightButton) + { + showPanelMenu(me->globalPos()); + return true; // don't crash! + } + } + break; + + case QEvent::MouseButtonRelease: + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if ( me->button() == LeftButton ) + { + _is_lmb_down = false; + } + } + break; + + case QEvent::MouseMove: + { + QMouseEvent* me = (QMouseEvent*) e; + if (_is_lmb_down && + ((me->state() & LeftButton) == LeftButton) && + !Kicker::the()->isImmutable() && + !m_settings.config()->isImmutable() && + !ExtensionManager::the()->isMenuBar(this)) + { + QPoint p(me->globalPos() - _last_lmb_press); + int x_threshold = width(); + int y_threshold = height(); + + if (x_threshold > y_threshold) + { + x_threshold = x_threshold / 3; + y_threshold *= 2; + } + else + { + y_threshold = y_threshold / 3; + x_threshold *= 2; + } + + if ((abs(p.x()) > x_threshold) || + (abs(p.y()) > y_threshold)) + { + moveMe(); + return true; + } + } + } + break; + + default: + break; + } + + return false; +} + +PopupWidgetFilter::PopupWidgetFilter( QObject *parent ) + : QObject( parent, "PopupWidgetFilter" ) +{ +} + +bool PopupWidgetFilter::eventFilter( QObject*, QEvent* e ) +{ + if (e->type() == QEvent::Hide) + { + emit popupWidgetHiding(); + } + return false; +} + +#include "container_extension.moc" + diff --git a/kicker/kicker/core/container_extension.h b/kicker/kicker/core/container_extension.h new file mode 100644 index 000000000..aebe048e6 --- /dev/null +++ b/kicker/kicker/core/container_extension.h @@ -0,0 +1,215 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __container_extension_h__ +#define __container_extension_h__ + +#include <qframe.h> +#include <qptrlist.h> + +#include <kpanelextension.h> +#include <dcopobject.h> +#include <netwm_def.h> + +#include "global.h" +#include "appletinfo.h" +#include "unhidetrigger.h" +#include "extensionSettings.h" + +class QBoxLayout; +class QGridLayout; +class QPopupMenu; +class QTimer; +class QVBox; +class QXEmbed; +class HideButton; +class KConfig; +class KWinModule; +class PopupWidgetFilter; +class PanelExtensionOpMenu; +class QColor; + +class ExtensionContainer : public QFrame +{ + Q_OBJECT + +public: + enum UserHidden { Unhidden, LeftTop, RightBottom }; + enum HideMode { ManualHide, AutomaticHide, BackgroundHide }; + + ExtensionContainer(const AppletInfo& info, + const QString& extensionId, + QWidget *parent = 0); + ExtensionContainer(KPanelExtension* extension, + const AppletInfo& info, + const QString& extensionId, + QWidget *parent = 0); + virtual ~ExtensionContainer(); + + virtual QSize sizeHint(KPanelExtension::Position, const QSize &maxSize) const; + + const AppletInfo& info() const { return _info; } + + QString extensionId() const { return _id; } + + void readConfig(); + void writeConfig(); + + virtual QString panelId() const { return extensionId(); } + + virtual void about(); + virtual void help(); + virtual void preferences(); + virtual void reportBug(); + + void removeSessionConfigFile(); + + KPanelExtension::Orientation orientation() const; + KPanelExtension::Position position() const; + void setPosition(KPanelExtension::Position p) { arrange( p, alignment(), xineramaScreen() ); } + + int xineramaScreen() const; + void setXineramaScreen(int screen); + + void setResizeableHandle( bool resizeablehandle=true ); + void setHideButtons(bool showLeft, bool showRight); + void setSize(KPanelExtension::Size size, int custom); + KPanelExtension::Size size() const; + int customSize() const { return m_settings.customSize(); } + HideMode hideMode() const; + void unhideIfHidden(int showForHowManyMS = 0); + bool reserveStrut() const; + + KPanelExtension::Alignment alignment() const; + void setAlignment(KPanelExtension::Alignment a) { arrange( position(), a, xineramaScreen() ); } + + QRect currentGeometry() const; + QRect initialGeometry(KPanelExtension::Position p, KPanelExtension::Alignment a, + int XineramaScreen, bool autoHidden = false, + UserHidden userHidden = Unhidden) const; + + bool eventFilter( QObject *, QEvent * ); + + int panelOrder() const { return m_panelOrder; } + void setPanelOrder(int order) { m_panelOrder = order; } + +signals: + void removeme(ExtensionContainer*); + +protected slots: + virtual void showPanelMenu( const QPoint& pos ); + void moveMe(); + void updateLayout(); + void actuallyUpdateLayout(); + void enableMouseOverEffects(); + void updateHighlightColor(); + +protected: + bool event(QEvent*); + void closeEvent( QCloseEvent* e ); + void paintEvent(QPaintEvent*); + void leaveEvent(QEvent*); + + void arrange(KPanelExtension::Position p, KPanelExtension::Alignment a, int XineramaScreen); + bool autoHidden() const { return _autoHidden; }; + UserHidden userHidden() const { return _userHidden; }; + void resetLayout(); + bool needsBorder() const; + +private slots: + void unhideTriggered( UnhideTrigger::Trigger t, int XineramaScreen ); + void autoHideTimeout(); + void hideLeft(); + void hideRight(); + void autoHide(bool hide); + void animatedHide(bool left); + void updateWindowManager(); + void currentDesktopChanged(int); + void strutChanged(); + void blockUserInput( bool block ); + void maybeStartAutoHideTimer(); + void stopAutoHideTimer(); + void maintainFocus(bool); + +private: + bool shouldUnhideForTrigger(UnhideTrigger::Trigger t) const; + void init(); + QSize initialSize(KPanelExtension::Position p, QRect workArea) const; + QPoint initialLocation(KPanelExtension::Position p, KPanelExtension::Alignment a, + int XineramaScreen, const QSize &s, QRect workArea, + bool autohidden = false, UserHidden userHidden = Unhidden) const; + void positionChange(KPanelExtension::Position p); + void alignmentChange(KPanelExtension::Alignment a); + void xineramaScreenChange(int /*XineramaScreen*/) {} + int arrangeHideButtons(); + int setupBorderSpace(); + + ExtensionSettings m_settings; + ExtensionContainer::HideMode m_hideMode; + UnhideTrigger::Trigger m_unhideTriggeredAt; + + // State variables + bool _autoHidden; + UserHidden _userHidden; + bool _block_user_input; + QPoint _last_lmb_press; + bool _is_lmb_down; + bool _in_autohide; + + // Misc objects + QTimer *_autohideTimer; + QTimer *_updateLayoutTimer; + NETExtendedStrut _strut; + PopupWidgetFilter *_popupWidgetFilter; + + QString _id; + PanelExtensionOpMenu *_opMnu; + AppletInfo _info; + KPanelExtension::Type _type; + + // Widgets + HideButton *_ltHB; // Left Hide Button + HideButton *_rbHB; // Right Hide Button + QGridLayout *_layout; + + KPanelExtension *m_extension; + int m_maintainFocus; + int m_panelOrder; + QColor m_highlightColor; +}; + +class PopupWidgetFilter : public QObject +{ + Q_OBJECT + + public: + PopupWidgetFilter( QObject *parent ); + ~PopupWidgetFilter() {} + bool eventFilter( QObject *obj, QEvent* e ); + signals: + void popupWidgetHiding(); +}; + +typedef QValueList<ExtensionContainer*> ExtensionList; + +#endif diff --git a/kicker/kicker/core/containerarea.cpp b/kicker/kicker/core/containerarea.cpp new file mode 100644 index 000000000..23732e684 --- /dev/null +++ b/kicker/kicker/core/containerarea.cpp @@ -0,0 +1,1939 @@ +/***************************************************************** + +Copyright (c) 1996-2004 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <unistd.h> + +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qstyle.h> +#include <qtextstream.h> +#include <qtimer.h> +#include <qwmatrix.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kurl.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kiconloader.h> +#include <kmimetype.h> +#include <kprocess.h> +#include <krootpixmap.h> +#include <kpixmap.h> +#include <klocale.h> +#include <kio/netaccess.h> +#include <kservice.h> +#include <kurldrag.h> + +#include "addapplet.h" +#include "browser_dlg.h" +#include "container_applet.h" +#include "container_button.h" +#include "containerarealayout.h" +#include "dirdrop_mnu.h" +#include "exe_dlg.h" +#include "extensionmanager.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "kickertip.h" +#include "paneldrag.h" +#include "pluginmanager.h" + +#include "containerarea.h" + +// for multihead +extern int kicker_screen_number; + +ContainerArea::ContainerArea(KConfig* _c, + QWidget* parent, + QPopupMenu* opMenu, + const char* name) + : Panner(parent, name), + _moveAC(0), + _pos(KPanelExtension::Left), + _config(_c), + _dragIndicator(0), + _dragMoveAC(0), + _dragMoveOffset(QPoint(0,0)), + m_opMenu(opMenu), + _rootPixmap(0), + _useBgTheme(false), + _bgSet(false), + m_canAddContainers(true), + m_immutable(_c->isImmutable()), + m_updateBackgroundsCalled(false), + m_layout(0), + m_addAppletDialog(0) +{ + setBackgroundOrigin( WidgetOrigin ); + + m_contents = viewport(); + + m_layout = new ContainerAreaLayout(m_contents); + + // Install an event filter to propagate layout hints coming from m_contents. + m_contents->installEventFilter(this); + + setBackground(); + + connect(&_autoScrollTimer, SIGNAL(timeout()), SLOT(autoScroll())); + connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(setBackground())); + connect(Kicker::the(), SIGNAL(immutabilityChanged(bool)), + SLOT(immutabilityChanged(bool))); + connect(this, SIGNAL(contentsMoving(int, int)), SLOT(setBackground())); +} + +ContainerArea::~ContainerArea() +{ + // don't emit signals from destructor + blockSignals( true ); + // clear applets + removeAllContainers(); +} + +void ContainerArea::initialize(bool useDefaultConfig) +{ + // do we really need to do this? + removeAllContainers(); + + // restore applet layout or load a default panel layout + _config->setGroup("General"); + if (_config->hasKey("Applets2")) + { + if (_config->groupIsImmutable("General")) + { + m_immutable = true; + } + + m_canAddContainers = !m_immutable && + !_config->entryIsImmutable("Applets2"); + loadContainers(_config->readListEntry("Applets2")); + } + else if (useDefaultConfig) + { + defaultContainerConfig(); + } + + setAcceptDrops(!isImmutable()); + QTimer::singleShot(0, this, SLOT(resizeContents())); +} + +void ContainerArea::defaultContainerConfig() +{ + //FIXME: make this use a file template so it isn't hardcoded anymore + BaseContainer::List containers; + + containers.append(new KMenuButtonContainer(m_opMenu, m_contents)); + + int dsize; + if (orientation() == Qt::Horizontal) + { + dsize = width(); + } + else + { + dsize = height(); + } + + dsize -= 560; + QStringList buttons; + + QFile f(locate("data", "kicker/default-apps")); + if (f.open(IO_ReadOnly)) + { + QTextStream is(&f); + + while (!is.eof()) + buttons << is.readLine(); + + f.close(); + } + else + { + buttons << "kde-Home.desktop" + << "kde-konqbrowser.desktop"; + } + + //int size = dsize; + for (QStringList::ConstIterator it = buttons.begin(); it != buttons.end(); ++it) + { + /*size -= 42; + if (size <= 0) + break;*/ + + BaseContainer *button = 0; + KService::Ptr service = KService::serviceByStorageId(*it); + if (!service) + { + // look for a special button + QString s = locate("appdata", *it); + if (s.isEmpty()) continue; + QString itExt = (*it).section('/', 1); + button = new ExtensionButtonContainer(itExt, m_opMenu, m_contents); + } + else + { + button = new ServiceButtonContainer(service, m_opMenu, m_contents); + } + + if (button->isValid()) + { + containers.append(button); + } + else + { + delete button; + } + } + + PluginManager* manager = PluginManager::the(); + + // pager applet + AppletContainer* a = manager->createAppletContainer( + "minipagerapplet.desktop", + true, + QString::null, + m_opMenu, + m_contents); + if (a) + { + a->setFreeSpace(0.09); + containers.append(a); + } + + // taskbar applet + a = manager->createAppletContainer( + "taskbarapplet.desktop", + true, + QString::null, + m_opMenu, + m_contents); + if (a) + { + a->setFreeSpace(0.09); + containers.append(a); + } + + // system tray applet + a = manager->createAppletContainer( + "systemtrayapplet.desktop", + true, + QString::null, + m_opMenu, + m_contents ); + if (a) + { + a->setFreeSpace(1); + containers.append(a); + } + + // clock applet + a = manager->createAppletContainer( + "clockapplet.desktop", + true, + QString::null, + m_opMenu, + m_contents ); + if (a) + { + a->setFreeSpace(1); + containers.append(a); + } + + for (BaseContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + addContainer(*it); + } + + saveContainerConfig(); +} + +void ContainerArea::loadContainers(const QStringList& containers) +{ + // read applet list + bool badApplets = false; + + // now restore the applets + QStringList::const_iterator it = containers.constBegin(); + QStringList::const_iterator itEnd = containers.constEnd(); + for (; it != itEnd; ++it) + { + QString appletId(*it); + + // is there a config group for this applet? + if (!_config->hasGroup(appletId)) + { + continue; + } + + KConfigGroup group(_config, appletId.latin1()); + + BaseContainer* a = 0; + + int sep = appletId.findRev('_'); + Q_ASSERT(sep != -1); + QString appletType = appletId.left(sep); + + // create a matching applet container + if (appletType == "KMenuButton") + a = new KMenuButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "DesktopButton") + a = new DesktopButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "WindowListButton") + a = new WindowListButtonContainer(group, m_opMenu, m_contents); + else if ((appletType == "BookmarksButton") && kapp->authorizeKAction("bookmarks")) + a = new BookmarksButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "ServiceButton") + a = new ServiceButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "URLButton") + a = new URLButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "BrowserButton") + a = new BrowserButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "ServiceMenuButton") + a = new ServiceMenuButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "ExecButton") + a = new NonKDEAppButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "ExtensionButton") + a = new ExtensionButtonContainer(group, m_opMenu, m_contents); + else if (appletType == "Applet") + { + bool immutable = Kicker::the()->isImmutable() || + group.groupIsImmutable() || + group.entryIsImmutable("ConfigFile"); + a = PluginManager::the()->createAppletContainer( + group.readPathEntry("DesktopFile"), + true, // isStartup + group.readPathEntry("ConfigFile"), + m_opMenu, + m_contents, + immutable); + } + + if (a && a->isValid()) + { + a->setAppletId(appletId); + a->loadConfiguration(group); + addContainer(a); + } + else + { + badApplets = true; + delete a; + } + } + + if (badApplets) + { + // since we may have had Bad Applets in our list + // let's save it again, just in case + saveContainerConfig(); + } + + // while this is also called in addContainer (well, resizeContents()), + // it gets executed too soon. we need to wait until the containers are + // actually resized, but we enter the event loop prior to that happening + // above. + QTimer::singleShot(0, this, SLOT(updateContainersBackground())); +} + +void ContainerArea::saveContainerConfig(bool layoutOnly) +{ + if (!canAddContainers()) + { + return; + } + + // Save the applet list + QStringList alist; + QLayoutIterator it2 = m_layout->iterator(); + for (; it2.current(); ++it2) + { + BaseContainer* a = dynamic_cast<BaseContainer*>(it2.current()->widget()); + if (a) + { + KConfigGroup group(_config, a->appletId().latin1()); + a->saveConfiguration(group, layoutOnly); + alist.append(a->appletId()); + } + } + + KConfigGroup group( _config, "General" ); + group.writeEntry("Applets2", alist); + + _config->sync(); +} + +void ContainerArea::removeAllContainers() +{ + for (BaseContainer::List::const_iterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + delete *it; + } + m_containers.clear(); +} + +void ContainerArea::configure() +{ + setBackground(); + + for (BaseContainer::Iterator it = m_containers.begin(); + it != m_containers.end(); + ++it) + { + (*it)->configure(); + } + + resizeContents(); +} + +const QWidget* ContainerArea::addButton(const AppletInfo& info) +{ + QString buttonType = info.library(); + + if (buttonType == "BookmarksButton") + { + if (kapp->authorizeKAction("bookmarks")) + { + return addBookmarksButton(); + } + } + else if (buttonType == "BrowserButton") + { + return addBrowserButton(); + } + else if (buttonType == "DesktopButton") + { + return addDesktopButton(); + } + else if (buttonType == "ExecButton") + { + return addNonKDEAppButton(); + } + else if (buttonType == "KMenuButton") + { + return addKMenuButton(); + } + else if (buttonType == "WindowListButton") + { + return addWindowListButton(); + } + else // ExtensionButton + { + return addExtensionButton(info.desktopFile()); + } + + return 0; +} + +const QWidget* ContainerArea::addKMenuButton() +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new KMenuButtonContainer(m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addDesktopButton() +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new DesktopButtonContainer(m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addWindowListButton() +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new WindowListButtonContainer(m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addBookmarksButton() +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new BookmarksButtonContainer(m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addServiceButton(const QString& desktopFile) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new ServiceButtonContainer(desktopFile,m_opMenu, + m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addURLButton(const QString &url) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new URLButtonContainer(url, m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addBrowserButton() +{ + if (!canAddContainers()) + { + return 0; + } + + PanelBrowserDialog *dlg = new PanelBrowserDialog(QDir::home().path(), + "kdisknav"); + + if (dlg->exec() == QDialog::Accepted) + { + return addBrowserButton(dlg->path(), dlg->icon()); + } + + return 0; +} + +const QWidget* ContainerArea::addBrowserButton(const QString &startDir, + const QString& icon) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new BrowserButtonContainer(startDir, m_opMenu, + icon, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addServiceMenuButton(const QString& relPath) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new ServiceMenuButtonContainer(relPath, m_opMenu, + m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addNonKDEAppButton() +{ + if (!canAddContainers()) + { + return 0; + } + + PanelExeDialog dlg(QString::null, QString::null, QString::null, + QString::null, QString::null, false, 0); + + if (dlg.exec() == QDialog::Accepted) + { + return addNonKDEAppButton(dlg.title(), dlg.description(), + dlg.command(), dlg.iconPath(), + dlg.commandLine(), + dlg.useTerminal()); + } + + return 0; +} + +const QWidget* ContainerArea::addNonKDEAppButton(const QString &name, + const QString &description, + const QString& filePath, + const QString &icon, + const QString &cmdLine, + bool inTerm) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer *b = new NonKDEAppButtonContainer(name, + description, + filePath, icon, + cmdLine, inTerm, + m_opMenu, m_contents); + completeContainerAddition(b); + return b; +} + +const QWidget* ContainerArea::addExtensionButton(const QString& df) +{ + if (!canAddContainers()) + { + return 0; + } + + BaseContainer* b = new ExtensionButtonContainer(df, + m_opMenu, + m_contents); + completeContainerAddition(b); + return b; +} + +void ContainerArea::completeContainerAddition(BaseContainer* container, + int index) +{ + //FIXME: the original comment was: + // Set freespace to one since the container will be added at the end. + // yet this is not always true =/ + container->setFreeSpace(1); + addContainer(container, true, index); + scrollTo(container); + saveContainerConfig(); +} + +AppletContainer* ContainerArea::addApplet(const AppletInfo& info, + bool isImmutable, + int insertionIndex) +{ + if (!canAddContainers()) + { + return 0; + } + + AppletContainer* a = PluginManager::the()->createAppletContainer( + info.desktopFile(), + false, // not startup + QString::null, // no config + m_opMenu, + m_contents, + isImmutable); + + if (!a || !a->isValid()) + { + delete a; + return 0; + } + + completeContainerAddition(a, insertionIndex); + return a; +} + +void ContainerArea::addContainer(BaseContainer* a, bool arrange, int index) +{ + if (!a) + { + return; + } + + if (a->appletId().isNull()) + { + a->setAppletId(createUniqueId(a->appletType())); + } + + m_containers.append(a); + + if (arrange) + { + QWidget* w = m_layout->widgetAt(index); + QPoint oldInsertionPoint = Kicker::the()->insertionPoint(); + if (w) + { + // let's set the insertion point to where the widget asked to be + // put in front of is + Kicker::the()->setInsertionPoint(w->geometry().topLeft()); + } + + if (Kicker::the()->insertionPoint().isNull()) + { + m_layout->insertIntoFreeSpace(a, QPoint()); + } + else + { + m_layout->insertIntoFreeSpace(a, mapFromGlobal(Kicker::the()->insertionPoint())); + } + + if (w) + { + Kicker::the()->setInsertionPoint(oldInsertionPoint); + } + } + else + { + m_layout->add(a); + } + + connect(a, SIGNAL(moveme(BaseContainer*)), + SLOT(startContainerMove(BaseContainer*))); + connect(a, SIGNAL(removeme(BaseContainer*)), + SLOT(removeContainer(BaseContainer*))); + connect(a, SIGNAL(takeme(BaseContainer*)), + SLOT(takeContainer(BaseContainer*))); + connect(a, SIGNAL(requestSave()), + SLOT(slotSaveContainerConfig())); + connect(a, SIGNAL(maintainFocus(bool)), + this, SIGNAL(maintainFocus(bool))); + + if (dynamic_cast<AppletContainer*>(a)) + { + connect(a, SIGNAL(updateLayout()), SLOT(resizeContents())); + } + + a->configure(orientation(), popupDirection()); + a->show(); + resizeContents(); +} + +bool ContainerArea::removeContainer(BaseContainer *a) +{ + if (!a || isImmutable() || a->isImmutable()) + { + return false; + } + + a->slotRemoved(_config); + m_containers.remove(a); + m_layout->remove(a); + a->deleteLater(); + saveContainerConfig(true); + resizeContents(); + return true; +} + +bool ContainerArea::removeContainer(int index) +{ + if (isImmutable()) + { + return false; + } + + BaseContainer* a = dynamic_cast<BaseContainer*>(m_layout->widgetAt(index)); + if (!a || a->isImmutable()) + { + return false; + } + + a->slotRemoved(_config); + m_containers.remove(a); + m_layout->remove(a); + a->deleteLater(); + saveContainerConfig(true); + resizeContents(); + return true; +} + +void ContainerArea::removeContainers(BaseContainer::List containers) +{ + if (isImmutable()) + { + return; + } + + m_layout->setEnabled(false); + + for (BaseContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + BaseContainer* a = *it; + if (a->isImmutable()) + { + continue; + } + + a->slotRemoved(_config); + m_containers.remove(a); + m_layout->remove(a); + a->deleteLater(); + } + + m_layout->setEnabled(true); + saveContainerConfig(true); + resizeContents(); +} + +void ContainerArea::takeContainer(BaseContainer* a) +{ + if (!a) + { + return; + } + + disconnect(a, SIGNAL(moveme(BaseContainer*)), + this, SLOT(startContainerMove(BaseContainer*))); + disconnect(a, SIGNAL(removeme(BaseContainer*)), + this, SLOT(removeContainer(BaseContainer*))); + disconnect(a, SIGNAL(takeme(BaseContainer*)), + this, SLOT(takeContainer(BaseContainer*))); + disconnect(a, SIGNAL(requestSave()), + this, SLOT(slotSaveContainerConfig())); + disconnect(a, SIGNAL(maintainFocus(bool)), + this, SIGNAL(maintainFocus(bool))); + + // Just remove the group from our own config file. Leave separate config + // files untouched. + _config->deleteGroup(a->appletId().latin1()); + _config->sync(); + m_containers.remove(a); + m_layout->remove(a); + saveContainerConfig(true); + resizeContents(); +} + +void ContainerArea::resizeContents() +{ + int w = width(); + int h = height(); + + if (orientation() == Qt::Horizontal) + { + int newWidth = m_layout->widthForHeight(h); + if (newWidth > w) + { + resizeContents(newWidth, h); + } + else + { + resizeContents(w, h); + } + } + else + { + int newHeight = m_layout->heightForWidth(w); + + if (newHeight > h) + { + resizeContents(w, newHeight); + } + else + { + resizeContents(w, h); + } + } +} + +QString ContainerArea::createUniqueId(const QString& appletType) const +{ + QString idBase = appletType + "_%1"; + QString newId; + int i = 0; + bool unique = false; + + while (!unique) + { + i++; + newId = idBase.arg(i); + + unique = true; + for (BaseContainer::ConstIterator it = m_containers.begin(); + it != m_containers.end(); + ++it) + { + BaseContainer* b = *it; + if (b->appletId() == newId) + { + unique = false; + break; + } + } + } + + return newId; +} + +bool ContainerArea::canAddContainers() const +{ + return m_canAddContainers && Kicker::the()->canAddContainers(); +} + +void ContainerArea::startContainerMove(BaseContainer *a) +{ + if (!a || isImmutable()) + { + return; + } + + _moveAC = a; + + KickerTip::enableTipping(false); + emit maintainFocus(true); + setMouseTracking(true); + grabMouse(sizeAllCursor); + + m_layout->setStretchEnabled(false); + a->raise(); +} + +void ContainerArea::mouseReleaseEvent(QMouseEvent *) +{ + if (!_moveAC) + { + return; + } + + // start container move was caled successfuly + // so we need to complete the move here + _autoScrollTimer.stop(); + releaseMouse(); + setCursor(arrowCursor); + setMouseTracking(false); + + _moveAC->completeMoveOperation(); + KickerTip::enableTipping(true); + + _moveAC = 0; + + emit maintainFocus(false); + m_layout->setStretchEnabled(true); + updateContainersBackground(); + saveContainerConfig(true); +} + +void ContainerArea::mouseMoveEvent(QMouseEvent *ev) +{ + if (!_moveAC) + { + Panner::mouseMoveEvent(ev); + return; + } + + if (ev->state() == LeftButton && !rect().contains(ev->pos())) + { + // leaveEvent() doesn't work, while grabbing the mouse + _autoScrollTimer.stop(); + releaseMouse(); + setCursor(arrowCursor); + setMouseTracking(false); + + _moveAC->completeMoveOperation(); + KickerTip::enableTipping(true); + + emit maintainFocus(false); + m_layout->setStretchEnabled(true); + updateContainersBackground(); + saveContainerConfig(true); + + PanelDrag *dd = new PanelDrag(_moveAC, this); + dd->setPixmap(kapp->iconLoader()->loadIcon(_moveAC->icon(), KIcon::Small)); + grabKeyboard(); + dd->drag(); + releaseKeyboard(); + return; + } + + if (orientation() == Horizontal) + { + int oldX = _moveAC->x() + _moveAC->moveOffset().x(); + int x = ev->pos().x() + contentsX(); + if (ev->state() & ShiftButton) + { + m_layout->moveContainerPush(_moveAC, x - oldX); + } + else + { + m_layout->moveContainerSwitch(_moveAC, x - oldX); + /* FIXME: Scrolling when the container moves out of the viewport + bool scroll = false; + if (rtl) + if (newPos - 80 <= 0) + scroll = true; + else + if (newPos + 80 >= (horizontal ? geometry().width() - moving->geometry().width() + : geometry().height() - moving->geometry().height())) + scroll = true; + [...] + if (scroll) { + if (!_autoScrollTimer.isActive()) + _autoScrollTimer.start(50); + + if (horizontal) + scrollBy(dir*10, 0); + else + scrollBy(0, dir*10); + } + */ + } + } + else + { + int oldY = _moveAC->y() + _moveAC->moveOffset().y(); + int y = ev->pos().y() + contentsY(); + if (ev->state() & ShiftButton) + { + m_layout->moveContainerPush(_moveAC, y - oldY); + } + else + { + m_layout->moveContainerSwitch(_moveAC, y - oldY); + // TODO: Scrolling + } + } + + ensureVisible(ev->pos().x() + contentsX(), ev->pos().y() + contentsY()); + updateContainersBackground(); +} + +int ContainerArea::position() const +{ + return static_cast<int>(_pos); +} + +KPanelApplet::Direction ContainerArea::popupDirection() const +{ + return KickerLib::positionToDirection(_pos); +} + +bool ContainerArea::isImmutable() const +{ + return m_immutable || Kicker::the()->isImmutable(); +} + +void ContainerArea::dragEnterEvent(QDragEnterEvent *ev) +{ + bool canAccept = !isImmutable() && + (PanelDrag::canDecode(ev) || + AppletInfoDrag::canDecode(ev) || + KURLDrag::canDecode(ev)); + ev->accept(canAccept); + + if (!canAccept) + { + return; + } + + m_layout->setStretchEnabled(false); + + if (!_dragIndicator) + { + _dragIndicator = new DragIndicator(m_contents); + } + + BaseContainer *draggedContainer = 0; + int preferedWidth = height(); + int preferedHeight = width(); + if (PanelDrag::decode(ev, &draggedContainer)) + { + preferedWidth = draggedContainer->widthForHeight(height()); + preferedHeight = draggedContainer->heightForWidth(width()); + } + + if (orientation() == Horizontal) + { + _dragIndicator->setPreferredSize(QSize(preferedWidth, height())); + } + else + { + _dragIndicator->setPreferredSize(QSize(width(), preferedHeight)); + } + _dragMoveOffset = QPoint(_dragIndicator->width()/2, + _dragIndicator->height()/2); + + // Find the container before the position of the dragindicator. + BaseContainer::Iterator it = m_containers.end(); + + if (it != m_containers.begin()) + { + do + { + --it; + BaseContainer* a = *it; + + if ((orientation() == Horizontal && + a->x() < (ev->pos().x() + contentsX()) - _dragMoveOffset.x()) || + (orientation() == Vertical && + a->y() < (ev->pos().y() + contentsY()) - _dragMoveOffset.y())) + { + _dragMoveAC = a; + break; + } + } while (it != m_containers.begin()); + } + + if (orientation() == Horizontal) + { + moveDragIndicator(ev->pos().x() + contentsX() - _dragMoveOffset.x()); + } + else + { + moveDragIndicator(ev->pos().y() + contentsY() - _dragMoveOffset.y()); + } + + _dragIndicator->show(); +} + +void ContainerArea::dragMoveEvent(QDragMoveEvent* ev) +{ + if (ev->source() == this) + { + // Abort the drag and go back to container sliding. + // Actually, this should be placed in dragEnterEvent(), but + // then it does work only on every second event. + + // Cancel the drag by faking an Escape keystroke. + QKeyEvent fakedKeyPress(QEvent::KeyPress, Key_Escape, 0, 0); + QKeyEvent fakedKeyRelease(QEvent::KeyRelease, Key_Escape, 0, 0); + QApplication::sendEvent(this, &fakedKeyPress); + QApplication::sendEvent(this, &fakedKeyRelease); + qApp->processEvents(); + startContainerMove(_moveAC); + + // Align the container to the mouse position. + if (orientation() == Horizontal) + { + m_layout->moveContainerSwitch(_moveAC, ev->pos().x() + contentsX() - _moveAC->x()); + } + else + { + m_layout->moveContainerSwitch(_moveAC, ev->pos().y() + contentsY() - _moveAC->y()); + } + return; + } + + if (!_dragIndicator) + { + return; + } + + if (orientation() == Horizontal) + { + moveDragIndicator(ev->pos().x() + contentsX() - _dragMoveOffset.x()); + } + else + { + moveDragIndicator(ev->pos().y() + contentsY() - _dragMoveOffset.y()); + } +} + +void ContainerArea::dragLeaveEvent(QDragLeaveEvent*) +{ + if (_dragIndicator) + { + _dragIndicator->hide(); + } + m_layout->setStretchEnabled(true); + _dragMoveAC = 0; +} + +void ContainerArea::dropEvent(QDropEvent *ev) +{ + if (!_dragIndicator) + { + // we assume that this is the result of a successful drag enter + // which means we'll have a _dragIndicator. if for + // some reason we don't, let's not go down this code path + return; + } + + BaseContainer *a = 0; + if (PanelDrag::decode(ev, &a)) + { + if (!a) + { + _dragMoveAC = 0; + _dragIndicator->hide(); + m_layout->setStretchEnabled(true); + return; + } + + QObject *parent = ev->source() ? ev->source()->parent() : 0; + while (parent && (parent != this)) + { + parent = parent->parent(); + } + + if (parent) + { + // Move container a + if (orientation() == Horizontal) + { + int oldX = a->x(); + int x = _dragIndicator->x(); + m_layout->moveContainerSwitch(a, x - oldX); + } + else if (orientation() == Vertical) + { + int oldY = a->y(); + int y = _dragIndicator->y(); + m_layout->moveContainerSwitch(a, y - oldY); + } + + _dragMoveAC = 0; + _dragIndicator->hide(); + m_layout->setEnabled(true); + m_layout->setStretchEnabled(true); + saveContainerConfig(true); + return; + } + + // it came from another panel + Kicker::the()->setInsertionPoint(_dragIndicator->pos()); + a->reparent(m_contents, 0, _dragIndicator->pos(), true); + a->setAppletId(createUniqueId(a->appletType())); + addContainer(a, true); + Kicker::the()->setInsertionPoint(QPoint()); + m_layout->updateFreeSpaceValues(); + _dragMoveAC = 0; + _dragIndicator->hide(); + m_layout->setStretchEnabled(true); + saveContainerConfig(); + return; + } + + // is it an applet info? + AppletInfo info; + if (AppletInfoDrag::decode(ev, info)) + { + Kicker::the()->setInsertionPoint(_dragIndicator->pos()); + _dragIndicator->hide(); + m_layout->setStretchEnabled(true); + + if (info.type() & AppletInfo::Button) + { + addButton(info); + } + else if (info.type() == AppletInfo::Applet) + { + addApplet(info); + } + + Kicker::the()->setInsertionPoint(QPoint()); + return; + } + + // ok, let's try a KURL drag + KURL::List uriList; + if (!KURLDrag::decode(ev, uriList)) + { + _dragMoveAC = 0; + _dragIndicator->hide(); + m_layout->setStretchEnabled(true); + return; + } + + Kicker::the()->setInsertionPoint(_dragIndicator->pos()); + + KURL::List::ConstIterator it(uriList.begin()); + for (; it != uriList.end(); ++it) + { + const KURL &url = *it; + + // Create a new PanelButton for this URL. + + // see if it's a executable or directory + if (url.protocol() == "programs") + { + QString relPath = url.path(); + if (relPath[0] == '/') + { + relPath = relPath.right(relPath.length() - 1); + } + a = new ServiceMenuButtonContainer(relPath, m_opMenu, m_contents); + } + else if (url.isLocalFile()) + { + QFileInfo fi(url.path()); + if (fi.isDir()) + { // directory + switch (PanelDirDropMenu().exec(mapToGlobal(ev->pos()))) + { + case PanelDirDropMenu::Browser: + a = new BrowserButtonContainer(url.path(), m_opMenu, + KMimeType::iconForURL(url), m_contents); + break; + case PanelDirDropMenu::Url: + a = new URLButtonContainer(url.url(), m_opMenu, m_contents); + break; + default: ; + } + } + else if ( KMimeType::findByURL(url)->name() == "application/x-desktop" ) + { + // a local desktop file being dragged from an external program. + // Make a copy first. + KDesktopFile df(url.path()); + KURL newUrl; + newUrl.setPath(KickerLib::copyDesktopFile(url)); + if (df.readType() == "Link") + a = new URLButtonContainer(newUrl.url(), m_opMenu, m_contents); + else + a = new ServiceButtonContainer(newUrl.path(), m_opMenu, m_contents); + } + else if (fi.isExecutable()) + { + // non-KDE executable + QString pixmapFile; + KMimeType::pixmapForURL(url, 0, KIcon::Panel, 0, + KIcon::DefaultState, &pixmapFile); + PanelExeDialog dlg(QString::null, QString::null, url.path(), + pixmapFile, QString::null, false, 0); + if (dlg.exec() == QDialog::Accepted) + { + // KIconloader returns a full path, we only want the name + QFileInfo iconfi(dlg.iconPath()); + a = new NonKDEAppButtonContainer(dlg.title(), + dlg.description(), + dlg.command(), + iconfi.fileName(), + dlg.commandLine(), + dlg.useTerminal(), + m_opMenu, + m_contents); + } + } + else // some unknown local file + { + a = new URLButtonContainer(url.url(), m_opMenu, m_contents); + } + } + else // a internet URL + { + a = new URLButtonContainer(url.url(), m_opMenu, m_contents); + } + + if (!a) + { + _dragIndicator->hide(); + Kicker::the()->setInsertionPoint(QPoint()); + m_layout->setStretchEnabled(true); + return; + } + + addContainer(a, true); + m_layout->updateFreeSpaceValues(); + } + + saveContainerConfig(); + _dragMoveAC = 0; + _dragIndicator->hide(); + Kicker::the()->setInsertionPoint(QPoint()); + m_layout->setStretchEnabled(true); +} + +bool ContainerArea::eventFilter(QObject* o, QEvent* e) +{ + // Propagate the layout hints which m_contents receives. This way widgets + // which contain a ContainerArea can react to layout changes of its + // contents. For example: If an applets grows, the top level widget may + // want to grow as well. + if (o == m_contents) + { + if (e->type() == QEvent::LayoutHint) + { + updateGeometry(); // Posts a new layout hint to our parent. + } + return false; + } + + return Panner::eventFilter(o, e); +} + +void ContainerArea::resizeEvent(QResizeEvent *ev) +{ + Panner::resizeEvent(ev); + setBackground(); +} + +void ContainerArea::viewportResizeEvent(QResizeEvent* ev) +{ + Panner::viewportResizeEvent(ev); + if (orientation() == Horizontal) + { + m_contents->resize(kMax(widthForHeight(ev->size().height()), + ev->size().width()), + ev->size().height()); + } + else + { + m_contents->resize(ev->size().width(), + kMax(heightForWidth(ev->size().width()), + ev->size().height())); + } + resizeContents(m_contents->width(), m_contents->height()); +} + +void ContainerArea::setBackground() +{ + _bgSet = false; + m_cachedGeometry.clear(); + + if (KickerSettings::transparent() && + (KickerSettings::menubarPanelTransparent() || + !ExtensionManager::the()->isMenuBar(topLevelWidget()))) + { + if (!_rootPixmap) + { + _rootPixmap = new KRootPixmap(this); + _rootPixmap->setCustomPainting(true); + connect(_rootPixmap, SIGNAL(backgroundUpdated(const QPixmap&)), + SLOT(updateBackground(const QPixmap&))); + } + else + { + _rootPixmap->repaint(true); + } + + double tint = double(KickerSettings::tintValue()) / 100; + _rootPixmap->setFadeEffect(tint, KickerSettings::tintColor()); + _rootPixmap->start(); + _bgSet = true; + return; + } + else if (_rootPixmap) + { + delete _rootPixmap; + _rootPixmap = 0; + } + + unsetPalette(); + + if (KickerSettings::useBackgroundTheme()) + { + // by keeping the src image static, we can share it among panels and only + // reload from disk when it actually changes in the config, not every time we + // get a resize or configure event + static QString bgStr; + static QImage srcImage; + QString newBgStr = locate("appdata", KickerSettings::backgroundTheme()); + + if (bgStr != newBgStr) + { + bgStr = newBgStr; + srcImage.load(bgStr); + } + + if (srcImage.isNull()) + { + KickerSettings::setUseBackgroundTheme(false); + } + else + { + QImage bgImage = srcImage; + + if (orientation() == Vertical) + { + if (KickerSettings::rotateBackground()) + { + QWMatrix matrix; + matrix.rotate(position() == KPanelExtension::Left ? 90: 270); + bgImage = bgImage.xForm(matrix); + } + + bgImage = bgImage.scaleWidth( size().width() ); + } + else + { + if (position() == KPanelExtension::Top && + KickerSettings::rotateBackground()) + { + QWMatrix matrix; + matrix.rotate(180); + bgImage = bgImage.xForm(matrix); + } + + bgImage = bgImage.scaleHeight( size().height() ); + } + + if (KickerSettings::colorizeBackground()) + { + KickerLib::colorize(bgImage); + } + setPaletteBackgroundPixmap(QPixmap(bgImage)); + QTimer::singleShot(0, this, SLOT(updateContainersBackground())); + } + } + + _bgSet = true; +} + +void ContainerArea::immutabilityChanged(bool immutable) +{ + // we set all the child container's immutability here instead of connecting + // the immutabilityChanged signal up everywhere so that we can control the + // order of immutability changing and the background being updated. since + // immutability implies applet handle visibility, those things must happen + // first before updating our background. + for (BaseContainer::ConstIterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + (*it)->setImmutable(immutable); + } + + setAcceptDrops(!isImmutable()); + QTimer::singleShot(0, this, SLOT(setBackground())); +} + +QRect ContainerArea::availableSpaceFollowing(BaseContainer* a) +{ + QRect availableSpace = rect(); + BaseContainer* b = 0; + + if (a) + { + BaseContainer::Iterator it = m_containers.find(a); + if (it != m_containers.end() && + ++it != m_containers.end()) + { + b = (*it); + } + } + + if (!b) + { + BaseContainer::Iterator it = m_containers.begin(); + if (it != m_containers.end()) + { + b = (*it); + } + } + + if (orientation() == Horizontal) + { + if (a) + { + availableSpace.setLeft(a->x() + a->width()); + } + + if (b) + { + availableSpace.setRight(b->x() - 1); + } + } + else + { + if (a) + { + availableSpace.setTop(a->y() + a->height()); + } + + if (b) + { + availableSpace.setBottom(b->y() - 1); + } + } + + return availableSpace; +} + +void ContainerArea::moveDragIndicator(int pos) +{ + QRect availableSpace = availableSpaceFollowing(_dragMoveAC); + + // Move _dragIndicator to position pos, restricted by availableSpace. + // Resize _dragIndicator if necessary. + if (orientation() == Horizontal) + { + if (availableSpace.size().width() < + _dragIndicator->preferredSize().width()) + { + _dragIndicator->resize(availableSpace.size()); + _dragIndicator->move(availableSpace.topLeft()); + } + else + { + int newX = pos; + _dragIndicator->resize(_dragIndicator->preferredSize()); + newX = QMAX(newX, availableSpace.left()); + newX = QMIN(newX, + availableSpace.right() + 1 - _dragIndicator->width() ); + _dragIndicator->move(newX, availableSpace.top()); + } + } + else + { + if (availableSpace.size().height() < + _dragIndicator->preferredSize().height()) + { + _dragIndicator->resize(availableSpace.size()); + _dragIndicator->move(availableSpace.topLeft()); + } + else + { + int newY = pos; + _dragIndicator->resize(_dragIndicator->preferredSize()); + newY = QMAX(newY, availableSpace.top()); + newY = QMIN(newY, + availableSpace.bottom() + 1 - _dragIndicator->height() ); + _dragIndicator->move(availableSpace.left(), newY); + } + } +} + +void ContainerArea::updateBackground( const QPixmap& pm ) +{ + QBrush bgBrush(colorGroup().background(), pm); + QPalette pal = kapp->palette(); + pal.setBrush(QColorGroup::Background, bgBrush); + setPalette(pal); + + // because the Pixmap can be smaller as the containerarea + // we construct a pixmap the same size as we are that every + // applet or button can use to cut out its background + _completeBg.resize(width(), height()); + _completeBg.fill(this, 0, 0); + + m_cachedGeometry.clear(); + updateContainersBackground(); +} + +void ContainerArea::resizeContents(int w, int h) +{ + // this looks silly but is required otherwise (some?) c++ compilers can't see + // Panner::resizeContents(int, int) due to the overloaded ContainerArea::resizeContents() + Panner::resizeContents(w, h); + + if (!m_updateBackgroundsCalled) + { + m_updateBackgroundsCalled = true; + QTimer::singleShot(0, this, SLOT(updateContainersBackground())); + } +} + +void ContainerArea::slotSaveContainerConfig() +{ + saveContainerConfig(); +} + +void ContainerArea::setPosition(KPanelExtension::Position p) +{ + if (_pos == p) + { + return; + } + + _pos = p; + Qt::Orientation o = (p == KPanelExtension::Top || + p == KPanelExtension::Bottom) ? + Qt::Horizontal : Qt::Vertical; + bool orientationChanged = (orientation() != o); + m_layout->setEnabled(false); + + if (orientationChanged) + { + setOrientation(o); + m_layout->setOrientation(o); + + // when we change orientation, we will resize the "width" + // component down to 0, forcing a resize in resizeContents() + // when that gets called AFTER we've been moved + // it's not always safe to do the resize here, as scroll buttons + // from the panner may get in our way. =/ + if (o == Horizontal) + { + resizeContents(0, height()); + } + else + { + resizeContents(width(), 0); + } + } + + for (BaseContainer::ConstIterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + if (orientationChanged) + { + (*it)->setOrientation(o); + } + + (*it)->setPopupDirection( popupDirection() ); + } + + m_layout->setEnabled(true); + + setContentsPos(0, 0); + m_contents->move(0, 0); + setBackground(); + + // container extension repaints for us! + //repaint(); +} + +void ContainerArea::setAlignment(KPanelExtension::Alignment a) +{ + for (BaseContainer::ConstIterator it = m_containers.begin(); + it != m_containers.end(); + ++it) + { + (*it)->setAlignment(a); + } +} + +void ContainerArea::autoScroll() +{ + if(!_moveAC) return; + + if(orientation() == Horizontal) { + if(_moveAC->pos().x() <= 80) + scrollBy(-10, 0); + else if(_moveAC->pos().x() >= width() - _moveAC->width() - 80) + scrollBy(10, 0); + } + else { + if(_moveAC->pos().y() <= 80) + scrollBy(0, -10); + else if(_moveAC->pos().y() >= height() - _moveAC->height() - 80) + scrollBy(0, 10); + } +} + +void ContainerArea::scrollTo(BaseContainer* b) +{ + if (!b) + { + return; + } + + int x, y; + viewportToContents(b->pos().x(), b->pos().y(), x, y); + ensureVisible(x, y); +} + +void ContainerArea::updateContainersBackground() +{ + m_updateBackgroundsCalled = false; + + if (!_bgSet) + { + return; + } + + for (BaseContainer::ConstIterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + // A rather ugly hack. The code calls updateContainersBackground() all over + // the place even when nothing in fact has changed. Updating the background + // on every single unrelated change however means that e.g. the systray + // flickers when a new window is opened/closed (because the taskbar is relayouted, + // which triggers updateContainersBackground() even though the geometry + // of the taskbar does not change in fact. I'm apparently unable to fix this + // properly, so just cache the geometry and update background only when + // the geometry changes or when the background really changes (in which + // case the cached is cleared). + if( !m_cachedGeometry.contains( *it )) + { + m_cachedGeometry[ *it ] = QRect(); + connect( *it, SIGNAL( destroyed()), SLOT( destroyCachedGeometry())); + } + if( m_cachedGeometry[ *it ] != (*it)->geometry()) + { + (*it)->setBackground(); + m_cachedGeometry[ *it ] = (*it)->geometry(); + } + } +} + +void ContainerArea::destroyCachedGeometry() +{ + m_cachedGeometry.remove(const_cast<QWidget*>(static_cast<const QWidget*>(sender()))); +} + +BaseContainer::List ContainerArea::containers(const QString& type) const +{ + if (type.isEmpty() || type == "All") + { + return m_containers; + } + + BaseContainer::List list; + + if (type == "Special Button") + { + for (BaseContainer::ConstIterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + QString type = (*it)->appletType(); + if (type == "KMenuButton" || + type == "WindowListButton" || + type == "BookmarksButton" || + type == "DesktopButton" || + type == "BrowserButton" || + type == "ExecButton" || + type == "ExtensionButton") + { + list.append(*it); + } + } + + return list; + } + + for (BaseContainer::ConstIterator it = m_containers.constBegin(); + it != m_containers.constEnd(); + ++it) + { + if ((*it)->appletType() == type) + { + list.append(*it); + } + } + + return list; +} + +int ContainerArea::containerCount(const QString& type) const +{ + if (type.isEmpty() || type == "All") + { + return m_containers.count(); + } + + int count = 0; + if (type == "Special Button") + { + for (BaseContainer::ConstIterator it = m_containers.begin(); + it != m_containers.end(); + ++it) + { + QString type = (*it)->appletType(); + if (type == "KMenuButton" || + type == "WindowListButton" || + type == "BookmarksButton" || + type == "DesktopButton" || + type == "BrowserButton" || + type == "ExecButton" || + type == "ExtensionButton") + { + ++count; + } + } + + return count; + } + + for (BaseContainer::ConstIterator it = m_containers.begin(); + it != m_containers.end(); + ++it) + { + if ((*it)->appletType() == type) + { + ++count; + } + } + + return count; +} + +QStringList ContainerArea::listContainers() const +{ + return m_layout->listItems(); +} + +void ContainerArea::repaint() +{ + Panner::repaint(); +} + +void ContainerArea::showAddAppletDialog() +{ + if (!m_addAppletDialog) + { + m_addAppletDialog = new AddAppletDialog(this, this, 0); + connect(m_addAppletDialog, SIGNAL(finished()), this, SLOT(addAppletDialogDone())); + } + else + { + // this ensures that if we get shown again via the menu + // that the dialog picks up + // the new place to insert things + m_addAppletDialog->updateInsertionPoint(); + } + + KWin::setOnDesktop(m_addAppletDialog->winId(), KWin::currentDesktop()); + m_addAppletDialog->show(); + m_addAppletDialog->raise(); +} + +void ContainerArea::addAppletDialogDone() +{ + m_addAppletDialog->deleteLater(); + m_addAppletDialog = 0; +} + +const QPixmap* ContainerArea::completeBackgroundPixmap() const +{ + return &_completeBg; +} + +int ContainerArea::widthForHeight(int h) const +{ + return m_layout->widthForHeight(h); +} + +int ContainerArea::heightForWidth(int w) const +{ + return m_layout->heightForWidth(w); +} + + +DragIndicator::DragIndicator(QWidget* parent, const char* name) + : QWidget(parent, name) +{ + setBackgroundOrigin(AncestorOrigin); +} + + +void DragIndicator::paintEvent(QPaintEvent*) +{ + QPainter painter(this); + QRect rect(0, 0, width(), height()); + style().drawPrimitive( QStyle::PE_FocusRect, &painter, rect, colorGroup(), + QStyle::Style_Default, colorGroup().base() ); +} + +void DragIndicator::mousePressEvent(QMouseEvent*) +{ + hide(); +} + +#include "containerarea.moc" diff --git a/kicker/kicker/core/containerarea.h b/kicker/kicker/core/containerarea.h new file mode 100644 index 000000000..8b17c8ae9 --- /dev/null +++ b/kicker/kicker/core/containerarea.h @@ -0,0 +1,195 @@ +/***************************************************************** + +Copyright (c) 1996-2004 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __containerarea_h__ +#define __containerarea_h__ + +#include <qpixmap.h> +#include <qptrlist.h> +#include <qtimer.h> + +#include <appletinfo.h> + +#include "global.h" +#include "panner.h" +#include "container_base.h" + +class KConfig; +class DragIndicator; +class PanelContainer; +class KRootPixmap; + +class AppletContainer; +class ContainerAreaLayout; +class AddAppletDialog; + +class ContainerArea : public Panner +{ + Q_OBJECT + +public: + ContainerArea( KConfig* config, QWidget* parent, QPopupMenu* opMenu, const char* name = 0 ); + ~ContainerArea(); + + void initialize(bool useDefaultConfig); + int position() const; + KPanelApplet::Direction popupDirection() const; + bool isImmutable() const; + + const QWidget* addButton(const AppletInfo& info); + const QWidget* addKMenuButton(); + const QWidget* addDesktopButton(); + const QWidget* addWindowListButton(); + const QWidget* addBookmarksButton(); + const QWidget* addServiceButton(const QString& desktopFile); + const QWidget* addURLButton(const QString &url); + const QWidget* addBrowserButton(); + const QWidget* addBrowserButton(const QString &startDir, + const QString& icon = QString("kdisknav")); + const QWidget* addServiceMenuButton(const QString& relPath); + const QWidget* addNonKDEAppButton(); + const QWidget* addNonKDEAppButton(const QString &name, + const QString &description, + const QString &filePath, + const QString &icon, + const QString &cmdLine, bool inTerm); + const QWidget* addExtensionButton(const QString& desktopFile); + AppletContainer* addApplet(const AppletInfo& info, + bool isImmutable = false, + int insertionIndex = -1); + + void configure(); + + bool inMoveOperation() const { return (_moveAC != 0); } + int widthForHeight(int height) const; + int heightForWidth(int width) const; + + const QPixmap* completeBackgroundPixmap() const; + + BaseContainer::List containers(const QString& type) const; + int containerCount(const QString& type) const; + QStringList listContainers() const; + bool canAddContainers() const; + +signals: + void maintainFocus(bool); + +public slots: + void resizeContents(int w, int h); + bool removeContainer(BaseContainer* a); + bool removeContainer(int index); + void removeContainers(BaseContainer::List containers); + void takeContainer(BaseContainer* a); + void setPosition(KPanelExtension::Position p); + void setAlignment(KPanelExtension::Alignment a); + void slotSaveContainerConfig(); + void repaint(); + void showAddAppletDialog(); + void addAppletDialogDone(); + +protected: + QString createUniqueId(const QString& appletType) const; + void completeContainerAddition(BaseContainer* container, + int insertionIndex = -1); + + bool eventFilter(QObject*, QEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent *); + void dragEnterEvent(QDragEnterEvent*); + void dragMoveEvent(QDragMoveEvent*); + void dragLeaveEvent(QDragLeaveEvent*); + void dropEvent(QDropEvent*); + void resizeEvent(QResizeEvent*); + void viewportResizeEvent(QResizeEvent*); + + void defaultContainerConfig(); + void loadContainers(const QStringList& containers); + void saveContainerConfig(bool layoutOnly = false); + + QRect availableSpaceFollowing(BaseContainer*); + void moveDragIndicator(int pos); + + void scrollTo(BaseContainer*); + + void addContainer(BaseContainer* a, + bool arrange = false, + int insertionIndex = -1); + void removeAllContainers(); + +protected slots: + void autoScroll(); + void updateBackground(const QPixmap&); + void setBackground(); + void immutabilityChanged(bool); + void updateContainersBackground(); + void startContainerMove(BaseContainer*); + void resizeContents(); + void destroyCachedGeometry(); + +private: + BaseContainer::List m_containers; + BaseContainer* _moveAC; + KPanelExtension::Position _pos; + KConfig* _config; + DragIndicator* _dragIndicator; + BaseContainer* _dragMoveAC; + QPoint _dragMoveOffset; + QPopupMenu* m_opMenu; + KRootPixmap* _rootPixmap; + bool _transparent; + bool _useBgTheme; + bool _bgSet; + QPixmap _completeBg; + QTimer _autoScrollTimer; + bool m_canAddContainers; + bool m_immutable; + bool m_updateBackgroundsCalled; + + QWidget* m_contents; + ContainerAreaLayout* m_layout; + AddAppletDialog* m_addAppletDialog; + QMap< QWidget*, QRect > m_cachedGeometry; +}; + + +class DragIndicator : public QWidget +{ + Q_OBJECT + +public: + DragIndicator(QWidget* parent = 0, const char* name = 0); + ~DragIndicator() {} + + QSize preferredSize() const { return _preferredSize; } + void setPreferredSize(const QSize& size) { _preferredSize = size; } + +protected: + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent*); + +private: + QSize _preferredSize; +}; + +#endif + diff --git a/kicker/kicker/core/containerarealayout.cpp b/kicker/kicker/core/containerarealayout.cpp new file mode 100644 index 000000000..a865bec86 --- /dev/null +++ b/kicker/kicker/core/containerarealayout.cpp @@ -0,0 +1,803 @@ +/***************************************************************** + +Copyright (c) 1996-2004 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <assert.h> +#include <math.h> + +#include <qapplication.h> +#include <kdebug.h> +#include <kglobal.h> + +#include "containerarea.h" +#include "containerarealayout.h" +#include "container_applet.h" +#include "container_button.h" + +class ContainerAreaLayoutIterator : public QGLayoutIterator +{ + public: + ContainerAreaLayoutIterator(ContainerAreaLayout::ItemList *l) + : m_idx(0), m_list(l) + { + } + + QLayoutItem* current() + { + return m_idx < int(m_list->count()) ? (*m_list->at(m_idx))->item : 0; + } + + QLayoutItem* next() + { + m_idx++; + return current(); + } + + QLayoutItem* takeCurrent() + { + QLayoutItem* item = 0; + ContainerAreaLayout::ItemList::iterator b = m_list->at(m_idx); + if (b != m_list->end()) + { + ContainerAreaLayoutItem* layoutItem = *b; + item = layoutItem->item; + layoutItem->item = 0; + m_list->erase(b); + delete layoutItem; + } + return item; + } + + private: + int m_idx; + ContainerAreaLayout::ItemList* m_list; +}; + + +int ContainerAreaLayoutItem::heightForWidth(int w) const +{ + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + if (container) + { + return container->heightForWidth(w); + } + else + { + return item->sizeHint().height(); + } +} + +int ContainerAreaLayoutItem::widthForHeight(int h) const +{ + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + if (container) + { + return container->widthForHeight(h); + } + else + { + return item->sizeHint().width(); + } +} + +bool ContainerAreaLayoutItem::isStretch() const +{ + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + return container ? container->isStretch() : false; +} + +double ContainerAreaLayoutItem::freeSpaceRatio() const +{ + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + if (container) + return kClamp(container->freeSpace(), 0.0, 1.0); + else + return m_freeSpaceRatio; +} + +void ContainerAreaLayoutItem::setFreeSpaceRatio(double ratio) +{ + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + if (container) + container->setFreeSpace(ratio); + else + m_freeSpaceRatio = ratio; +} + +Qt::Orientation ContainerAreaLayoutItem::orientation() const +{ + return m_layout->orientation(); +} + +QRect ContainerAreaLayoutItem::geometryR() const +{ + return m_layout->transform(geometry()); +} + +void ContainerAreaLayoutItem::setGeometryR(const QRect& r) +{ + setGeometry(m_layout->transform(r)); +} + +int ContainerAreaLayoutItem::widthForHeightR(int h) const +{ + if (orientation() == Horizontal) + { + return widthForHeight(h); + } + else + { + return heightForWidth(h); + } +} + +int ContainerAreaLayoutItem::widthR() const +{ + if (orientation() == Horizontal) + { + return geometry().width(); + } + else + { + return geometry().height(); + } +} + +int ContainerAreaLayoutItem::heightR() const +{ + if (orientation() == Horizontal) + { + return geometry().height(); + } + else + { + return geometry().width(); + } +} + +int ContainerAreaLayoutItem::leftR() const +{ + if (orientation() == Horizontal) + { + if (QApplication::reverseLayout()) + return m_layout->geometry().right() - geometry().right(); + else + return geometry().left(); + } + else + { + return geometry().top(); + } +} + +int ContainerAreaLayoutItem::rightR() const +{ + if (orientation() == Horizontal) + { + if (QApplication::reverseLayout()) + return m_layout->geometry().right() - geometry().left(); + else + return geometry().right(); + } + else + { + return geometry().bottom(); + } +} + + +ContainerAreaLayout::ContainerAreaLayout(QWidget* parent) + : QLayout(parent), + m_orientation(Horizontal), + m_stretchEnabled(true) +{ +} + +void ContainerAreaLayout::addItem(QLayoutItem* item) +{ + m_items.append(new ContainerAreaLayoutItem(item, this)); +} + +void ContainerAreaLayout::insertIntoFreeSpace(QWidget* widget, QPoint insertionPoint) +{ + if (!widget) + { + return; + } + + add(widget); + ContainerAreaLayoutItem* item = m_items.last(); + + if (!item) + { + // this should never happen as we just added the item above + // but we do this to be safe. + return; + } + + ItemList::iterator currentIt = m_items.begin(); + if (currentIt == m_items.end()) + { + // this shouldn't happen either, but again... we try and be safe + return; + } + + ItemList::iterator nextIt = m_items.begin(); + ++nextIt; + + if (nextIt == m_items.end()) + { + // first item in! + item->setGeometryR(QRect(insertionPoint.x(), insertionPoint.y(), widget->width(), widget->height())); + updateFreeSpaceValues(); + return; + } + + int insPos = (orientation() == Horizontal) ? insertionPoint.x(): insertionPoint.y(); + Item* current = *currentIt; + Item* next = *nextIt; + + for (; nextIt != m_items.end(); ++currentIt, ++nextIt) + { + next = *nextIt; + current = *currentIt; + if (current == item || next == item) + { + continue; + } + + if (insPos == 0) + { + if (current->rightR() + 3 < next->leftR()) + { + insPos = current->rightR(); + break; + } + } + else + { + if (currentIt == m_items.begin() && + (current->leftR() > insPos || + (current->leftR() <= insPos) && + (current->rightR() > insPos))) + { + break; + } + + if ((current->rightR() < insPos) && (next->leftR() > insPos)) + { + // Free space available at insertion point! + if (insPos + item->widthR() > next->leftR()) + { + // We have overlap on the right, move to the left + insPos = next->leftR() - item->widthR(); + if (insPos < current->rightR()) + { + // We have overlap on the left as well, move to the right + insPos = current->rightR(); + // We don't fit entirely, let updateFreeSpaceValues sort it out + } + } + current = next; + break; + } + + if ((next->leftR() <= insPos) && (next->rightR() > insPos)) + { + // Insert at the location of next + current = next; + insPos = next->leftR(); + break; + } + } + } + + QRect geom = item->geometryR(); + geom.moveLeft(insPos); + item->setGeometryR(geom); + widget->setGeometry(transform(geom)); // widget isn't shown, layout not active yet + + if (current) + { + m_items.erase(m_items.fromLast()); + ItemList::iterator insertIt = m_items.find(current); + + if (insertIt == m_items.begin()) + { + m_items.push_front(item); + } + else if (insertIt == m_items.end()) + { + // yes, we just removed it from the end, but + // if we remove it afterwards and it insertIt + // was our item then we end up with a bad iterator + m_items.append(item); + } + else + { + m_items.insert(insertIt, item); + } + } + + updateFreeSpaceValues(); +} + +QStringList ContainerAreaLayout::listItems() const +{ + QStringList items; + for (ItemList::const_iterator it = m_items.constBegin(); + it != m_items.constEnd(); ++it) + { + QLayoutItem* item = (*it)->item; + BaseContainer* container = dynamic_cast<BaseContainer*>(item->widget()); + + if (!container) + { + continue; + } + + AppletContainer* applet = dynamic_cast<AppletContainer*>(container); + if (applet) + { + items.append(applet->info().desktopFile()); + } + else + { + // button containers don't give us anything useful that isn't + // i18n'd (e.g. all service buttons and url buttons simply report + // "URL" as their tileName()) which would require that we + // extend PanelButton to be more expressive to get something more + // instead i just cop'd out and use the visible name. good enough. + items.append(container->visibleName()); + } + } + + return items; +} + +QWidget* ContainerAreaLayout::widgetAt(int index) const +{ + if (index < 0 || index >= (int)m_items.count()) + { + return 0; + } + + return m_items[index]->item->widget(); +} + +QSize ContainerAreaLayout::sizeHint() const +{ + const int size = KickerLib::sizeValue(KPanelExtension::SizeNormal); + + if (orientation() == Horizontal) + { + return QSize(widthForHeight(size), size); + } + else + { + return QSize(size, heightForWidth(size)); + } +} + +QSize ContainerAreaLayout::minimumSize() const +{ + const int size = KickerLib::sizeValue(KPanelExtension::SizeTiny); + + if (orientation() == Horizontal) + { + return QSize(widthForHeight(size), size); + } + else + { + return QSize(size, heightForWidth(size)); + } +} + +QLayoutIterator ContainerAreaLayout::iterator() +{ + return QLayoutIterator(new ContainerAreaLayoutIterator(&m_items)); +} + +void ContainerAreaLayout::setGeometry(const QRect& rect) +{ + //RESEARCH: when can we short curcuit this? + // maybe a dirty flag to be set when we have containers + // that needs laying out? + + QLayout::setGeometry(rect); + + float totalFreeSpace = kMax(0, widthR() - widthForHeightR(heightR())); + int occupiedSpace = 0; + + ItemList::const_iterator it = m_items.constBegin(); + while (it != m_items.constEnd()) + { + ContainerAreaLayoutItem* cur = *it; + ++it; + ContainerAreaLayoutItem* next = (it != m_items.constEnd()) ? *it : 0; + + double fs = cur->freeSpaceRatio(); + double freeSpace = fs * totalFreeSpace; + int pos = int(rint(freeSpace)) + occupiedSpace; + + int w = cur->widthForHeightR(heightR()); + occupiedSpace += w; + if (m_stretchEnabled && cur->isStretch()) + { + if (next) + { + double nfs = next->freeSpaceRatio(); + w += int((nfs - fs)*totalFreeSpace); + } + else + { + w = widthR() - pos; + } + } + cur->setGeometryR(QRect(pos, 0, w, heightR())); + } +} + +int ContainerAreaLayout::widthForHeight(int h) const +{ + int width = 0; + ItemList::const_iterator it = m_items.constBegin(); + for (; it != m_items.constEnd(); ++it) + { + width += kMax(0, (*it)->widthForHeight(h)); + } + return width; +} + +int ContainerAreaLayout::heightForWidth(int w) const +{ + int height = 0; + ItemList::const_iterator it = m_items.constBegin(); + for (; it != m_items.constEnd(); ++it) + { + height += kMax(0, (*it)->heightForWidth(w)); + } + return height; +} + +void ContainerAreaLayout::setStretchEnabled(bool enable) +{ + if (m_stretchEnabled != enable) + { + m_stretchEnabled = enable; + activate(); + } +} + +void ContainerAreaLayout::updateFreeSpaceValues() +{ + int freeSpace = + kMax(0, widthR() - widthForHeightR(heightR())); + + double fspace = 0; + for (ItemList::const_iterator it = m_items.constBegin(); + it != m_items.constEnd(); + ++it) + { + int distance = distanceToPreviousItem(it); + if (distance < 0) distance = 0; + fspace += distance; + double ssf = ( freeSpace == 0 ? 0 : fspace/freeSpace ); + if (ssf > 1) ssf = 1; + if (ssf < 0) ssf = 0; + (*it)->setFreeSpaceRatio(ssf); + } +} + +int ContainerAreaLayout::distanceToPreviousItem(ItemList::const_iterator it) const +{ + assert(it != m_items.constEnd()); + + ContainerAreaLayoutItem* cur = *it; + --it; + ContainerAreaLayoutItem* prev = (it != m_items.constEnd()) ? *it : 0; + + return prev ? cur->leftR() - prev->leftR() - prev->widthForHeightR(heightR()) : + cur->leftR() - leftR(); +} + +void ContainerAreaLayout::moveContainerSwitch(QWidget* container, int distance) +{ + const bool horizontal = orientation() == Horizontal; + const bool reverseLayout = QApplication::reverseLayout(); + + if (horizontal && reverseLayout) + distance = - distance; + + const bool forward = distance > 0; + + // Get the iterator 'it' pointing to 'moving'. + ItemList::const_iterator it = m_items.constBegin(); + while (it != m_items.constEnd() && (*it)->item->widget() != container) + { + ++it; + } + + if (it == m_items.constEnd()) + { + return; + } + + ContainerAreaLayoutItem* moving = *it; + forward ? ++it : --it; + ContainerAreaLayoutItem* next = (it != m_items.constEnd()) ? *it : 0; + ContainerAreaLayoutItem* last = moving; + + while (next) + { + // Calculate the position and width of the virtual container + // containing 'moving' and 'next'. + int tpos = forward ? next->leftR() - moving->widthR() + : next->leftR(); + int tsize = moving->widthR() + next->widthR(); + + // Determine the middle of the containers. + int tmiddle = tpos + tsize / 2; + int movingMiddle = moving->leftR() + distance + moving->widthR() / 2; + + // Check if the middle of 'moving' has moved past the middle of the + // virtual container. + if (!forward && movingMiddle > tmiddle + || forward && movingMiddle < tmiddle) + break; + + // Move 'next' to the other side of 'moving'. + QRect geom = next->geometryR(); + if (forward) + geom.moveLeft(geom.left() - moving->widthR()); + else + geom.moveLeft(geom.left() + moving->widthR()); + next->setGeometryR(geom); + + // Store 'next'. It may become null in the next iteration, but we + // need its value later. + last = next; + forward ? ++it : --it; + next = (it != m_items.constEnd()) ? *it : 0; + } + + int newPos = moving->leftR() + distance; + if (last != moving) + { + // The case that moving has switched position with at least one other container. + newPos = forward ? kMax(newPos, last->rightR() + 1) + : kMin(newPos, last->leftR() - moving->widthR()); + + // Move 'moving' to its new position in the container list. + ItemList::iterator itMoving = m_items.find(moving); + + if (itMoving != m_items.end()) + { + ItemList::iterator itLast = itMoving; + if (forward) + { + ++itLast; + ++itLast; + } + else + { + --itLast; + } + + m_items.erase(itMoving); + + if (itLast == m_items.end()) + { + if (forward) + { + m_items.append(moving); + } + else + { + m_items.push_front(moving); + } + } + else + { + m_items.insert(itLast, moving); + } + } + } + else if (next) + { + // Make sure that the moving container will not overlap the next one. + newPos = forward ? kMin(newPos, next->leftR() - moving->widthR()) + : kMax(newPos, next->rightR() + 1); + } + + // Move the container to its new position and prevent it from moving outside the panel. + QRect geom = moving->geometryR(); + distance = kClamp(newPos, 0, widthR() - moving->widthR()); + geom.moveLeft(distance); + moving->setGeometryR(geom); + + // HACK - since the menuapplet is not movable by the user, make sure it's always left-aligned + ItemList::const_iterator prev = m_items.constEnd(); + for( ItemList::const_iterator it = m_items.constBegin(); + it != m_items.constEnd(); + ( prev = it ), ++it ) + { + if( BaseContainer* container = dynamic_cast<BaseContainer*>((*it)->item->widget())) + if(AppletContainer* applet = dynamic_cast<AppletContainer*>(container)) + if( applet->info().desktopFile() == "menuapplet.desktop" ) + { + QRect geom = (*it)->geometryR(); + if( prev != m_items.constEnd()) + geom.moveLeft( (*prev)->rightR() + 1 ); + else + geom.moveLeft( 0 ); + (*it)->setGeometryR( geom ); + } + } + + updateFreeSpaceValues(); +} + +int ContainerAreaLayout::moveContainerPush(QWidget* a, int distance) +{ + const bool horizontal = orientation() == Horizontal; + const bool reverseLayout = QApplication::reverseLayout(); + + // Get the iterator 'it' pointing to the layoutitem representing 'a'. + ItemList::const_iterator it = m_items.constBegin(); + while (it != m_items.constEnd() && (*it)->item->widget() != a) + { + ++it; + } + + if (it != m_items.constEnd()) + { + if (horizontal && reverseLayout) + { + distance = -distance; + } + + int retVal = moveContainerPushRecursive(it, distance); + updateFreeSpaceValues(); + if (horizontal && reverseLayout) + { + retVal = -retVal; + } + return retVal; + } + else + { + return 0; + } +} + +int ContainerAreaLayout::moveContainerPushRecursive(ItemList::const_iterator it, + int distance) +{ + if (distance == 0) + return 0; + + const bool forward = distance > 0; + + int available; // Space available for the container to move. + int moved; // The actual distance the container will move. + ContainerAreaLayoutItem* cur = *it; + forward ? ++it : --it; + ContainerAreaLayoutItem* next = (it != m_items.constEnd()) ? *it : 0; + + if (!next) + { + available = forward ? rightR() - cur->rightR() + : -cur->leftR(); + } + else + { + available = forward ? next->leftR() - cur->rightR() - 1 + : next->rightR() - cur->leftR() + 1; + + if (!forward && distance < available + || forward && distance > available) + available += moveContainerPushRecursive(it, distance - available); + } + moved = forward ? kMin(distance, available) + : kMax(distance, available); + + QRect geom = cur->geometryR(); + geom.moveLeft(geom.left() + moved); + cur->setGeometryR(geom); + + return moved; +} + +QRect ContainerAreaLayout::transform(const QRect& r) const +{ + if (orientation() == Horizontal) + { + if (QApplication::reverseLayout()) + { + QRect t = r; + t.moveLeft(geometry().right() - r.right()); + return t; + } + else + { + return r; + } + } + else + { + return QRect(r.y(), r.x(), r.height(), r.width()); + } +} + +int ContainerAreaLayout::widthForHeightR(int h) const +{ + if (orientation() == Horizontal) + { + return widthForHeight(h); + } + else + { + return heightForWidth(h); + } +} + +int ContainerAreaLayout::widthR() const +{ + if (orientation() == Horizontal) + { + return geometry().width(); + } + else + { + return geometry().height(); + } +} + +int ContainerAreaLayout::heightR() const +{ + if (orientation() == Horizontal) + { + return geometry().height(); + } + else + { + return geometry().width(); + } +} + +int ContainerAreaLayout::leftR() const +{ + if (orientation() == Horizontal) + return geometry().left(); + else + return geometry().top(); +} + +int ContainerAreaLayout::rightR() const +{ + if (orientation() == Horizontal) + return geometry().right(); + else + return geometry().bottom(); +} + diff --git a/kicker/kicker/core/containerarealayout.h b/kicker/kicker/core/containerarealayout.h new file mode 100644 index 000000000..4d4e0561d --- /dev/null +++ b/kicker/kicker/core/containerarealayout.h @@ -0,0 +1,120 @@ +/***************************************************************** + +Copyright (c) 1996-2004 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __containerarealayout_h__ +#define __containerarealayout_h__ + +#include <qlayout.h> + +class ContainerAreaLayout; + +class ContainerAreaLayoutItem : public Qt +{ + public: + ContainerAreaLayoutItem(QLayoutItem* i, ContainerAreaLayout* layout) + : item(i), + m_freeSpaceRatio(0.0), + m_layout(layout) + {} + + ~ContainerAreaLayoutItem() + { delete item; } + + int heightForWidth(int w) const; + int widthForHeight(int h) const; + + bool isStretch() const; + + QRect geometry() const + { return item->geometry(); } + void setGeometry(const QRect& geometry) + { item->setGeometry(geometry); } + + double freeSpaceRatio() const; + void setFreeSpaceRatio(double ratio); + + Orientation orientation() const; + + // Relative geometry + QRect geometryR() const; + void setGeometryR(const QRect&); + int widthForHeightR(int w) const; + int widthR() const; + int heightR() const; + int leftR() const; + int rightR() const; + + QLayoutItem* item; + + private: + double m_freeSpaceRatio; + ContainerAreaLayout* m_layout; +}; + +class ContainerAreaLayout : public QLayout +{ + public: + typedef ContainerAreaLayoutItem Item; + typedef QValueList<Item*> ItemList; + + ContainerAreaLayout(QWidget* parent); + + void addItem(QLayoutItem* item); + void insertIntoFreeSpace(QWidget* item, QPoint insertionPoint); + QStringList listItems() const; + QWidget* widgetAt(int index) const; + QSize sizeHint() const; + QSize minimumSize() const; + QLayoutIterator iterator(); + void setGeometry(const QRect& rect); + + Orientation orientation() const { return m_orientation; } + void setOrientation(Orientation o) { m_orientation = o; } + int heightForWidth(int w) const; + int widthForHeight(int h) const; + void updateFreeSpaceValues(); + void moveToFirstFreePosition(BaseContainer* a); + + void setStretchEnabled(bool enable); + + void moveContainerSwitch(QWidget* container, int distance); + int moveContainerPush(QWidget* container, int distance); + + // Relative geometry + QRect transform(const QRect&) const; + int widthForHeightR(int w) const; + int widthR() const; + int heightR() const; + int leftR() const; + int rightR() const; + + private: + int moveContainerPushRecursive(ItemList::const_iterator it, int distance); + int distanceToPreviousItem(ItemList::const_iterator it) const; + + Orientation m_orientation; + bool m_stretchEnabled; + ItemList m_items; +}; + +#endif diff --git a/kicker/kicker/core/default-apps b/kicker/kicker/core/default-apps new file mode 100644 index 000000000..7505e5279 --- /dev/null +++ b/kicker/kicker/core/default-apps @@ -0,0 +1,2 @@ +Home.desktop +Internet/konqbrowser.desktop diff --git a/kicker/kicker/core/extensionSettings.kcfg b/kicker/kicker/core/extensionSettings.kcfg new file mode 100644 index 000000000..dcf7edd23 --- /dev/null +++ b/kicker/kicker/core/extensionSettings.kcfg @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + +<include>kapplication.h</include> +<include>kpanelextension.h</include> +<include>unhidetrigger.h</include> +<kcfgfile arg="true"/> +<group name="General"> + +<entry name="IExist" type="Bool"> + <label>Whether this panel actually exists or not. Primarily to work around the fact that KConfigXT won't write a config file unless there is at least one non-default entry.</label> + <default>false</default> +</entry> +<entry name="Position" type="Int" > + <label>The position of the panel</label> + <default code="true">KPanelExtension::Bottom</default> + <min>0</min> + <max>3</max> + </entry> + +<entry name="Alignment" type="Int" > + <label>The alignment of the panel</label> + <default code="true">KPanelExtension::Left</default> + <min>0</min> + <max>2</max> + </entry> + +<entry name="XineramaScreen" type="Int"> + <label>Primary xinerama screen</label> + <default code="true">QApplication::desktop()->primaryScreen()</default> + </entry> + +<entry name="HideButtonSize" type="Int" > + <label>Hide button size</label> + <default>14</default> + <min>3</min> + <max>48</max> + </entry> + +<entry name="ShowLeftHideButton" type="Bool" > + <label>Show left panel hide button</label> + <default>false</default> + </entry> + +<entry name="ShowRightHideButton" type="Bool" > + <label>Show right panel hide button</label> + <default>false</default> + </entry> + +<entry name="AutoHidePanel" type="Bool" > + <label>Auto hide panel</label> + <default>false</default> + </entry> + +<entry name="AutoHideSwitch" type="Bool" > + <label>Enable auto hide</label> + <default>false</default> + </entry> + +<entry name="AutoHideDelay" type="Int" > + <label>Delay before auto hide</label> + <default>3</default> + </entry> + +<entry name="UnhideLocation" type="Int" > + <label>The trigger location for unhides</label> + <default code="true">UnhideTrigger::None</default> + <min code="true">UnhideTrigger::None</min> + <max code="true">UnhideTrigger::TopLeft</max> + </entry> + +<entry name="BackgroundHide" type="Bool" > + <label>Enable background hiding</label> + <default>false</default> + </entry> + +<entry name="HideAnimation" type="Bool" > + <label>Animate panel hiding</label> + <default>true</default> + </entry> + +<entry name="HideAnimationSpeed" type="Int" > + <label>Panel hiding animation speed</label> + <default>40</default> + </entry> + +<entry name="SizePercentage" type="Int" > + <label>Length in percentage</label> + <default>100</default> + <min>1</min> + <max>100</max> + </entry> + +<entry name="ExpandSize" type="Bool" > + <label>Expand as required to fit contents</label> + <default>true</default> + </entry> + +<entry name="Size" type="Int"> + <label>Size</label> + <default code="true">KPanelExtension::SizeNormal</default> + </entry> + +<entry name="CustomSize" type="Int" > + <label>Custom size</label> + <default>58</default> + <min>16</min> + </entry> + +</group> +</kcfg> diff --git a/kicker/kicker/core/extensionSettings.kcfgc b/kicker/kicker/core/extensionSettings.kcfgc new file mode 100644 index 000000000..bee651f64 --- /dev/null +++ b/kicker/kicker/core/extensionSettings.kcfgc @@ -0,0 +1,5 @@ +File=extensionSettings.kcfg +Singleton=false +ClassName=ExtensionSettings +Mutators=true +IncludeFiles=kpanelextension.h diff --git a/kicker/kicker/core/extensionmanager.cpp b/kicker/kicker/core/extensionmanager.cpp new file mode 100644 index 000000000..d6342b8f9 --- /dev/null +++ b/kicker/kicker/core/extensionmanager.cpp @@ -0,0 +1,773 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> +Copyright (c) 2004-2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> + +#include <kaboutdata.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmenubar.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kwinmodule.h> +#include <dcopref.h> + +#include "container_extension.h" +#include "global.h" +#include "kicker.h" +#include "panelextension.h" +#include "pluginmanager.h" + +#include "extensionmanager.h" + +ExtensionManager* ExtensionManager::m_self = 0; + +ExtensionManager* ExtensionManager::the() +{ + if (!m_self) + { + m_self = new ExtensionManager; + } + + return m_self; +} + +ExtensionManager::ExtensionManager() + : QObject(0, "ExtensionManager"), + m_menubarPanel(0), + m_mainPanel(0), + m_panelCounter(-1) +{ +} + +ExtensionManager::~ExtensionManager() +{ + if (this == m_self) + { + m_self = 0; + } + + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); it != itEnd; ++it) + { + delete *it; + } + _containers.clear(); + + delete m_menubarPanel; + delete m_mainPanel; +} + +void ExtensionManager::initialize() +{ +// kdDebug(1210) << "ExtensionManager::loadContainerConfig()" << endl; + KConfig* config = KGlobal::config(); + PluginManager* pm = PluginManager::the(); + + // set up the "main" panel + if (config->hasGroup("Main Panel")) + { + config->setGroup("Main Panel"); + if (config->hasKey("DesktopFile")) + { + m_mainPanel = pm->createExtensionContainer(config->readPathEntry("DesktopFile"), + true, config->readPathEntry("ConfigFile"), + "Main Panel"); + } + } + + if (!m_mainPanel) + { + // fall back to a regular ol' PanelExtension + m_mainPanel = pm->createExtensionContainer( + "childpanelextension.desktop", + true, + QString(kapp->aboutData()->appName()) + "rc", + "Main Panel"); + } + + if (!m_mainPanel) + { + KMessageBox::error(0, i18n("The KDE panel (kicker) could not load the main panel " + "due to a problem with your installation. "), + i18n("Fatal Error!")); + exit(1); + } + + configureMenubar(true); + + Kicker::the()->setMainWidget(m_mainPanel); + + m_mainPanel->readConfig(); + m_mainPanel->show(); + kapp->processEvents(); + + // read extension list + config->setGroup("General"); + QStringList elist = config->readListEntry("Extensions2"); + + // now restore the extensions + QStringList::iterator itEnd = elist.end(); + for (QStringList::iterator it = elist.begin(); it != elist.end(); ++it) + { + // extension id + QString extensionId(*it); + + // create a matching applet container + if (extensionId.find("Extension") == -1) + { + continue; + } + + // is there a config group for this extension? + if (!config->hasGroup(extensionId)) + { + continue; + } + + // set config group + config->setGroup(extensionId); + + ExtensionContainer* e = pm->createExtensionContainer(config->readPathEntry("DesktopFile"), + true, // is startup + config->readPathEntry("ConfigFile"), + extensionId); + if (e) + { + addContainer(e); + e->readConfig(); + e->show(); + kapp->processEvents(); + } + } + + pm->clearUntrustedLists(); + connect(Kicker::the(), SIGNAL(configurationChanged()), SLOT(configurationChanged())); + DCOPRef r( "ksmserver", "ksmserver" ); + r.send( "resumeStartup", QCString( "kicker" )); +} + +void ExtensionManager::configureMenubar(bool duringInit) +{ + KConfig menuConfig( "kdesktoprc", true ); + if( KConfigGroup( &menuConfig, "KDE" ).readBoolEntry("macStyle", false) + || KConfigGroup( &menuConfig, "Menubar" ).readBoolEntry( "ShowMenubar", false )) + { + if (KGlobal::dirs()->findResource("applets", "menuapplet.desktop").isEmpty() || + m_menubarPanel) + { + return; + } + + if (duringInit) + { + AppletInfo menubarInfo("menuapplet.desktop", QString::null, AppletInfo::Applet); + if (PluginManager::the()->hasInstance(menubarInfo)) + { + // it's already there, in the main panel! + return; + } + migrateMenubar(); + } + + AppletInfo info("childpanelextension.desktop", + "kicker_menubarpanelrc", + AppletInfo::Extension); + KPanelExtension* menubar = new MenubarExtension(info); + m_menubarPanel = new ExtensionContainer(menubar, info, "Menubar Panel"); + m_menubarPanel->setPanelOrder(-1); + m_menubarPanel->readConfig(); + m_menubarPanel->setPosition(KPanelExtension::Top); + m_menubarPanel->setXineramaScreen(XineramaAllScreens); + m_menubarPanel->setHideButtons(false, false); + + // this takes care of resizing the panel so it shows with the right height + updateMenubar(); + + m_menubarPanel->show(); + connect(kapp, SIGNAL(kdisplayFontChanged()), SLOT(updateMenubar())); + } + else if (m_menubarPanel) + { + int screen = m_menubarPanel->xineramaScreen(); + delete m_menubarPanel; + m_menubarPanel = 0; + + emit desktopIconsAreaChanged(desktopIconsArea(screen), screen); + } +} + +void ExtensionManager::migrateMenubar() +{ + // lame, lame, lame. + // the menubar applet was just plunked into kicker and not much + // thought was put into how it should be used. great idea, but no + // integration. >:-( + // so now we have to check to see if we HAVE another extension that + // will have a menubar in it, and if so, abort creating one of our + // own. + // + // the reason i didn't do this as a kconfig_update script is that + // most people don't use this feature, so no reason to penalize + // everyone, and moreover the user may added this to their main + // panel, meaning kickerrc itself would have to be vastly modified + // with lots of complications. not work it IMHO. + + KConfig* config = KGlobal::config(); + config->setGroup("General"); + + if (config->readBoolEntry("CheckedForMenubar", false)) + { + return; + } + + if (!locate("config", "kicker_menubarpanelrc").isEmpty()) + { + // don't overwrite/override something that's already there + return; + } + + QStringList elist = config->readListEntry("Extensions2"); + QStringList::iterator itEnd = elist.end(); + for (QStringList::iterator it = elist.begin(); it != elist.end(); ++it) + { + QString extensionId(*it); + + if (extensionId.find("Extension") == -1) + { + continue; + } + + // is there a config group for this extension? + if (!config->hasGroup(extensionId)) + { + continue; + } + + config->setGroup(extensionId); + QString extension = config->readPathEntry("ConfigFile"); + KConfig extensionConfig(locate("config", extension)); + extensionConfig.setGroup("General"); + + if (extensionConfig.hasKey("Applets2")) + { + QStringList containers = extensionConfig.readListEntry("Applets2"); + QStringList::iterator cit = containers.begin(); + QStringList::iterator citEnd = containers.end(); + for (; cit != citEnd; ++cit) + { + QString appletId(*cit); + + // is there a config group for this applet? + if (!extensionConfig.hasGroup(appletId)) + { + continue; + } + + KConfigGroup group(&extensionConfig, appletId.latin1()); + QString appletType = appletId.left(appletId.findRev('_')); + + if (appletType == "Applet") + { + QString appletFile = group.readPathEntry("DesktopFile"); + if (appletFile.find("menuapplet.desktop") != -1) + { + QString menubarConfig = locate("config", extension); + KIO::NetAccess::copy(menubarConfig, + locateLocal("config", + "kicker_menubarpanelrc"), 0); + elist.remove(it); + config->setGroup("General"); + config->writeEntry("Extensions2", elist); + config->writeEntry("CheckedForMenubar", true); + config->sync(); + return; + } + } + } + } + } + + config->setGroup("General"); + config->writeEntry("CheckedForMenubar", true); +} + +void ExtensionManager::saveContainerConfig() +{ +// kdDebug(1210) << "ExtensionManager::saveContainerConfig()" << endl; + + KConfig *config = KGlobal::config(); + + // build the extension list + QStringList elist; + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); it != itEnd; ++it) + { + elist.append((*it)->extensionId()); + } + + // write extension list + config->setGroup("General"); + config->writeEntry("Extensions2", elist); + + config->sync(); +} + +void ExtensionManager::configurationChanged() +{ + if (m_mainPanel) + { + m_mainPanel->readConfig(); + } + + if (m_menubarPanel) + { + m_menubarPanel->readConfig(); + } + + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); it != itEnd; ++it) + { + (*it)->readConfig(); + } +} + +void ExtensionManager::updateMenubar() +{ + if (!m_menubarPanel) + { + return; + } + + //kdDebug(0) << "ExtensionManager::updateMenubar()" << endl; + // we need to make sure the panel is tall enough to accomodate the + // menubar! an easy way to find out the height of a menu: make one ;) + KMenuBar tmpmenu; + tmpmenu.insertItem("KDE Rocks!"); + m_menubarPanel->setSize(KPanelExtension::SizeCustom, + tmpmenu.sizeHint().height()); + m_menubarPanel->writeConfig(); + + emit desktopIconsAreaChanged(desktopIconsArea(m_menubarPanel->xineramaScreen()), + m_menubarPanel->xineramaScreen()); +} + +bool ExtensionManager::isMainPanel(const QWidget* panel) const +{ + return m_mainPanel == panel; +} + +bool ExtensionManager::isMenuBar(const QWidget* panel) const +{ + return m_menubarPanel == panel; +} + +void ExtensionManager::addExtension( const QString& desktopFile ) +{ + PluginManager* pm = PluginManager::the(); + ExtensionContainer *e = pm->createExtensionContainer(desktopFile, + false, // is not startup + QString::null, // no config + uniqueId()); + + + kdDebug(1210) << "ExtensionManager::addExtension" << endl; + + if (e) + { + e->readConfig(); + // as a new panel, the position will be set to the preferred position + // we just need to make sure this works with the rest of the panel layout + e->setPosition(initialPanelPosition(e->position())); + kdDebug(1210)<<"after e->readConfig(): pos="<<e->position()<<endl; + addContainer(e); + e->show(); + e->writeConfig(); + saveContainerConfig(); + } +} + +void ExtensionManager::addContainer(ExtensionContainer* e) +{ + if (!e) + { + return; + } + + _containers.append(e); + + connect(e, SIGNAL(removeme(ExtensionContainer*)), + this, SLOT(removeContainer(ExtensionContainer*))); + + emit desktopIconsAreaChanged(desktopIconsArea(e->xineramaScreen()), + e->xineramaScreen()); +} + +void ExtensionManager::removeContainer(ExtensionContainer* e) +{ + if (!e) + { + return; + } + + e->removeSessionConfigFile(); + _containers.remove(e); + e->deleteLater(); // Wait till we return to the main event loop + saveContainerConfig(); + + emit desktopIconsAreaChanged(desktopIconsArea(e->xineramaScreen()), + e->xineramaScreen()); +} + +void ExtensionManager::removeAllContainers() +{ + while (!_containers.isEmpty()) + { + ExtensionContainer* e = _containers.first(); + _containers.remove(e); + e->deleteLater(); // Wait till we return to the main event loop + } + + saveContainerConfig(); +} + +QString ExtensionManager::uniqueId() +{ + QString idBase = "Extension_%1"; + QString newId; + int i = 0; + bool unique = false; + + while (!unique) + { + i++; + newId = idBase.arg(i); + + unique = true; + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); it != itEnd; ++it) + { + if ((*it)->extensionId() == newId) + { + unique = false; + break; + } + } + } + + return newId; +} + +KPanelExtension::Position ExtensionManager::initialPanelPosition(KPanelExtension::Position preferred) +{ + // Guess a good position + bool positions[KPanelExtension::Bottom+1]; + for( int i = 0; i <= (int) KPanelExtension::Bottom; ++i ) + { + positions[i] = true; + } + + ExtensionList::iterator itEnd = _containers.end(); + for (ExtensionList::iterator it = _containers.begin(); it != itEnd; ++it) + { + positions[(int) (*it)->position()] = false; + } + + KPanelExtension::Position pos = preferred; + if (positions[(int)pos]) + return pos; + + pos = (KPanelExtension::Position) (pos ^ 1); + if (positions[(int)pos]) + return pos; + + pos = (KPanelExtension::Position) (pos ^ 3); + if (positions[(int)pos]) + return pos; + + pos = (KPanelExtension::Position) (pos ^ 1); + if (positions[(int)pos]) + return pos; + + return preferred; +} + +bool ExtensionManager::shouldExclude(int XineramaScreen, + const ExtensionContainer* extension, + const ExtensionContainer* exclude) const +{ + // Rules of Exclusion: + // 0. Exclude ourselves + // 1. Exclude panels not on our Xinerama screen + // 2. Exclude panels on the same side of the screen as ourselves that are above us + // 3. Exclude panels on the opposite side of the screen. Breaks down if the user + // dabbles in insane layouts where a top/bottom or left/right pair overlap? + // 4. Exclude panels on adjacent sides of the screen that do not overlap with us + + if (exclude->winId() == extension->winId()) + { + // Rule 0 Exclusion + return true; + } + + if (extension->xineramaScreen()!= XineramaAllScreens && + exclude->xineramaScreen() != XineramaAllScreens && + exclude->xineramaScreen() != XineramaScreen) + { + // Rule 1 exclusion + return true; + } + + if (!exclude->reserveStrut()) + { + return true; + } + + bool lowerInStack = extension->panelOrder() < exclude->panelOrder(); + if (exclude->position() == extension->position()) + { + // Rule 2 Exclusion + if (extension->position() == KPanelExtension::Bottom && + exclude->geometry().bottom() == extension->geometry().bottom() && + !exclude->geometry().intersects(extension->geometry())) + { + return false; + } + else if (extension->position() == KPanelExtension::Top && + exclude->geometry().top() == extension->geometry().top() && + !exclude->geometry().intersects(extension->geometry())) + { + return false; + } + else if (extension->position() == KPanelExtension::Left && + exclude->geometry().left() == extension->geometry().left() && + !exclude->geometry().intersects(extension->geometry())) + { + return false; + } + else if (extension->position() == KPanelExtension::Right && + exclude->geometry().right() == extension->geometry().right() && + !exclude->geometry().intersects(extension->geometry())) + { + return false; + } + + return lowerInStack; + } + + // Rule 3 exclusion + if (exclude->orientation() == extension->orientation()) + { + // on the opposite side of the screen from us. + return true; + } + + // Rule 4 exclusion + if (extension->position() == KPanelExtension::Bottom) + { + if (exclude->geometry().bottom() > extension->geometry().top()) + { + return lowerInStack; + } + } + else if (extension->position() == KPanelExtension::Top) + { + if (exclude->geometry().top() < extension->geometry().bottom()) + { + return lowerInStack; + } + } + else if (extension->position() == KPanelExtension::Left) + { + if (exclude->geometry().left() < extension->geometry().right()) + { + return lowerInStack; + } + } + else /* if (extension->position() == KPanelExtension::Right) */ + { + if (exclude->geometry().right() > extension->geometry().left()) + { + return lowerInStack; + } + } + + return true; +} + +QRect ExtensionManager::workArea(int XineramaScreen, const ExtensionContainer* extension) +{ + if (!extension) + { + return Kicker::the()->kwinModule()->workArea(XineramaScreen); + } + + QValueList<WId> list; + + ExtensionList::iterator itEnd = _containers.end(); + ExtensionList::iterator it = _containers.begin(); + + // If the hide mode is Manual, exclude the struts of + // panels below this one in the list. Else exclude the + // struts of all panels. + if (extension->reserveStrut() && + extension != m_menubarPanel && + extension->hideMode() == ExtensionContainer::ManualHide) + { + if (m_mainPanel && shouldExclude(XineramaScreen, extension, m_mainPanel)) + { + list.append(m_mainPanel->winId()); + } + + for (; it != itEnd; ++it) + { + if (shouldExclude(XineramaScreen, extension, *it)) + { + list.append((*it)->winId()); + } + } + } + else + { + // auto hide panel? just ignore everything else for now. + if (extension == m_menubarPanel) + { + list.append(m_menubarPanel->winId()); + } + + if (m_mainPanel) + { + list.append(m_mainPanel->winId()); + } + + for (; it != itEnd; ++it) + { + list.append((*it)->winId()); + } + } + + QRect workArea; + if (XineramaScreen == XineramaAllScreens) + { + /* special value for all screens */ + workArea = Kicker::the()->kwinModule()->workArea(list); + } + else + { + workArea = Kicker::the()->kwinModule()->workArea(list, XineramaScreen) + .intersect(QApplication::desktop()->screenGeometry(XineramaScreen)); + } + + return workArea; +} + +int ExtensionManager::nextPanelOrder() +{ + ++m_panelCounter; + return m_panelCounter; +} + +void ExtensionManager::reduceArea(QRect &area, const ExtensionContainer *extension) const +{ + if (!extension || + extension->hideMode() == ExtensionContainer::AutomaticHide || + !extension->reserveStrut()) + { + return; + } + + QRect geom = extension->initialGeometry(extension->position(), extension->alignment(), + extension->xineramaScreen()); + + // reduce given area (QRect) to the space not covered by the given extension + // As simplification: the length of the extension is not taken into account + // which means that even a small extension e.g. on the left side of the desktop + // will remove the available area with its with + + switch (extension->position()) + { + case KPanelExtension::Left: + { + area.setLeft(QMAX(area.left(), geom.right())); + break; + } + case KPanelExtension::Right: + { + area.setRight(QMIN(area.right(), geom.left())); + break; + } + case KPanelExtension::Top: + { + area.setTop(QMAX(area.top(), geom.bottom())); + break; + } + case KPanelExtension::Bottom: + { + area.setBottom(QMIN(area.bottom(), geom.top())); + break; + } + default: ; // ignore KPanelExtension::Floating ... at least for now + } +} + +QRect ExtensionManager::desktopIconsArea(int screen) const +{ + // This is pretty broken, mixes Xinerama and non-Xinerama multihead + // and generally doesn't seem to be required anyway => ignore screen. +// QRect area = QApplication::desktop()->screenGeometry(screen); + QRect area = QApplication::desktop()->geometry(); + + reduceArea(area, m_mainPanel); + reduceArea(area, m_menubarPanel); + + for (ExtensionList::const_iterator it = _containers.constBegin(); + it != _containers.constEnd(); + ++it) + { + reduceArea(area, (*it)); + } + + kdDebug(1210) << "ExtensionManager::desktopIconsArea() = " << area + << " screen = " << screen << endl; + return area; +} + +void ExtensionManager::extensionSizeChanged(ExtensionContainer *extension) +{ + // we have to recalc the available space for desktop icons + if (!extension) + { + return; + } + + emit desktopIconsAreaChanged(desktopIconsArea(extension->xineramaScreen()), + extension->xineramaScreen()); +} + +#include "extensionmanager.moc" diff --git a/kicker/kicker/core/extensionmanager.h b/kicker/kicker/core/extensionmanager.h new file mode 100644 index 000000000..2885df01f --- /dev/null +++ b/kicker/kicker/core/extensionmanager.h @@ -0,0 +1,92 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __extensionmanager_h__ +#define __extensionmanager_h__ + +#include <qvaluelist.h> +#include <qobject.h> + +#include "container_extension.h" + +const int XineramaAllScreens = -2; + +class ExtensionManager : public QObject +{ + Q_OBJECT + +public: + static ExtensionManager* the(); + + void configureMenubar(bool duringInit); + void addExtension( const QString &desktopFile ); + bool isMainPanel(const QWidget* panel) const; + bool isMenuBar(const QWidget* panel) const; + void addContainer( ExtensionContainer* ); + void removeAllContainers(); + ExtensionList containers() const { return _containers; } + + KPanelExtension::Position initialPanelPosition(KPanelExtension::Position preferred); + QRect workArea(int XineramaScreen, const ExtensionContainer* container); + int nextPanelOrder(); + + // return the space available for all icons on the desktop + // subtracts all panels from XineramaScreen's geometry + QRect desktopIconsArea(int xineramaScreen) const; + +public slots: + void removeContainer( ExtensionContainer* ); + void initialize(); + void extensionSizeChanged(ExtensionContainer *); + +signals: + void desktopIconsAreaChanged(const QRect &, int xineramaScreen); + +protected: + friend class Kicker; + + ExtensionManager(); + ~ExtensionManager(); + QString uniqueId(); + void saveContainerConfig(); + bool shouldExclude(int XineramaScreen, + const ExtensionContainer* container, + const ExtensionContainer* exclude) const; + +protected slots: + void configurationChanged(); + void updateMenubar(); + +private: + void migrateMenubar(); + void reduceArea(QRect &area, const ExtensionContainer *panel) const; + + ExtensionList _containers; + ExtensionContainer* m_menubarPanel; + ExtensionContainer* m_mainPanel; + int m_panelCounter; + static ExtensionManager* m_self; +}; + +#endif + diff --git a/kicker/kicker/core/kicker.cpp b/kicker/kicker/core/kicker.cpp new file mode 100644 index 000000000..65e059c5b --- /dev/null +++ b/kicker/kicker/core/kicker.cpp @@ -0,0 +1,401 @@ +/***************************************************************** + + Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ******************************************************************/ + +#include <stdlib.h> +#include <unistd.h> + +#include <qfile.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <dcopclient.h> +#include <kconfig.h> +#include <kcmdlineargs.h> +#include <kcmultidialog.h> +#include <kcrash.h> +#include <kdebug.h> +#include <kdirwatch.h> +#include <kglobal.h> +#include <kglobalaccel.h> +#include <kiconloader.h> +#include <kimageio.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kwin.h> +#include <kwinmodule.h> + +#include "extensionmanager.h" +#include "pluginmanager.h" +#include "menumanager.h" +#include "k_mnu.h" +#include "showdesktop.h" +#include "panelbutton.h" + +#include "kicker.h" +#include "kickerSettings.h" + +#include "kicker.moc" + +Kicker* Kicker::the() { return static_cast<Kicker*>(kapp); } + +Kicker::Kicker() + : KUniqueApplication(), + keys(0), + m_kwinModule(0), + m_configDialog(0), + m_canAddContainers(true) +{ + // initialize the configuration object + KickerSettings::instance(instanceName() + "rc"); + + if (KCrash::crashHandler() == 0 ) + { + // this means we've most likely crashed once. so let's see if we + // stay up for more than 2 minutes time, and if so reset the + // crash handler since the crash isn't a frequent offender + QTimer::singleShot(120000, this, SLOT(setCrashHandler())); + } + else + { + // See if a crash handler was installed. It was if the -nocrashhandler + // argument was given, but the app eats the kde options so we can't + // check that directly. If it wasn't, don't install our handler either. + setCrashHandler(); + } + + // Make kicker immutable if configuration modules have been marked immutable + if (isKioskImmutable() && kapp->authorizeControlModules(Kicker::configModules(true)).isEmpty()) + { + config()->setReadOnly(true); + config()->reparseConfiguration(); + } + + dcopClient()->setDefaultObject("Panel"); + disableSessionManagement(); + QString dataPathBase = KStandardDirs::kde_default("data").append("kicker/"); + KGlobal::dirs()->addResourceType("mini", dataPathBase + "pics/mini"); + KGlobal::dirs()->addResourceType("icon", dataPathBase + "pics"); + KGlobal::dirs()->addResourceType("builtinbuttons", dataPathBase + "builtins"); + KGlobal::dirs()->addResourceType("specialbuttons", dataPathBase + "menuext"); + KGlobal::dirs()->addResourceType("applets", dataPathBase + "applets"); + KGlobal::dirs()->addResourceType("tiles", dataPathBase + "tiles"); + KGlobal::dirs()->addResourceType("extensions", dataPathBase + "extensions"); + + KImageIO::registerFormats(); + + KGlobal::iconLoader()->addExtraDesktopThemes(); + + KGlobal::locale()->insertCatalogue("libkonq"); + KGlobal::locale()->insertCatalogue("libdmctl"); + KGlobal::locale()->insertCatalogue("libtaskbar"); + + // initialize our keys + // note that this creates the KMenu by calling MenuManager::the() + keys = new KGlobalAccel( this ); +#define KICKER_ALL_BINDINGS +#include "kickerbindings.cpp" + keys->readSettings(); + keys->updateConnections(); + + // set up our global settings + configure(); + + connect(this, SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int))); + connect(this, SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged())); + connect(this, SIGNAL(kdisplayStyleChanged()), SLOT(slotStyleChanged())); + +#if (QT_VERSION-0 >= 0x030200) // XRANDR support + connect(desktop(), SIGNAL(resized(int)), SLOT(slotDesktopResized())); +#endif + + // the panels, aka extensions + QTimer::singleShot(0, ExtensionManager::the(), SLOT(initialize())); + + connect(ExtensionManager::the(), SIGNAL(desktopIconsAreaChanged(const QRect &, int)), + this, SLOT(slotDesktopIconsAreaChanged(const QRect &, int))); +} + +Kicker::~Kicker() +{ + // order of deletion here is critical to avoid crashes + delete ExtensionManager::the(); + delete MenuManager::the(); +} + +void Kicker::setCrashHandler() +{ + KCrash::setEmergencySaveFunction(Kicker::crashHandler); +} + +void Kicker::crashHandler(int /* signal */) +{ + fprintf(stderr, "kicker: crashHandler called\n"); + + DCOPClient::emergencyClose(); + sleep(1); + system("kicker --nocrashhandler &"); // try to restart +} + +void Kicker::slotToggleShowDesktop() +{ + // don't connect directly to the ShowDesktop::toggle() slot + // so that the ShowDesktop object doesn't get created if + // this feature is never used, and isn't created until after + // startup even if it is + ShowDesktop::the()->toggle(); +} + +void Kicker::toggleLock() +{ + KickerSettings::self()->setLocked(!KickerSettings::locked()); + KickerSettings::self()->writeConfig(); + emit immutabilityChanged(isImmutable()); +} + +void Kicker::toggleShowDesktop() +{ + ShowDesktop::the()->toggle(); +} + +bool Kicker::desktopShowing() +{ + return ShowDesktop::the()->desktopShowing(); +} + +void Kicker::slotSettingsChanged(int category) +{ + if (category == (int)KApplication::SETTINGS_SHORTCUTS) + { + keys->readSettings(); + keys->updateConnections(); + } +} + +void Kicker::paletteChanged() +{ + KConfigGroup c(KGlobal::config(), "General"); + KickerSettings::setTintColor(c.readColorEntry("TintColor", + &palette().active().mid())); + KickerSettings::self()->writeConfig(); +} + +void Kicker::slotStyleChanged() +{ + restart(); +} + +bool Kicker::highlightMenuItem(const QString &menuId) +{ + return MenuManager::the()->kmenu()->highlightMenuItem( menuId ); +} + +void Kicker::showKMenu() +{ + MenuManager::the()->showKMenu(); +} + +void Kicker::popupKMenu(const QPoint &p) +{ + MenuManager::the()->popupKMenu(p); +} + +void Kicker::configure() +{ + static bool notFirstConfig = false; + + KConfig* c = KGlobal::config(); + c->reparseConfiguration(); + c->setGroup("General"); + m_canAddContainers = !c->entryIsImmutable("Applets2"); + + KickerSettings::self()->readConfig(); + + QToolTip::setGloballyEnabled(KickerSettings::showToolTips()); + + if (notFirstConfig) + { + emit configurationChanged(); + { + QByteArray data; + emitDCOPSignal("configurationChanged()", data); + } + } + + notFirstConfig = true; +// kdDebug(1210) << "tooltips " << ( _showToolTips ? "enabled" : "disabled" ) << endl; +} + +void Kicker::quit() +{ + exit(1); +} + +void Kicker::restart() +{ + // do this on a timer to give us time to return true + QTimer::singleShot(0, this, SLOT(slotRestart())); +} + +void Kicker::slotRestart() +{ + // since the child will awaken before we do, we need to + // clear the untrusted list manually; can't rely on the + // dtor's to this for us. + PluginManager::the()->clearUntrustedLists(); + + char ** o_argv = new char*[2]; + o_argv[0] = strdup("kicker"); + o_argv[1] = 0L; + execv(QFile::encodeName(locate("exe", "kdeinit_wrapper")), o_argv); + + exit(1); +} + +bool Kicker::isImmutable() const +{ + return config()->isImmutable() || KickerSettings::locked(); +} + +bool Kicker::isKioskImmutable() const +{ + return config()->isImmutable(); +} + +void Kicker::addExtension( const QString &desktopFile ) +{ + ExtensionManager::the()->addExtension( desktopFile ); +} + +QStringList Kicker::configModules(bool controlCenter) +{ + QStringList args; + + if (controlCenter) + { + args << "kde-panel.desktop"; + } + else + { + args << "kde-kicker_config_arrangement.desktop" + << "kde-kicker_config_hiding.desktop" + << "kde-kicker_config_menus.desktop" + << "kde-kicker_config_appearance.desktop"; + } + args << "kde-kcmtaskbar.desktop"; + return args; +} + +QPoint Kicker::insertionPoint() +{ + return m_insertionPoint; +} + +void Kicker::setInsertionPoint(const QPoint &p) +{ + m_insertionPoint = p; +} + + +void Kicker::showConfig(const QString& configPath, int page) +{ + if (!m_configDialog) + { + m_configDialog = new KCMultiDialog(0); + + QStringList modules = configModules(false); + QStringList::ConstIterator end(modules.end()); + for (QStringList::ConstIterator it = modules.begin(); it != end; ++it) + { + m_configDialog->addModule(*it); + } + + connect(m_configDialog, SIGNAL(finished()), SLOT(configDialogFinished())); + } + + if (!configPath.isEmpty()) + { + QByteArray data; + QDataStream stream(data, IO_WriteOnly); + stream << configPath; + emitDCOPSignal("configSwitchToPanel(QString)", data); + } + + KWin::setOnDesktop(m_configDialog->winId(), KWin::currentDesktop()); + m_configDialog->show(); + m_configDialog->raise(); + if (page > -1) + { + m_configDialog->showPage(page); + } +} + +void Kicker::showTaskBarConfig() +{ + showConfig(QString(), 4); +} + +void Kicker::configureMenubar() +{ + ExtensionManager::the()->configureMenubar(false); +} + +void Kicker::configDialogFinished() +{ + m_configDialog->delayedDestruct(); + m_configDialog = 0; +} + +void Kicker::slotDesktopResized() +{ + configure(); // reposition on the desktop +} + +void Kicker::clearQuickStartMenu() +{ + MenuManager::the()->kmenu()->clearRecentMenuItems(); +} + +KWinModule* Kicker::kwinModule() +{ + if (!m_kwinModule) + { + m_kwinModule = new KWinModule(); + } + + return m_kwinModule; +} + +QRect Kicker::desktopIconsArea(int screen) const +{ + return ExtensionManager::the()->desktopIconsArea(screen); +} + +void Kicker::slotDesktopIconsAreaChanged(const QRect &area, int screen) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << area; + stream << screen; + emitDCOPSignal("desktopIconsAreaChanged(QRect, int)", params); +} diff --git a/kicker/kicker/core/kicker.h b/kicker/kicker/core/kicker.h new file mode 100644 index 000000000..9ac1d3eac --- /dev/null +++ b/kicker/kicker/core/kicker.h @@ -0,0 +1,131 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __kicker_h__ +#define __kicker_h__ + +#include <qcolor.h> + +#include <kuniqueapplication.h> +#include <kicontheme.h> + +class KCMultiDialog; +class KDirWatch; +class KGlobalAccel; +class KWinModule; +class PanelKMenu; +class PanelPopupButton; + +class Kicker : public KUniqueApplication +{ + Q_OBJECT + K_DCOP + +public: + Kicker(); + ~Kicker(); + +k_dcop: + void configure(); + void quit(); + void restart(); + void addExtension( const QString &desktopFile ); + void popupKMenu( const QPoint &globalPos ); + void clearQuickStartMenu(); + bool highlightMenuItem( const QString &menuId ); + void showKMenu(); + void toggleShowDesktop(); + bool desktopShowing(); + void showConfig(const QString& config, int page = -1); + void showTaskBarConfig(); + void configureMenubar(); + // return the region on the desktop, which is not covered by panels + // and therefore allowed to be used by icons placed on the desktop + QRect desktopIconsArea(int screen) const; + +k_dcop_signals: + void desktopIconsAreaChanged(QRect area, int screen); + +public: + static Kicker* the(); + KDirWatch* fileWatcher(); + KWinModule* kwinModule(); + + bool isImmutable() const; + bool isKioskImmutable() const; + bool canAddContainers() const { return m_canAddContainers && !isImmutable(); } + + static QStringList configModules(bool controlCenter); + + /** + * Global position where to insert a new item + */ + QPoint insertionPoint(); + + /** + * Set the global position where to insert a new item + * This is not meant to be used by more than one code path + * at a time! A point is set, then later accessed, then cleared + * as an atomic action: + * + * Kicker::the()->setInsertionPoint(p); + * ... + * QPoint where = Kicker::the()->insertionPoint(); + * ... + * Kicker::the()->setInsertionPoint(QPoint()); + * + * this is not pretty, but it's pragmatic and does everything + * that is needed + */ + void setInsertionPoint(const QPoint &p); + + +public slots: + void slotToggleShowDesktop(); + void toggleLock(); + +signals: + void configurationChanged(); + void immutabilityChanged(bool immutable); + +private slots: + void configDialogFinished(); + void slotSettingsChanged( int ); + void slotRestart(); + void slotDesktopResized(); + void slotStyleChanged(); + void paletteChanged(); + void setCrashHandler(); + void slotDesktopIconsAreaChanged(const QRect &area, int screen); + +private: + static void crashHandler(int signal); + + KGlobalAccel* keys; + KWinModule* m_kwinModule; + KCMultiDialog* m_configDialog; + bool m_canAddContainers; + QPoint m_insertionPoint; +}; + +#endif diff --git a/kicker/kicker/core/kickerbindings.cpp b/kicker/kicker/core/kickerbindings.cpp new file mode 100644 index 000000000..2134fb975 --- /dev/null +++ b/kicker/kicker/core/kickerbindings.cpp @@ -0,0 +1,50 @@ +/***************************************************************** + +Copyright (c) 2001-2004 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef NOSLOTS +# define DEF( name, key3, key4, target, fnSlot ) \ + keys->insert( name, i18n(name), QString::null, key3, key4, target, SLOT(fnSlot) ) +#else +# define DEF( name, key3, key4, target, fnSlot ) \ + keys->insert( name, i18n(name), QString::null, key3, key4 ) +#endif +#define WIN KKey::QtWIN + +#ifdef KICKER_ALL_BINDINGS +#define LAUNCH_MENU +#define SHOW_DESKTOP +#endif + +#ifdef LAUNCH_MENU + keys->insert("Program:kicker", i18n("Panel")); + DEF(I18N_NOOP("Popup Launch Menu" ), ALT+Qt::Key_F1, WIN+Qt::Key_Menu, + MenuManager::the(), kmenuAccelActivated()); +#endif + +#ifdef SHOW_DESKTOP + DEF(I18N_NOOP( "Toggle Showing Desktop" ), ALT+CTRL+Qt::Key_D, WIN+CTRL+Qt::Key_D, + this, slotToggleShowDesktop()); +#endif + +#undef DEF +#undef WIN diff --git a/kicker/kicker/core/main.cpp b/kicker/kicker/core/main.cpp new file mode 100644 index 000000000..8eb033e29 --- /dev/null +++ b/kicker/kicker/core/main.cpp @@ -0,0 +1,154 @@ +/***************************************************************** + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <config.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kaboutdata.h> +#include <kglobal.h> +#include <kconfig.h> +#include <dcopclient.h> +#include <dcopref.h> + +#include <X11/Xlib.h> +#include <fixx11h.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> + +#include "kicker.h" + +int kicker_screen_number = 0; + +static const char description[] = + I18N_NOOP("The KDE panel"); + +static const char version[] = VERSION; + +static void sighandler(int) +{ + fprintf(stderr, "kicker: sighandler called\n"); + QApplication::exit(); +} + +extern "C" KDE_EXPORT int kdemain( int argc, char ** argv ) +{ + { + QCString multiHead = getenv("KDE_MULTIHEAD"); + if (multiHead.lower() == "true") { + Display *dpy = XOpenDisplay(NULL); + if (! dpy) { + fprintf(stderr, "%s: FATAL ERROR: couldn't open display %s\n", + argv[0], XDisplayName(NULL)); + exit(1); + } + + int number_of_screens = ScreenCount(dpy); + kicker_screen_number = DefaultScreen(dpy); + int pos; + QCString display_name = XDisplayString(dpy); + XCloseDisplay(dpy); + dpy = 0; + + if ((pos = display_name.findRev('.')) != -1) + display_name.remove(pos, 10); + + QCString env; + if (number_of_screens != 1) { + for (int i = 0; i < number_of_screens; i++) { + if (i != kicker_screen_number && fork() == 0) { + kicker_screen_number = i; + // break here because we are the child process, we don't + // want to fork() anymore + break; + } + } + + env.sprintf("DISPLAY=%s.%d", display_name.data(), kicker_screen_number); + + if (putenv(strdup(env.data()))) { + fprintf(stderr, + "%s: WARNING: unable to set DISPLAY environment variable\n", + argv[0]); + perror("putenv()"); + } + } + } + } + + KGlobal::locale()->setMainCatalogue("kicker"); + + QCString appname; + if (kicker_screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", kicker_screen_number); + + KAboutData aboutData( appname.data(), I18N_NOOP("KDE Panel"), + version, description, KAboutData::License_BSD, + I18N_NOOP("(c) 1999-2004, The KDE Team") ); + + aboutData.addAuthor("Aaron J. Seigo", I18N_NOOP("Current maintainer"), "aseigo@kde.org"); + aboutData.addAuthor("Matthias Elter",0, "elter@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + aboutData.addAuthor("Wilco Greven",0, "greven@kde.org"); + aboutData.addAuthor("Rik Hemsley",0, "rik@kde.org"); + aboutData.addAuthor("Daniel M. Duley",0, "mosfet@kde.org"); + aboutData.addAuthor("Preston Brown",0, "pbrown@kde.org"); + aboutData.addAuthor("John Firebaugh",0, "jfirebaugh@kde.org"); + aboutData.addAuthor("Waldo Bastian", I18N_NOOP("Kiosk mode"), "bastian@kde.org"); + + aboutData.addCredit("Jessica Hall", /* I18N_NOOP("KConfigXT") */ 0, "jes.hall@kdemail.net"); + aboutData.addCredit("Stefan Nikolaus", /* I18N_NOOP("Bug fixes") */ 0, "stefan.nikolaus@kdemail.net"); + aboutData.addCredit("Benoît Minisini", /* I18N_NOOP("Bug fixes") */ 0, "gambas@users.sourceforge.net"); + KCmdLineArgs::init( argc, argv, &aboutData ); + + if (!Kicker::start()) { + kdError() << "kicker is already running!" << endl; + return 0; + } + + if (signal(SIGTERM, sighandler) == SIG_IGN) + signal(SIGTERM, SIG_IGN); + if (signal(SIGINT, sighandler) == SIG_IGN) + signal(SIGINT, SIG_IGN); + if (signal(SIGHUP, sighandler) == SIG_IGN) + signal(SIGHUP, SIG_IGN); + + // send it even before KApplication ctor, because ksmserver will launch another app as soon + // as QApplication registers with it + DCOPClient* cl = new DCOPClient; + cl->attach(); + DCOPRef r( "ksmserver", "ksmserver" ); + r.setDCOPClient( cl ); + r.send( "suspendStartup", QCString( "kicker" )); + delete cl; + Kicker* kicker = new Kicker; + int rv = kicker->exec(); + delete kicker; + return rv; +} + diff --git a/kicker/kicker/core/menumanager.cpp b/kicker/kicker/core/menumanager.cpp new file mode 100644 index 000000000..ba07b39c7 --- /dev/null +++ b/kicker/kicker/core/menumanager.cpp @@ -0,0 +1,272 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qpixmap.h> +#include <qtimer.h> + +#include <kapplication.h> +#include <dcopclient.h> + +#include "client_mnu.h" +#include "container_extension.h" +#include "global.h" +#include "k_mnu.h" +#include "kicker.h" +#include "panelbutton.h" + +#include "menumanager.h" +#include "menumanager.moc" + +// Why MenuManager doesn't use KStaticDeleter +// MenuManager gets created before the ExtensionManager +// So using KStaticDeleter results in MenuManager getting +// deleted before ExtensionManager, which means also the panels +// which means also the K Menu buttons. K Menu buttons call +// MenuManager in their dtor, so if MenuManager is already gone +// then every KButton will cause it to be reconstructed. +// So we rely on Kicker to delete MenuManager on the way out +// ensuring it's the last thing to go. +MenuManager* MenuManager::m_self = 0; + +MenuManager* MenuManager::the() +{ + if (!m_self) + { + m_self = new MenuManager(); + } + + return m_self; +} + +MenuManager::MenuManager(QObject *parent) + : QObject(parent, "MenuManager"), DCOPObject("MenuManager") +{ + m_kmenu = new PanelKMenu; + kapp->dcopClient()->setNotifications(true); + connect(kapp->dcopClient(), SIGNAL(applicationRemoved(const QCString&)), + this, SLOT(applicationRemoved(const QCString&))); +} + +MenuManager::~MenuManager() +{ + if (this == m_self) + { + m_self = 0; + } + + delete m_kmenu; +} + +void MenuManager::slotSetKMenuItemActive() +{ + m_kmenu->selectFirstItem(); +} + +void MenuManager::showKMenu() +{ + m_kmenu->showMenu(); +} + +void MenuManager::popupKMenu(const QPoint &p) +{ +// kdDebug(1210) << "popupKMenu()" << endl; + if (m_kmenu->isVisible()) + { + m_kmenu->hide(); + } + else if (p.isNull()) + { + m_kmenu->popup(QCursor::pos()); + } + else + { + m_kmenu->popup( p ); + } +} + +void MenuManager::registerKButton(PanelPopupButton *button) +{ + if (!button) + { + return; + } + + m_kbuttons.append(button); +} + +void MenuManager::unregisterKButton(PanelPopupButton *button) +{ + m_kbuttons.remove(button); +} + +PanelPopupButton* MenuManager::findKButtonFor(QPopupMenu* menu) +{ + KButtonList::const_iterator itEnd = m_kbuttons.constEnd(); + for (KButtonList::const_iterator it = m_kbuttons.constBegin(); it != itEnd; ++it) + { + if ((*it)->popup() == menu) + { + return *it; + } + } + + return 0; +} + +void MenuManager::kmenuAccelActivated() +{ + if (m_kmenu->isVisible()) + { + m_kmenu->hide(); + return; + } + + m_kmenu->initialize(); + + if (m_kbuttons.isEmpty()) + { + // no button to use, make it behave like a desktop menu + QPoint p; + // Popup the K-menu at the center of the screen. + QDesktopWidget* desktop = KApplication::desktop(); + QRect r = desktop->screenGeometry(desktop->screenNumber(QCursor::pos())); + // kMenu->rect() is not valid before showing, use sizeHint() + p = r.center() - QRect( QPoint( 0, 0 ), m_kmenu->sizeHint()).center(); + m_kmenu->popup(p); + + // when the cursor is in the area where the menu pops up, + // the item under the cursor gets selected. The single shot + // avoids this from happening by allowing the item to be selected + // when the event loop is enterred, and then resetting it. + QTimer::singleShot(0, this, SLOT(slotSetKMenuItemActive())); + } + else + { + // We need the kmenu's size to place it at the right position. + // We cannot rely on the popup menu's current size(), if it wasn't + // shown before, so we resize it here according to its sizeHint(). + const QSize size = m_kmenu->sizeHint(); + m_kmenu->resize(size.width(),size.height()); + + PanelPopupButton* button = findKButtonFor(m_kmenu); + + // let's unhide the panel while we're at it. traverse the widget + // hierarchy until we find the panel, if any + QObject* menuParent = button->parent(); + while (menuParent) + { + ExtensionContainer* ext = dynamic_cast<ExtensionContainer*>(menuParent); + + if (ext) + { + ext->unhideIfHidden(); + // make sure it's unhidden before we use it to figure out + // where to popup + qApp->processEvents(); + break; + } + + menuParent = menuParent->parent(); + } + + button->showMenu(); + } +} + +QCString MenuManager::createMenu(QPixmap icon, QString text) +{ + static int menucount = 0; + menucount++; + QCString name; + name.sprintf("kickerclientmenu-%d", menucount ); + KickerClientMenu* p = new KickerClientMenu( 0, name ); + clientmenus.append(p); + m_kmenu->initialize(); + p->text = text; + p->icon = icon; + p->idInParentMenu = m_kmenu->insertClientMenu( p ); + p->createdBy = kapp->dcopClient()->senderId(); + m_kmenu->adjustSize(); + return name; +} + +void MenuManager::removeMenu(QCString menu) +{ + bool iterate = true; + ClientMenuList::iterator it = clientmenus.begin(); + for (; it != clientmenus.end(); iterate ? ++it : it) + { + iterate = true; + KickerClientMenu* m = *it; + if (m->objId() == menu) + { + m_kmenu->removeClientMenu(m->idInParentMenu); + it = clientmenus.erase(it); + iterate = false; + } + } + m_kmenu->adjustSize(); +} + + +void MenuManager::applicationRemoved(const QCString& appRemoved) +{ + bool iterate = true; + ClientMenuList::iterator it = clientmenus.begin(); + for (; it != clientmenus.end(); iterate ? ++it : it) + { + iterate = true; + KickerClientMenu* m = *it; + if (m->createdBy == appRemoved) + { + m_kmenu->removeClientMenu(m->idInParentMenu); + it = clientmenus.erase(it); + iterate = false; + } + } + m_kmenu->adjustSize(); +} + +bool MenuManager::process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &replyData) +{ + if ( fun == "createMenu(QPixmap,QString)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QPixmap icon; + QString text; + dataStream >> icon >> text; + QDataStream reply( replyData, IO_WriteOnly ); + reply << createMenu( icon, text ); + replyType = "QCString"; + return true; + } else if ( fun == "removeMenu(QCString)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QCString menu; + dataStream >> menu; + removeMenu( menu ); + replyType = "void"; + return true; + } + return false; +} diff --git a/kicker/kicker/core/menumanager.h b/kicker/kicker/core/menumanager.h new file mode 100644 index 000000000..ed0e5d225 --- /dev/null +++ b/kicker/kicker/core/menumanager.h @@ -0,0 +1,81 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef KICKER_MENU_MANAGER_H +#define KICKER_MENU_MANAGER_H + +#include <dcopobject.h> +#include <qvaluelist.h> + +class PanelKMenu; +class KickerClientMenu; +class PanelPopupButton; + +typedef QValueList<PanelPopupButton*> KButtonList; + +/** + * The factory for menus created by other applications. Also the owner of these menus. + */ +class MenuManager : public QObject, DCOPObject +{ + Q_OBJECT +public: + static MenuManager* the(); + + // dcop exported + QCString createMenu(QPixmap icon, QString text); + void removeMenu(QCString menu); + + // dcop internal + bool process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &reply); + + // KMenu controls + PanelKMenu* kmenu() { return m_kmenu; } + void showKMenu(); + void popupKMenu(const QPoint &p); + + void registerKButton(PanelPopupButton *button); + void unregisterKButton(PanelPopupButton *button); + PanelPopupButton* findKButtonFor(QPopupMenu* menu); + ~MenuManager(); + +public slots: + void slotSetKMenuItemActive(); + void kmenuAccelActivated(); + +protected slots: + void applicationRemoved(const QCString&); + +protected: + PanelKMenu* m_kmenu; + typedef QValueList<KickerClientMenu*> ClientMenuList; + ClientMenuList clientmenus; + +private: + MenuManager(QObject *parent = 0); + + static MenuManager* m_self; + KButtonList m_kbuttons; +}; + +#endif diff --git a/kicker/kicker/core/panelextension.cpp b/kicker/kicker/core/panelextension.cpp new file mode 100644 index 000000000..cf5067c17 --- /dev/null +++ b/kicker/kicker/core/panelextension.cpp @@ -0,0 +1,445 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + 2004 Aaron J. Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qframe.h> +#include <qvalidator.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qstyle.h> + +#include <kdebug.h> +#include <khelpmenu.h> +#include <klocale.h> +#include <kglobal.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kstdguiitem.h> + +#include "container_applet.h" +#include "container_extension.h" +#include "containerarea.h" +#include "extensionmanager.h" +#include "kicker.h" +#include "removecontainer_mnu.h" +#include "removeextension_mnu.h" + +#include "addapplet_mnu.h" +#include "addbutton_mnu.h" +#include "addextension_mnu.h" + +#include "panelextension.h" +#include "panelextension.moc" + +// KDE4: make these say Panel_(somenumber) +PanelExtension::PanelExtension(const QString& configFile, QWidget *parent, const char *name) + : DCOPObject(QCString("ChildPanel_") + QString::number((ulong)this).latin1()), + KPanelExtension(configFile, KPanelExtension::Stretch, 0, parent, name), + _opMnu(0), + m_panelAddMenu(0), + m_removeMnu(0), + m_addExtensionMenu(0), + m_removeExtensionMenu(0), + _configFile(configFile), + m_opMenuBuilt( false ) +{ + setAcceptDrops(!Kicker::the()->isImmutable()); + setCustomMenu(opMenu()); + + QVBoxLayout* _layout = new QVBoxLayout(this); + + // container area + _containerArea = new ContainerArea( config(), this, opMenu() ); + connect(_containerArea, SIGNAL(maintainFocus(bool)), this, SIGNAL(maintainFocus(bool))); + _layout->addWidget(_containerArea); + + _containerArea->viewport()->installEventFilter(this); + _containerArea->configure(); + + // Make sure the containerarea has the right orientation from the + // beginning. + positionChange(position()); + + connect(Kicker::the(), SIGNAL(configurationChanged()), + SLOT(configurationChanged())); + connect(Kicker::the(), SIGNAL(immutabilityChanged(bool)), + SLOT(immutabilityChanged(bool))); + + // we wait to get back to the event loop to start up the container area so that + // the main panel in ExtensionManager will be assigned and we can tell in a + // relatively non-hackish way that we are (or aren't) the "main panel" + QTimer::singleShot(0, this, SLOT(populateContainerArea())); +} + +PanelExtension::~PanelExtension() +{ +} + +void PanelExtension::populateContainerArea() +{ + _containerArea->show(); + + if (ExtensionManager::the()->isMainPanel(topLevelWidget())) + { + setObjId("Panel"); + _containerArea->initialize(true); + } + else + { + _containerArea->initialize(false); + } +} + +void PanelExtension::configurationChanged() +{ + _containerArea->configure(); +} + +void PanelExtension::immutabilityChanged(bool) +{ + m_opMenuBuilt = false; +} + +QPopupMenu* PanelExtension::opMenu() +{ + if (_opMnu) + { + return _opMnu; + } + + _opMnu = new QPopupMenu(this); + connect(_opMnu, SIGNAL(aboutToShow()), this, SLOT(slotBuildOpMenu())); + + return _opMnu; +} + +void PanelExtension::positionChange(Position p) +{ + _containerArea->setPosition(p); +} + +QSize PanelExtension::sizeHint(Position p, QSize maxSize) const +{ + QSize size; + + if (p == Left || p == Right) + { + size = QSize(sizeInPixels(), + _containerArea->heightForWidth(sizeInPixels())); + } + else + { + size = QSize(_containerArea->widthForHeight(sizeInPixels()), + sizeInPixels()); + } + + return size.boundedTo( maxSize ); +} + +bool PanelExtension::eventFilter(QObject*, QEvent * e) +{ + if ( e->type() == QEvent::MouseButtonPress ) + { + QMouseEvent* me = (QMouseEvent*) e; + if ( me->button() == RightButton && kapp->authorize("action/kicker_rmb")) + { + Kicker::the()->setInsertionPoint(me->globalPos()); + opMenu()->exec(me->globalPos()); + Kicker::the()->setInsertionPoint(QPoint()); + return true; + } + } + else + if ( e->type() == QEvent::Resize ) + { + emit updateLayout(); + } + + return false; +} + +void PanelExtension::setPanelSize(int size) +{ + int custom = customSize(); + if (size > KPanelExtension::SizeCustom) + { + custom = size; + size = KPanelExtension::SizeCustom; + } + + setSize(static_cast<Size>(size), custom); + + // save the size setting here if it isn't a custom setting + config()->setGroup("General"); + config()->writeEntry("Size", size); + config()->sync(); +} + +void PanelExtension::addKMenuButton() +{ + _containerArea->addKMenuButton(); +} + +void PanelExtension::addDesktopButton() +{ + _containerArea->addDesktopButton(); +} + +void PanelExtension::addWindowListButton() +{ + _containerArea->addWindowListButton(); +} + +void PanelExtension::addURLButton(const QString &url) +{ + _containerArea->addURLButton(url); +} + +void PanelExtension::addBrowserButton(const QString &startDir) +{ + _containerArea->addBrowserButton(startDir); +} + +void PanelExtension::addServiceButton(const QString& desktopEntry) +{ + _containerArea->addServiceButton(desktopEntry); +} + +void PanelExtension::addServiceMenuButton(const QString &, + const QString& relPath) +{ + _containerArea->addServiceMenuButton(relPath); +} + +void PanelExtension::addNonKDEAppButton(const QString &filePath, + const QString &icon, + const QString &cmdLine, bool inTerm) +{ + _containerArea->addNonKDEAppButton(filePath, QString::null, filePath, icon, + cmdLine, inTerm); +} + +void PanelExtension::addNonKDEAppButton(const QString &title, + const QString &description, + const QString &filePath, + const QString &icon, + const QString &cmdLine, bool inTerm) +{ + _containerArea->addNonKDEAppButton(title, description, filePath, icon, + cmdLine, inTerm); +} + +void PanelExtension::addApplet(const QString &desktopFile) +{ + _containerArea->addApplet(AppletInfo(desktopFile, QString::null, AppletInfo::Applet)); +} + +void PanelExtension::addAppletContainer(const QString &desktopFile) +{ + // KDE4: this appears in the DCOP interface. + // but it's such a bad name, can this go away? + addApplet(desktopFile); +} + +bool PanelExtension::insertApplet(const QString& desktopFile, int index) +{ + return _containerArea->addApplet(desktopFile, false, index) != 0; +} + +bool PanelExtension::insertImmutableApplet(const QString& desktopFile, int index) +{ + return _containerArea->addApplet(desktopFile, true, index) != 0; +} + +QStringList PanelExtension::listApplets() +{ + return _containerArea->listContainers(); + BaseContainer::List containers = _containerArea->containers("All"); + QStringList names; + + for (BaseContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + names.append((*it)->visibleName()); + } + + return names; +} + +bool PanelExtension::removeApplet(int index) +{ + return _containerArea->removeContainer(index); +} + +void PanelExtension::restart() +{ + Kicker::the()->restart(); +} + +void PanelExtension::configure() +{ + Kicker::the()->configure(); +} + +void PanelExtension::slotBuildOpMenu() +{ + const int REMOVE_EXTENSION_ID = 1000; + if (m_opMenuBuilt || !_opMnu) + { + if (_opMnu) + { + bool haveExtensions = ExtensionManager::the()->containers().count() > 0; + _opMnu->setItemEnabled(REMOVE_EXTENSION_ID, haveExtensions); + } + + return; + } + + _opMnu->clear(); + + delete m_panelAddMenu; + m_panelAddMenu = 0; + delete m_removeMnu; + m_removeMnu = 0; + delete m_addExtensionMenu; + m_addExtensionMenu = 0; + delete m_removeExtensionMenu; + m_removeExtensionMenu = 0; + + m_opMenuBuilt = true; + bool kickerImmutable = Kicker::the()->isImmutable(); + bool isMenuBar = ExtensionManager::the()->isMenuBar(dynamic_cast<QWidget*>(parent())); + + if (!kickerImmutable) + { + // setup addmenu and removemenu + if (_containerArea->canAddContainers()) + { + _opMnu->insertItem(isMenuBar ? i18n("Add &Applet to Menubar...") + : i18n("Add &Applet to Panel..."), + _containerArea, SLOT(showAddAppletDialog())); + m_panelAddMenu = new PanelAddButtonMenu(_containerArea, this); + _opMnu->insertItem(isMenuBar ? i18n("Add Appli&cation to Menubar") + : i18n("Add Appli&cation to Panel"), + m_panelAddMenu); + + m_removeMnu = new RemoveContainerMenu(_containerArea, this); + _opMnu->insertItem(isMenuBar ? i18n("&Remove From Menubar") + : i18n("&Remove From Panel"), + m_removeMnu); + _opMnu->insertSeparator(); + + m_addExtensionMenu = new PanelAddExtensionMenu(this); + _opMnu->insertItem(i18n("Add New &Panel"), m_addExtensionMenu); + m_removeExtensionMenu = new PanelRemoveExtensionMenu(this); + _opMnu->insertItem(i18n("Remove Pa&nel"), m_removeExtensionMenu, + REMOVE_EXTENSION_ID); + _opMnu->setItemEnabled(REMOVE_EXTENSION_ID, + ExtensionManager::the()->containers().count() > 0); + _opMnu->insertSeparator(); + } + + _opMnu->insertItem(SmallIconSet("lock"), i18n("&Lock Panels"), + Kicker::the(), SLOT(toggleLock())); + } + else if (!Kicker::the()->isKioskImmutable()) + { + _opMnu->insertItem(kickerImmutable? SmallIconSet("unlock") : + SmallIconSet("lock"), + kickerImmutable ? i18n("Un&lock Panels") : + i18n("&Lock Panels"), + Kicker::the(), SLOT(toggleLock())); + } + + if (!isMenuBar && !Kicker::the()->isKioskImmutable()) + { + _opMnu->insertItem(SmallIconSet("configure"), + i18n("&Configure Panel..."), + this, SLOT(showConfig())); + _opMnu->insertSeparator(); + } + + if (kapp->authorize("action/help")) + { + KHelpMenu* help = new KHelpMenu( this, KGlobal::instance()->aboutData(), false); + _opMnu->insertItem(SmallIconSet("help"), KStdGuiItem::help().text(), help->menu()); + } + _opMnu->adjustSize(); +} + +void PanelExtension::showConfig() +{ + Kicker::the()->showConfig(_configFile); +} + +MenubarExtension::MenubarExtension(const AppletInfo& info) + : PanelExtension(info.configFile()), + m_menubar(0) +{ +} + +MenubarExtension::~MenubarExtension() +{ + if (m_menubar) + { + m_menubar->setImmutable(false); + _containerArea->slotSaveContainerConfig(); + } +} + +void MenubarExtension::populateContainerArea() +{ + PanelExtension::populateContainerArea(); + BaseContainer::List containers = _containerArea->containers("All"); + for (BaseContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + if ((*it)->appletType() == "Applet") + { + AppletContainer* applet = dynamic_cast<AppletContainer*>(*it); + if (applet && applet->info().desktopFile() == "menuapplet.desktop") + { + m_menubar = applet; + break; + } + } + } + + if (!m_menubar) + { + m_menubar = _containerArea->addApplet(AppletInfo("menuapplet.desktop", + QString::null, + AppletInfo::Applet)); + } + + // in the pathological case we may not have a menuapplet at all, + // so check for it =/ + if (m_menubar) + { + m_menubar->setImmutable(true); + } +} + diff --git a/kicker/kicker/core/panelextension.h b/kicker/kicker/core/panelextension.h new file mode 100644 index 000000000..d1d7deb28 --- /dev/null +++ b/kicker/kicker/core/panelextension.h @@ -0,0 +1,126 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter + 2004 Aaron J. Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _panelextension_h_ +#define _panelextension_h_ + +#include <kpanelextension.h> +#include <dcopobject.h> + +#include "appletinfo.h" + +class AppletContainer; +class ContainerArea; +class QPopupMenu; +class QGridLayout; + +// This is the KPanelExtension responsible for the main kicker panel +// Prior to KDE 3.4 it was the ChildPanelExtension + +class PanelExtension : public KPanelExtension, virtual public DCOPObject +{ + Q_OBJECT + K_DCOP + +public: + PanelExtension(const QString& configFile, QWidget *parent = 0, const char *name = 0); + virtual ~PanelExtension(); + + QPopupMenu* opMenu(); + +k_dcop: + int panelSize() { return sizeInPixels(); } + int panelOrientation() { return static_cast<int>(orientation()); } + int panelPosition() { return static_cast<int>(position()); } + + void setPanelSize(int size); + void addKMenuButton(); + void addDesktopButton(); + void addWindowListButton(); + void addURLButton(const QString &url); + void addBrowserButton(const QString &startDir); + void addServiceButton(const QString &desktopEntry); + void addServiceMenuButton(const QString &name, const QString& relPath); + void addNonKDEAppButton(const QString &filePath, const QString &icon, + const QString &cmdLine, bool inTerm); + void addNonKDEAppButton(const QString &title, const QString &description, + const QString &filePath, const QString &icon, + const QString &cmdLine, bool inTerm); + + void addApplet(const QString &desktopFile); + void addAppletContainer(const QString &desktopFile); // KDE4: remove, useless + + bool insertApplet(const QString& desktopFile, int index); + bool insertImmutableApplet(const QString& desktopFile, int index); + QStringList listApplets(); + bool removeApplet(int index); + + void restart(); // KDE4: remove, moved to Kicker + void configure(); // KDE4: remove, moved to Kikcker + +public: + QSize sizeHint(Position, QSize maxSize) const; + Position preferedPosition() const { return Bottom; } + bool eventFilter( QObject *, QEvent * ); + +protected: + void positionChange(Position); + + ContainerArea *_containerArea; + +protected slots: + void configurationChanged(); + void immutabilityChanged(bool); + void slotBuildOpMenu(); + void showConfig(); + virtual void populateContainerArea(); + +private: + QPopupMenu* _opMnu; + QPopupMenu* m_panelAddMenu; + QPopupMenu* m_removeMnu; + QPopupMenu* m_addExtensionMenu; + QPopupMenu* m_removeExtensionMenu; + QString _configFile; + bool m_opMenuBuilt; +}; + +class MenubarExtension : public PanelExtension +{ + Q_OBJECT + + public: + MenubarExtension(const AppletInfo& info); + virtual ~MenubarExtension(); + + protected slots: + virtual void populateContainerArea(); + + private: + MenubarExtension(); + + AppletContainer* m_menubar; +}; + +#endif diff --git a/kicker/kicker/core/pluginmanager.cpp b/kicker/kicker/core/pluginmanager.cpp new file mode 100644 index 000000000..e392959ad --- /dev/null +++ b/kicker/kicker/core/pluginmanager.cpp @@ -0,0 +1,378 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qfile.h> +#include <qtimer.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klibloader.h> +#include <kpanelapplet.h> +#include <kpanelextension.h> +#include <kstandarddirs.h> +#include <kstaticdeleter.h> + +#include "appletinfo.h" +#include "container_applet.h" +#include "container_extension.h" +#include "panelextension.h" +#include "pluginmanager.h" + +static KStaticDeleter<PluginManager> pluginManagerDeleter; +PluginManager* PluginManager::m_self = 0; + +PluginManager* PluginManager::the() +{ + if (!m_self) + { + pluginManagerDeleter.setObject(m_self, new PluginManager()); + } + + return m_self; +} + +AppletInfo::List PluginManager::applets(bool sort, AppletInfo::List* list) +{ + QStringList rel; + KGlobal::dirs()->findAllResources("applets", "*.desktop", false, true, rel); + return plugins(rel, AppletInfo::Applet, sort, list); +} + +AppletInfo::List PluginManager::extensions(bool sort, AppletInfo::List* list) +{ + QStringList rel; + KGlobal::dirs()->findAllResources("extensions", "*.desktop", false, true, rel); + return plugins(rel, AppletInfo::Extension, sort, list); +} + +AppletInfo::List PluginManager::builtinButtons(bool sort, AppletInfo::List* list) +{ + QStringList rel; + KGlobal::dirs()->findAllResources("builtinbuttons", "*.desktop", false, true, rel); + return plugins(rel, AppletInfo::BuiltinButton, sort, list); +} + +AppletInfo::List PluginManager::specialButtons(bool sort, AppletInfo::List* list) +{ + QStringList rel; + KGlobal::dirs()->findAllResources("specialbuttons", "*.desktop", false, true, rel); + return plugins(rel, AppletInfo::SpecialButton, sort, list); +} + +AppletInfo::List PluginManager::plugins(const QStringList& desktopFiles, + AppletInfo::AppletType type, + bool sort, + AppletInfo::List* list) +{ + AppletInfo::List plugins; + + if (list) + { + plugins = *list; + } + + for (QStringList::ConstIterator it = desktopFiles.constBegin(); + it != desktopFiles.constEnd(); ++it) + { + AppletInfo info(*it, QString::null, type); + + if (!info.isHidden()) + { + plugins.append(info); + } + } + + if (sort) + { + qHeapSort(plugins.begin(), plugins.end()); + } + + return plugins; +} + +PluginManager::PluginManager() +{ + KConfigGroup generalGroup(KGlobal::config(), "General"); + m_untrustedApplets = generalGroup.readListEntry("UntrustedApplets"); + m_untrustedExtensions = generalGroup.readListEntry("UntrustedExtensions"); +} + +PluginManager::~PluginManager() +{ + AppletInfo::Dict::const_iterator it = _dict.constBegin(); + for (; it != _dict.constEnd(); ++it) + { + disconnect(it.key(), SIGNAL(destroyed( QObject*)), + this, SLOT(slotPluginDestroyed(QObject*))); + delete it.data(); + } + + // clear the untrusted lists + clearUntrustedLists(); +} + +KPanelApplet* PluginManager::loadApplet(const AppletInfo& info, + QWidget* parent ) +{ + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->library( QFile::encodeName(info.library()) ); + + if (!lib) + { + kdWarning() << "cannot open applet: " << info.library() + << " because of " << loader->lastErrorMessage() << endl; + return 0; + } + + KPanelApplet* (*init_ptr)(QWidget *, const QString&); + init_ptr = (KPanelApplet* (*)(QWidget *, const QString&))lib->symbol( "init" ); + + if (!init_ptr) + { + kdWarning() << info.library() << " is not a kicker extension!" << endl; + loader->unloadLibrary( QFile::encodeName(info.library()) ); + return 0; + } + + KPanelApplet* applet = init_ptr( parent, info.configFile() ); + + if (applet) + { + _dict.insert( applet, new AppletInfo( info ) ); + connect( applet, SIGNAL( destroyed( QObject* ) ), + SLOT( slotPluginDestroyed( QObject* ) ) ); + } + + return applet; +} + +KPanelExtension* PluginManager::loadExtension( + const AppletInfo& info, QWidget* parent ) +{ + if (info.library() == "childpanel_panelextension" + /* KDE4? || info.library() == "panel" */) + { + return new PanelExtension(info.configFile(), parent, "panelextension"); + } + + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->library( QFile::encodeName(info.library()) ); + + if( !lib ) { + kdWarning() << "cannot open extension: " << info.library() + << " because of " << loader->lastErrorMessage() << endl; + return 0; + } + + KPanelExtension* (*init_ptr)(QWidget *, const QString&); + init_ptr = (KPanelExtension* (*)(QWidget *, const QString&))lib->symbol( "init" ); + + if(!init_ptr){ + kdWarning() << info.library() << " is not a kicker extension!" << endl; + loader->unloadLibrary( QFile::encodeName(info.library()) ); + return 0; + } + + KPanelExtension* extension = init_ptr( parent, info.configFile() ); + + if( extension ) { + _dict.insert( extension, new AppletInfo( info ) ); + connect( extension, SIGNAL( destroyed( QObject* ) ), + SLOT( slotPluginDestroyed( QObject* ) ) ); + } + + return extension; +} + +bool PluginManager::hasInstance( const AppletInfo& info ) const +{ + AppletInfo::Dict::const_iterator it = _dict.constBegin(); + for (; it != _dict.constEnd(); ++it) + { + if (it.data()->library() == info.library()) + { + return true; + } + } + + return false; +} + +void PluginManager::slotPluginDestroyed(QObject* object) +{ + AppletInfo* info = 0; + AppletInfo::Dict::iterator it = _dict.begin(); + for (; it != _dict.end(); ++it) + { + if (it.key() == object) + { + info = dynamic_cast<AppletInfo*>(it.data()); + _dict.erase(it); + break; + } + } + + if (!info) + { + return; + } + + LibUnloader::unload(info->library()); + delete info; +} + +AppletContainer* PluginManager::createAppletContainer( + const QString& desktopFile, + bool isStartup, + const QString& configFile, + QPopupMenu* opMenu, + QWidget* parent, + bool isImmutable) +{ + QString desktopPath = KGlobal::dirs()->findResource( "applets", desktopFile ); + + // KDE4: remove + // support the old (KDE 2.2) nameing scheme + if (desktopPath.isEmpty()) + { + desktopPath = KGlobal::dirs()->findResource( "applets", + desktopFile.right( + desktopFile.length() - 1 ) ); + } + + if (desktopPath.isEmpty()) + return 0; + + AppletInfo info( desktopPath, configFile, AppletInfo::Applet ); + + bool instanceFound = hasInstance(info); + if (info.isUniqueApplet() && instanceFound) + { + return 0; + } + + bool untrusted = m_untrustedApplets.find(desktopFile) != m_untrustedApplets.end(); + if (isStartup && untrusted) + { + // don't load extensions that bombed on us previously! + return 0; + } + else if (!isStartup && !instanceFound && !untrusted) + { + // we haven't loaded this puppy before and we're not in the untrusted list + m_untrustedApplets.append(desktopFile); + KConfigGroup generalGroup(KGlobal::config(), "General"); + generalGroup.writeEntry("UntrustedApplets", m_untrustedApplets); + generalGroup.sync(); + } + + AppletContainer* container = new AppletContainer(info, opMenu, isImmutable, parent); + + if (!container->isValid()) + { + delete container; + return 0; + } + + return container; +} + +ExtensionContainer* PluginManager::createExtensionContainer(const QString& desktopFile, + bool isStartup, + const QString& configFile, + const QString& extensionId) +{ + if (desktopFile.isEmpty()) + { + return 0; + } + + QString desktopPath = KGlobal::dirs()->findResource("extensions", desktopFile); + if (desktopPath.isEmpty()) + { + return 0; + } + + AppletInfo info( desktopPath, configFile, AppletInfo::Extension ); + + bool internal = (info.library() == "childpanel_panelextension"); + bool instance = !internal && hasInstance(info); + if (instance && info.isUniqueApplet()) + { + return 0; + } + + if (!internal) + { + bool untrusted = m_untrustedExtensions.find(desktopFile) != m_untrustedExtensions.end(); + if (isStartup && untrusted) + { + // don't load extensions that bombed on us previously! + return 0; + } + else if (!isStartup && !instance && !untrusted) + { + // we don't have an instance around and we're not in the untrusted list! + m_untrustedExtensions.append(desktopFile); + KConfigGroup generalGroup(KGlobal::config(), "General"); + generalGroup.writeEntry("UntrustedExtensions", m_untrustedExtensions); + generalGroup.sync(); + } + } + + return new ExtensionContainer(info, extensionId); +} + +void PluginManager::clearUntrustedLists() +{ + m_untrustedExtensions.clear(); + m_untrustedApplets.clear(); + + KConfigGroup generalGroup(KGlobal::config(), "General"); + generalGroup.writeEntry("UntrustedApplets", m_untrustedApplets); + generalGroup.writeEntry("UntrustedExtensions", m_untrustedExtensions); + generalGroup.sync(); +} + +LibUnloader::LibUnloader( const QString &libName, QObject *parent ) + : QObject( parent ), _libName( libName ) +{ + // NOTE: this doesn't work on kicker shutdown because the timer never gets + // fired. + QTimer::singleShot( 0, this, SLOT( unload() ) ); +} + +void LibUnloader::unload( const QString &libName ) +{ + (void)new LibUnloader( libName, kapp ); +} + +void LibUnloader::unload() +{ + KLibLoader::self()->unloadLibrary( QFile::encodeName( _libName ) ); + deleteLater(); +} + +#include "pluginmanager.moc" + diff --git a/kicker/kicker/core/pluginmanager.h b/kicker/kicker/core/pluginmanager.h new file mode 100644 index 000000000..bbea87b30 --- /dev/null +++ b/kicker/kicker/core/pluginmanager.h @@ -0,0 +1,106 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __PLUGIN_MANAGER_H__ +#define __PLUGIN_MANAGER_H__ + +#include <qmap.h> +#include <qobject.h> +#include <qstringlist.h> +#include <kdemacros.h> +#include <kstaticdeleter.h> + +#include "appletinfo.h" + +class AppletContainer; +class ExtensionContainer; +class KPanelApplet; +class KPanelExtension; +class QPopupMenu; + +class KDE_EXPORT PluginManager : public QObject +{ + Q_OBJECT + +public: + static PluginManager* the(); + static AppletInfo::List applets(bool sort = true, AppletInfo::List* list = 0); + static AppletInfo::List extensions(bool sort = true, AppletInfo::List* list = 0); + static AppletInfo::List builtinButtons(bool sort = true, AppletInfo::List* list = 0); + static AppletInfo::List specialButtons(bool sort = true, AppletInfo::List* list = 0); + + AppletContainer* createAppletContainer(const QString& desktopFile, + bool isStartup, + const QString& configFile, + QPopupMenu* opMenu, + QWidget* parent, + bool isImmutable = false); + ExtensionContainer* createExtensionContainer(const QString& desktopFile, + bool isStartup, + const QString& configFile, + const QString& extensionId); + + KPanelApplet* loadApplet(const AppletInfo& info, QWidget* parent); + KPanelExtension* loadExtension(const AppletInfo& info, QWidget* parent); + + bool hasInstance(const AppletInfo&) const; + +public slots: + void clearUntrustedLists(); + +protected: + static AppletInfo::List plugins(const QStringList& desktopFiles, + AppletInfo::AppletType, + bool sort, + AppletInfo::List* list); + +private slots: + void slotPluginDestroyed(QObject* plugin); + +private: + friend class KStaticDeleter<PluginManager>; + PluginManager(); + virtual ~PluginManager(); + + AppletInfo::Dict _dict; + static PluginManager* m_self; + QStringList m_untrustedApplets; + QStringList m_untrustedExtensions; +}; + +class LibUnloader : public QObject +{ + Q_OBJECT +public: + static void unload( const QString &libName ); + +private slots: + void unload(); + +private: + LibUnloader( const QString &libName, QObject *parent ); + + QString _libName; +}; + +#endif diff --git a/kicker/kicker/core/showdesktop.cpp b/kicker/kicker/core/showdesktop.cpp new file mode 100644 index 000000000..5575b3b28 --- /dev/null +++ b/kicker/kicker/core/showdesktop.cpp @@ -0,0 +1,198 @@ +/***************************************************************** + +Copyright (c) 1996-2001,2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +// kicker.h needs to be up here due to compilation errors that result +// it's placed further on. >=( +#include "kicker.h" +#include "kickerSettings.h" + +#include <kwin.h> +#include <kwinmodule.h> +#include <netwm.h> + +#include "showdesktop.h" +#include "showdesktop.moc" + +ShowDesktop* ShowDesktop::the() +{ + static ShowDesktop showDesktop; + return &showDesktop; +} + +ShowDesktop::ShowDesktop() + : QObject(), + m_showingDesktop(false) +{ + // This feature is implemented in KWin. Keep old code in Kicker for the case + // KDE is running with another WM without the feature. + NETRootInfo i( qt_xdisplay(), NET::Supported ); + m_wmSupport = i.isSupported( NET::WM2ShowingDesktop ); + if( m_wmSupport ) + { + connect( Kicker::the()->kwinModule(), SIGNAL( showingDesktopChanged( bool )), + SLOT( showingDesktopChanged( bool ))); + showingDesktopChanged( m_showingDesktop = Kicker::the()->kwinModule()->showingDesktop()); + } +} + +void ShowDesktop::slotCurrentDesktopChanged(int) +{ + showDesktop( false ); +} + +void ShowDesktop::slotWindowAdded(WId w) +{ + if (!m_showingDesktop) + { + return; + } + + NETWinInfo inf(qt_xdisplay(), w, qt_xrootwin(), + NET::XAWMState | NET::WMWindowType); + NET::WindowType windowType = inf.windowType(NET::AllTypesMask); + + if ((windowType == NET::Normal || windowType == NET::Unknown) && + inf.mappingState() == NET::Visible) + { + KConfig kwincfg( "kwinrc", true ); // see in kwin + kwincfg.setGroup( "Windows" ); + if( kwincfg.readBoolEntry( "ShowDesktopIsMinimizeAll", false )) + { + m_iconifiedList.clear(); + m_showingDesktop = false; + emit desktopShown(false); + } + else + { + m_activeWindow = w; + showDesktop(false); + } + } +} + +void ShowDesktop::slotWindowChanged(WId w, unsigned int dirty) +{ + if (!m_showingDesktop) + { + return; + } + + if (dirty & NET::XAWMState) + { + NETWinInfo inf(qt_xdisplay(), w, qt_xrootwin(), + NET::XAWMState | NET::WMWindowType); + NET::WindowType windowType = inf.windowType(NET::AllTypesMask); + + if ((windowType == NET::Normal || windowType == NET::Unknown) && + inf.mappingState() == NET::Visible) + { + // a window was deiconified, abort the show desktop mode. + m_iconifiedList.clear(); + m_showingDesktop = false; + emit desktopShown(false); + } + } +} + +void ShowDesktop::showDesktop( bool b ) +{ + if (b == m_showingDesktop) + { + return; + } + + if( m_wmSupport ) + { + NETRootInfo i( qt_xdisplay(), 0 ); + i.setShowingDesktop( b ); + return; + } + + if (b) + { + m_activeWindow = Kicker::the()->kwinModule()->activeWindow(); + m_iconifiedList.clear(); + + const QValueList<WId> windows = Kicker::the()->kwinModule()->windows(); + for (QValueList<WId>::ConstIterator it = windows.begin(); + it != windows.end(); + ++it) + { + WId w = *it; + + NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), + NET::XAWMState | NET::WMDesktop ); + + if (info.mappingState() == NET::Visible && + (info.desktop() == NETWinInfo::OnAllDesktops || + info.desktop() == (int)Kicker::the()->kwinModule()->currentDesktop())) + { + m_iconifiedList.append( w ); + } + } + + // find first, hide later, otherwise transients may get minimized + // with the window they're transient for + for (QValueVector<WId>::Iterator it = m_iconifiedList.begin(); + it != m_iconifiedList.end(); + ++it) + { + KWin::iconifyWindow( *it, false ); + } + + // on desktop changes or when a window is deiconified, we abort the show desktop mode + connect(Kicker::the()->kwinModule(), SIGNAL(currentDesktopChanged(int)), + SLOT(slotCurrentDesktopChanged(int))); + connect(Kicker::the()->kwinModule(), SIGNAL(windowChanged(WId,unsigned int)), + SLOT(slotWindowChanged(WId,unsigned int))); + connect(Kicker::the()->kwinModule(), SIGNAL(windowAdded(WId)), + SLOT(slotWindowAdded(WId))); + } + else + { + disconnect(Kicker::the()->kwinModule(), SIGNAL(currentDesktopChanged(int)), + this, SLOT(slotCurrentDesktopChanged(int))); + disconnect(Kicker::the()->kwinModule(), SIGNAL(windowChanged(WId,unsigned int)), + this, SLOT(slotWindowChanged(WId,unsigned int))); + disconnect(Kicker::the()->kwinModule(), SIGNAL(windowAdded(WId)), + this, SLOT(slotWindowAdded(WId))); + + for (QValueVector<WId>::ConstIterator it = m_iconifiedList.begin(); + it != m_iconifiedList.end(); + ++it) + { + KWin::deIconifyWindow(*it, false); + } + + KWin::forceActiveWindow(m_activeWindow); + } + + m_showingDesktop = b; + emit desktopShown(m_showingDesktop); +} + +void ShowDesktop::showingDesktopChanged( bool showing ) +{ + m_showingDesktop = showing; + emit desktopShown(m_showingDesktop); +} diff --git a/kicker/kicker/core/showdesktop.h b/kicker/kicker/core/showdesktop.h new file mode 100644 index 000000000..bebf62007 --- /dev/null +++ b/kicker/kicker/core/showdesktop.h @@ -0,0 +1,64 @@ +/***************************************************************** + +Copyright (c) 1996-2000,2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __showdesktop_h__ +#define __showdesktop_h__ + +class KWinModule; + +#include <qvaluevector.h> + +/** + * Singleton class that handles desktop access (minimizing all windows) + */ +class ShowDesktop : public QObject +{ + Q_OBJECT + +public: + static ShowDesktop* the(); + bool desktopShowing() { return m_showingDesktop; } + +public slots: + void showDesktop(bool show); + void toggle() { showDesktop( !desktopShowing() ); } + +signals: + void desktopShown(bool shown); + +private slots: + void slotCurrentDesktopChanged(int); + void slotWindowAdded(WId w); + void slotWindowChanged(WId w, unsigned int dirty); + void showingDesktopChanged( bool ); + +private: + ShowDesktop(); + + bool m_showingDesktop; + QValueVector<WId> m_iconifiedList; + WId m_activeWindow; + bool m_wmSupport; +}; + +#endif diff --git a/kicker/kicker/core/unhidetrigger.cpp b/kicker/kicker/core/unhidetrigger.cpp new file mode 100644 index 000000000..bd0e0a0f8 --- /dev/null +++ b/kicker/kicker/core/unhidetrigger.cpp @@ -0,0 +1,137 @@ +/***************************************************************** + +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qtimer.h> +#include <qcursor.h> +#include <kdebug.h> + +#include "unhidetrigger.h" +#include "unhidetrigger.moc" + +UnhideTrigger* UnhideTrigger::the() +{ + static UnhideTrigger UnhideTrigger; + return &UnhideTrigger; +} + +UnhideTrigger::UnhideTrigger() + : _lastTrigger( None ) + , _lastXineramaScreen( -1 ) + , enabledCount( 0 ) +{ + _timer = new QTimer( this ); + connect( _timer, SIGNAL(timeout()), SLOT(pollMouse()) ); +} + +void UnhideTrigger::setEnabled( bool enable ) +{ + if( enable ) { + enabledCount++; + } else { + enabledCount--; + } + + if ( enabledCount > 0 && !_timer->isActive() ) { + _timer->start( 100 ); + } else if( enabledCount <= 0 ) { + _timer->stop(); + } +} + +bool UnhideTrigger::isEnabled() const +{ + return _timer->isActive(); +} + +void UnhideTrigger::pollMouse() +{ + QPoint pos = QCursor::pos(); + for(int s = 0; s < QApplication::desktop()->numScreens(); s++) + { + QRect r = QApplication::desktop()->screenGeometry(s); + if (pos.x() == r.left()) + { + if (pos.y() == r.top()) + { + emitTrigger(TopLeft, s); + } + else if (pos.y() == r.bottom()) + { + emitTrigger(BottomLeft, s); + } + else + { + emitTrigger(Left, s); + } + } + else if (pos.x() == r.right()) + { + if (pos.y() == r.top()) + { + emitTrigger(TopRight, s); + } + else if (pos.y() == r.bottom()) + { + emitTrigger(BottomRight, s); + } + else + { + emitTrigger(Right, s); + } + } + else if (pos.y() == r.top()) + { + emitTrigger(Top, s); + } + else if (pos.y() == r.bottom()) + { + emitTrigger(Bottom, s); + } + else if (_lastTrigger != None) + { + emitTrigger(None, -1); + } + } +} + +void UnhideTrigger::resetTriggerThrottle() +{ + _lastTrigger = None; + _lastXineramaScreen = -1; +} + +void UnhideTrigger::emitTrigger( Trigger t, int XineramaScreen ) +{ + if( _lastTrigger == t && _lastXineramaScreen == XineramaScreen) + return; + + resetTriggerThrottle(); + emit triggerUnhide( t, XineramaScreen ); +} + +void UnhideTrigger::triggerAccepted( Trigger t, int XineramaScreen ) +{ + _lastTrigger = t; + _lastXineramaScreen = XineramaScreen; +} + diff --git a/kicker/kicker/core/unhidetrigger.h b/kicker/kicker/core/unhidetrigger.h new file mode 100644 index 000000000..7e13a0e1d --- /dev/null +++ b/kicker/kicker/core/unhidetrigger.h @@ -0,0 +1,62 @@ +/***************************************************************** + +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __UnhideTrigger_h__ +#define __UnhideTrigger_h__ + +// Fix compilation with --enable-final +#ifdef None +#undef None +#endif + + +#include <qobject.h> + +class UnhideTrigger : public QObject +{ + Q_OBJECT +public: + enum Trigger { None = 0, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, TopLeft }; + static UnhideTrigger* the(); + + void setEnabled( bool enable ); + bool isEnabled() const; + + // this is called whenever an item accepts a trigger, thereby preventing further calling of it again + void triggerAccepted( UnhideTrigger::Trigger t, int XineramaScreen ); + void resetTriggerThrottle(); + +signals: + void triggerUnhide( UnhideTrigger::Trigger t, int XineramaScreen ); +private slots: + void pollMouse(); +private: + UnhideTrigger(); + void emitTrigger( Trigger t , int XineramaScreen ); + Trigger _lastTrigger; + int _lastXineramaScreen; + QTimer *_timer; + int enabledCount; +}; + +#endif diff --git a/kicker/kicker/core/userrectsel.cpp b/kicker/kicker/core/userrectsel.cpp new file mode 100644 index 000000000..5654b1eb3 --- /dev/null +++ b/kicker/kicker/core/userrectsel.cpp @@ -0,0 +1,147 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qpainter.h> + +#include "userrectsel.h" +#include "userrectsel.moc" + +UserRectSel::UserRectSel(const RectList& rects, const QPoint& _offset, const QColor& color) + : QWidget(0, 0, WStyle_Customize | WX11BypassWM), + rectangles(rects), + offset(_offset) +{ + setGeometry(-10, -10, 2, 2); + _color = color; + for (int i = 0; i < 8; i++) + _frame[i] = 0; +} + +UserRectSel::~UserRectSel() +{ + for (int i = 0; i < 8; i++) + delete _frame[i]; +} + +void UserRectSel::mouseReleaseEvent(QMouseEvent * e) +{ + if (e->button() == LeftButton) + { + qApp->exit_loop(); + } +} + +void UserRectSel::mouseMoveEvent(QMouseEvent * e) +{ + PanelStrut nearest = current; + int diff = -1; + QPoint p = e->globalPos(); // + offset; + for (RectList::const_iterator it = rectangles.constBegin(); + it != rectangles.constEnd(); + ++it) + { + PanelStrut r = *it; + int ndiff = (r.m_rect.center() - p).manhattanLength(); + + if (diff < 0 || ndiff < diff) + { + diff = ndiff; + nearest = r; + } + } + + if (nearest != current) + { + paintCurrent(); + current = nearest; + paintCurrent(); + } +} + +void UserRectSel::paintCurrent() +{ + int i; + int x, y, w, h; + + if (!_frame[0]) + { + for (i = 0; i < 4; i++) + { + _frame[i] = new QWidget(0, 0, Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WX11BypassWM); + _frame[i]->setPaletteBackgroundColor(Qt::black); + } + for (i = 4; i < 8; i++) + { + _frame[i] = new QWidget(0, 0, Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WX11BypassWM); + _frame[i]->setPaletteBackgroundColor(_color); + } + } + + x = current.m_rect.x(); + y = current.m_rect.y(); + w = current.m_rect.width(); + h = current.m_rect.height(); + + if (w > 0 && h > 0) + { + _frame[0]->setGeometry(x, y, w, 4); + _frame[1]->setGeometry(x, y, 4, h); + _frame[2]->setGeometry(x + w - 4, y, 4, h); + _frame[3]->setGeometry(x, y + h - 4, w, 4); + + for (i = 0; i < 4; i++) + _frame[i]->show(); + } + + x += 1; + y += 1; + w -= 2; + h -= 2; + + if (w > 0 && h > 0) + { + _frame[4]->setGeometry(x, y, w, 2); + _frame[5]->setGeometry(x, y, 2, h); + _frame[6]->setGeometry(x + w - 2, y, 2, h); + _frame[7]->setGeometry(x, y + h - 2, w, 2); + + for (i = 4; i < 8; i++) + _frame[i]->show(); + } + +} + +UserRectSel::PanelStrut UserRectSel::select(const RectList& rects, const QPoint& offset, const QColor& color) +{ + UserRectSel sel(rects, offset, color); + sel.show(); + sel.grabMouse(); + sel.paintCurrent(); + qApp->enter_loop(); + sel.paintCurrent(); + sel.releaseMouse(); + qApp->syncX(); + return sel.current; +} + diff --git a/kicker/kicker/core/userrectsel.h b/kicker/kicker/core/userrectsel.h new file mode 100644 index 000000000..724f39818 --- /dev/null +++ b/kicker/kicker/core/userrectsel.h @@ -0,0 +1,99 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __userrectsel_h__ +#define __userrectsel_h__ + +#include <qwidget.h> +#include <qvaluevector.h> +#include <qcolor.h> + +#include <kpanelextension.h> + +class ShutUpCompiler; + +class UserRectSel : public QWidget +{ + Q_OBJECT + + public: + class PanelStrut + { + public: + PanelStrut() + : m_screen(-1), + m_pos(KPanelExtension::Bottom), + m_alignment(KPanelExtension::LeftTop) + { + } + + PanelStrut(const QRect& rect, int XineramaScreen, + KPanelExtension::Position pos, + KPanelExtension::Alignment alignment) + : m_rect(rect), + m_screen(XineramaScreen), + m_pos(pos), + m_alignment(alignment) + { + } + + bool operator==(const PanelStrut& rhs) + { + return m_screen == rhs.m_screen && + m_pos == rhs.m_pos && + m_alignment == rhs.m_alignment; + } + + bool operator!=(const PanelStrut& rhs) + { + return !(*this == rhs); + } + + QRect m_rect; + int m_screen; + KPanelExtension::Position m_pos; + KPanelExtension::Alignment m_alignment; + }; + + typedef QValueVector<PanelStrut> RectList; + static PanelStrut select(const RectList& rects, const QPoint& _offset, const QColor& color); + + protected: + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + + private: + UserRectSel(const RectList& rects, const QPoint& _offset, const QColor& color); + ~UserRectSel(); + void paintCurrent(); + + const RectList rectangles; + PanelStrut current; + QPoint offset; + QWidget *_frame[8]; + QColor _color; + + friend class ShutUpCompiler; +}; + +#endif diff --git a/kicker/kicker/kcmkicker.desktop b/kicker/kicker/kcmkicker.desktop new file mode 100644 index 000000000..d2a575979 --- /dev/null +++ b/kicker/kicker/kcmkicker.desktop @@ -0,0 +1,80 @@ +[Desktop Entry] +Icon=kcmkicker +Type=Application +Exec=kcmshell %i kicker_config kcmtaskbar +Name=Configure the Panel +Name[af]=Stel die paneel op +Name[ar]=قم بإعداد اللوØØ© +Name[az]=Paneli QuraÅŸdır +Name[be]=ÐаÑтаўленне панÑлі +Name[bg]=ÐаÑтройване на панела +Name[bn]=পà§à¦¯à¦¾à¦¨à§‡à¦² কনফিগার করো +Name[br]=Kefluniañ ar panell +Name[bs]=Podesite Panel +Name[ca]=Configura el plafó +Name[cs]=Nastavit panel +Name[csb]=Kònfigùracëjô panelu +Name[cy]=Ffurfweddu'r Panel +Name[da]=Indstil panelet +Name[de]=Kontrollleiste einrichten +Name[el]=ΡÏθμιση του πίνακα +Name[eo]=Agordo de Panelo +Name[es]=Configuración del panel +Name[et]=Paneeli seadistamine +Name[eu]=Konfiguratu panela +Name[fa]=پیکربندی تابلو +Name[fi]=Paneelin asetukset +Name[fr]=Configuration du tableau de bord +Name[fy]=Paniel ynstelle +Name[ga]=Cumraigh an Painéal +Name[gl]=Configurar o Painel +Name[he]=הגדר ×ת הלוח +Name[hi]=फलक कॉनà¥à¤«à¤¼à¤¿à¤—र करें +Name[hr]=Konfiguriranje ploÄe +Name[hu]=A panel beállÃtása +Name[is]=Stilla spjaldið +Name[it]=Configura il pannello +Name[ja]=パãƒãƒ«ã®è¨å®š +Name[ka]=პáƒáƒœáƒ”ლის კáƒáƒœáƒ¤áƒ˜áƒ’ურირებრ+Name[kk]=Панельді баптау +Name[km]=កំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​បន្ទះ +Name[ko]=íŒ¨ë„ ìž‘ì—… 표시줄 ì„¤ì • +Name[lt]=KonfigÅ«ruoti pultÄ… +Name[lv]=KonfigurÄ“t paneli +Name[mk]=Конфигурација на панелот +Name[mn]=Удирдах Ñамбар тохируулах +Name[ms]=Konfigur Panel +Name[mt]=Ikkonfigura l-pannell +Name[nb]=Tilpass panelet +Name[nds]=Dat Paneel instellen +Name[ne]=पà¥à¤¯à¤¾à¤¨à¤² कनà¥à¤«à¤¿à¤—र गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Name[nl]=Paneel instellen +Name[nn]=Set opp panelet +Name[pa]=ਪੈਨਲ ਸੰਰਚਨਾ +Name[pl]=Konfiguracja panelu +Name[pt]=Configurar o Painel +Name[pt_BR]=Configurar o Painel +Name[ro]=Configurează panoul +Name[ru]=ÐаÑтройка панели +Name[rw]=Kuboneza Umwanya +Name[se]=Heivet panela +Name[sk]=NastaviÅ¥ panel +Name[sl]=Nastavi pult +Name[sr]=Подешавање панела +Name[sr@Latn]=PodeÅ¡avanje panela +Name[sv]=Anpassa panelen +Name[ta]=பலகதà¯à®¤à¯ˆ வடிவமை +Name[tg]=Танзими Ñафҳа +Name[th]=ปรับà¹à¸•à¹ˆà¸‡à¸žà¸²à¹€à¸™à¸¥ +Name[tr]=Paneli Yapılandır +Name[tt]=Taqtanı Caylaw +Name[uk]=ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– +Name[uz]=Panelni moslash +Name[uz@cyrillic]=Панелни моÑлаш +Name[vi]=Cấu hình Bảng Ä‘iá»u khiển +Name[wa]=Apontyî li scriftôr +Name[zh_CN]=é…ç½®é¢æ¿ +Name[zh_TW]=è¨å®šé¢æ¿ +X-KDE-StartupNotify=true +OnlyShowIn=KDE; +Categories=Qt;KDE;Settings; diff --git a/kicker/kicker/kicker-3.1-properSizeSetting.pl b/kicker/kicker/kicker-3.1-properSizeSetting.pl new file mode 100644 index 000000000..1fba4eaeb --- /dev/null +++ b/kicker/kicker/kicker-3.1-properSizeSetting.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +while (<>) +{ + ($key, $sizeSetting) = ($_ =~ /([^=]+)=[ \t]*([^\n]+)/); + if ($key eq "Size") + { + print "[General]\n"; + + if ($sizeSetting == '24') + { + print "Size=0\n"; + } + elsif ($sizeSetting == '30') + { + print "Size=1\n"; + } + elsif ($sizeSetting == '46') + { + print "Size=2\n"; + } + elsif ($sizeSetting == '58') + { + print "Size=3\n"; + } + elsif ($sizeSetting > 10) + { + print "Size=4\n"; + print "CustomSize=" . $sizeSetting . "\n"; + } + exit(0); + } +} + diff --git a/kicker/kicker/kicker-3.4-reverseLayout.cpp b/kicker/kicker/kicker-3.4-reverseLayout.cpp new file mode 100644 index 000000000..bfcea5629 --- /dev/null +++ b/kicker/kicker/kicker-3.4-reverseLayout.cpp @@ -0,0 +1,152 @@ +#include <qfile.h> +#include <qmap.h> +#include <qregexp.h> +#include <qstring.h> +#include <qtextstream.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kglobal.h> +#include <klocale.h> +#include <kprocess.h> +#include <ktempfile.h> + +struct AppletInfo +{ + double freeSpace; + QString configFile; + QString desktopFile; +}; +typedef QMap<QString, AppletInfo> AppletInfoMap; + +int main(int argc, char** argv) +{ + // We must disguise as Kicker in order to obtain the correct reverseLayout setting. + KCmdLineArgs::init(argc, argv, "kicker", "", "", "", false); + KApplication app(false, false); + + QStringList stretchableApplets; + stretchableApplets << "taskbarapplet.desktop"; + + QTextStream in (stdin, IO_ReadOnly); + QTextStream out(stdout, IO_WriteOnly); + + QStringList appletIds; + AppletInfoMap applets; + + QRegExp rxGroup("^\\[(.+)\\]$"); + QRegExp rxKeyValue("([^=]+)=[ \t]*([^\n]+)"); + QString currentGroup; + + QString line; + while (!(line = in.readLine()).isNull()) + { + if (rxGroup.search(line) != -1) + { + currentGroup = rxGroup.cap(1); + continue; + } + + if (rxKeyValue.search(line) != -1) + { + QString key = rxKeyValue.cap(1); + QString value = rxKeyValue.cap(2); + + if (key == "Applets") + { + appletIds = QStringList::split(",", value); + } + else if (key == "FreeSpace") + { + applets[currentGroup].freeSpace = value.toDouble(); + } + else if (key == "ConfigFile") + { + applets[currentGroup].configFile = value; + } + else if (key == "DesktopFile") + { + applets[currentGroup].desktopFile = value; + } + } + } + + if (QApplication::reverseLayout()) + { + // Reverse appletIds + QStringList appletIdsRev; + QStringList::ConstIterator it; + for (it = appletIds.begin(); it != appletIds.end(); ++it) + { + appletIdsRev.prepend(*it); + } + appletIds = appletIdsRev; + + // Adjust the FreeSpace values + for (it = appletIds.begin(); it != appletIds.end(); ++it) + { + applets[*it].freeSpace = 1 - applets[*it].freeSpace; + + // Take care of stretchable applets. + if (stretchableApplets.contains(applets[*it].desktopFile)) + { + if (it != appletIds.begin()) + { + applets[*it].freeSpace = applets[*(--it)].freeSpace; + ++it; + } + else + { + applets[*it].freeSpace = 0; + } + } + } + } + + // Write the changed entries to stdout. + if (!appletIds.empty()) + { + out << "[General]" << endl; + out << "Applets2=" << appletIds.join(",") << endl; + QStringList::ConstIterator it; + for (it = appletIds.begin(); it != appletIds.end(); ++it) + { + out << "[" << *it << "]" << endl; + out << "FreeSpace2=" << applets[*it].freeSpace << endl; + } + } + + // Build a list of childpanel config files. + QStringList childPanelConfigFiles; + AppletInfoMap::ConstIterator it2; + QStringList::ConstIterator it; + for (it2 = applets.begin(); it2 != applets.end(); ++it2) + { + if (it2.data().desktopFile == "childpanelextension.desktop") + { + childPanelConfigFiles << it2.data().configFile; + } + } + + if (!childPanelConfigFiles.isEmpty()) + { + // Create a temporary kconf_update .upd file for updating the childpanels + KTempFile tempFile(QString::null, ".upd"); + QTextStream* upd = tempFile.textStream(); + for (it = childPanelConfigFiles.begin(); it != childPanelConfigFiles.end(); ++it) + { + *upd << "Id=kde_3.4_reverseLayout" << endl; + *upd << "File=" << *it << endl; + *upd << "Script=kicker-3.4-reverseLayout" << endl; + *upd << endl; + } + tempFile.close(); + + // Run kconf_update on the childpanel config files. + KProcess kconf_update; + kconf_update << "kconf_update" << tempFile.name(); + kconf_update.start(KProcess::Block); + + tempFile.unlink(); + } +} diff --git a/kicker/kicker/kicker-3.5-kconfigXTize.pl b/kicker/kicker/kicker-3.5-kconfigXTize.pl new file mode 100755 index 000000000..e836116d7 --- /dev/null +++ b/kicker/kicker/kicker-3.5-kconfigXTize.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl + +$detailed = 1; +$namesfirst = 1; + +while (<>) +{ + ($key, $value) = ($_ =~ /([^=]+)=[ \t]*([^\n]+)/); + if ($key eq "DetailedMenuEntries") + { + if ($value eq "false") + { + $detailed = 0; + } + } + elsif ($key eq "DetailedEntriesNamesFirst") + { + if ($value eq "false") + { + $namesfirst = 0; + } + } +} + +if (not $detailed) +{ + print "MenuEntryFormat=NameOnly\n"; +} +elsif ($namesfirst) +{ + print "MenuEntryFormat=NameAndDescription\n"; +} +else +{ + print "MenuEntryFormat=DescriptionAndName\n"; +} + diff --git a/kicker/kicker/kicker-3.5-taskbarEnums.pl b/kicker/kicker/kicker-3.5-taskbarEnums.pl new file mode 100755 index 000000000..1379e0c9d --- /dev/null +++ b/kicker/kicker/kicker-3.5-taskbarEnums.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl + +while (<>) +{ + ($key, $value) = ($_ =~ /([^=]+)=[ \t]*([^\n]+)/); + if ($key eq "GroupTasks") + { + if ($value eq "Never") + { + print "GroupTasks=GroupNever\n"; + } + elsif ($value eq "When Taskbar Full") + { + print "GroupTasks=GroupWhenFull\n"; + } + elsif ($value eq "Always") + { + print "GroupTasks=GroupAlways\n"; + } + } + elsif ($key =~ /ButtonAction/) + { + if ($value eq "Show Task List") + { + print "$key=ShowTaskList\n"; + } + elsif ($value eq "Show Operations Menu") + { + print "$key=ShowOperationsMenu\n"; + } + elsif ($value eq "Activate, Raise or Minimize Task") + { + print "$key=ActivateRaiseOrMinimize\n"; + } + elsif ($value eq "Activate Task") + { + print "$key=Activate\n"; + } + elsif ($value eq "Raise Task") + { + print "$key=Raise\n"; + } + elsif ($value eq "Lower Task") + { + print "$key=Lower\n"; + } + elsif ($value eq "Minimize Task") + { + print "$key=Minimize\n"; + } + + } +} + diff --git a/kicker/kicker/kickerrc.upd b/kicker/kicker/kickerrc.upd new file mode 100644 index 000000000..282a52cb1 --- /dev/null +++ b/kicker/kicker/kickerrc.upd @@ -0,0 +1,22 @@ +Id=kde_3_1_sizeChanges +File=kickerrc +Group=General +Options=overwrite +Script=kicker-3.1-properSizeSetting.pl,perl + +Id=kde_3_4_reverseLayout +File=kickerrc +Script=kicker-3.4-reverseLayout + +Id=kde_3_5_taskbarEnums +File=ktaskbarrc +Group=General +Options=overwrite +Script=kicker-3.5-taskbarEnums.pl,perl + +Id=kde_3_5_kconfigXTize +File=kickerrc +Group=menus +Script=kicker-3.5-kconfigXTize.pl,perl +RemoveKey=DetailedEntriesNamesFirst +RemoveKey=DetailedMenuEntries diff --git a/kicker/kicker/panel.desktop b/kicker/kicker/panel.desktop new file mode 100644 index 000000000..605610841 --- /dev/null +++ b/kicker/kicker/panel.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Exec=kicker +Name=KDE Panel +Name[af]=KDE Paneel +Name[ar]=لوØØ© KDE +Name[az]=KDE Paneli +Name[be]=ПанÑль KDE +Name[bg]=СиÑтемен панел +Name[bn]=কে.ডি.ই. পà§à¦¯à¦¾à¦¨à§‡à¦² +Name[br]=Panell KDE +Name[bs]=KDE panel +Name[ca]=Plafó KDE +Name[cs]=Panel KDE +Name[cy]=Panel KDE +Name[de]=KDE-Kontrollleiste +Name[el]=Πίνακας KDE +Name[eo]=Panelo +Name[es]=Panel de KDE +Name[et]=KDE paneel +Name[eu]=KDE panela +Name[fa]=تابلوی KDE +Name[fi]=KDE-paneeli +Name[fr]=Tableau de bord de KDE +Name[fy]=KDE Paniel +Name[ga]=Painéal KDE +Name[gl]=Painel de KDE +Name[he]=הלוח של KDE +Name[hi]=केडीई फलक +Name[hr]=KDE ploÄa +Name[hu]=Panel +Name[id]=Panel KDE +Name[is]=KDE spjald +Name[it]=Pannello di KDE +Name[ja]=KDE パãƒãƒ« +Name[ka]=KDE-ს პáƒáƒœáƒ”ლი +Name[kk]=KDE панелі +Name[km]=បន្ទះ KDE +Name[ku]=Panela KDE'yê +Name[lo]=ຖາດພາເນລຂàºà¸‡ KDE +Name[lt]=KDE pultas +Name[lv]=KDE Panelis +Name[mk]=Панелот на KDE +Name[mn]=КДÐ-Удирдлагын Ñамбар +Name[ms]=Panel KDE +Name[mt]=Pannell KDE +Name[nb]=KDE-Panel +Name[nds]=KDE-Paneel +Name[ne]=KDE पà¥à¤¯à¤¾à¤¨à¤² +Name[nl]=KDE Paneel +Name[nn]=KDE-panel +Name[nso]=Panel ya KDE +Name[pa]=KDE ਪੈਨਲ +Name[pl]=Panel +Name[pt]=Painel do KDE +Name[pt_BR]=Painel do KDE +Name[ro]=Panou KDE +Name[ru]=Панель KDE +Name[rw]=KDE Umwanya +Name[se]=KDE-panela +Name[sk]=KDE panel +Name[sl]=Pult KDE +Name[sr]=KDE панел +Name[sr@Latn]=KDE panel +Name[sv]=KDE-panel +Name[ta]=KDE பலகம௠+Name[te]=కెడిఈ పెనలౠ+Name[tg]=Сафҳаи KDE +Name[th]=ถาดพาเนล KDE +Name[tr]=KDE Paneli +Name[tt]=KDE Ãœzäge +Name[uk]=Панель KDE +Name[uz]=KDE paneli +Name[uz@cyrillic]=KDE панели +Name[ven]=Phanele ya KDE +Name[vi]=Bảng Ä‘iá»u khiển KDE +Name[wa]=Scriftôr KDE +Name[xh]=Ipanel ye KDE +Name[zh_CN]=KDE é¢æ¿ +Name[zh_TW]=KDE é¢æ¿ +Name[zu]=Iwindi lemininingwane le-KDE +X-DCOP-ServiceType=wait +X-KDE-autostart-after=kdesktop +DocPath=kicker/index.html +Type=Service +OnlyShowIn=KDE; +X-KDE-autostart-phase=0 diff --git a/kicker/kicker/ui/Makefile.am b/kicker/kicker/ui/Makefile.am new file mode 100644 index 000000000..e60e99bfd --- /dev/null +++ b/kicker/kicker/ui/Makefile.am @@ -0,0 +1,41 @@ +INCLUDES = -I$(srcdir)/../core -I../core -I$(srcdir)/../buttons \ + -I../../libkicker -I$(srcdir)/../../libkicker \ + -I$(top_srcdir)/libkonq -I$(top_srcdir)/kdmlib $(all_includes) + +noinst_LTLIBRARIES = libkicker_ui.la + +libkicker_ui_la_SOURCES = addbutton_mnu.cpp appletitem.ui appletview.ui addapplet.cpp \ + addapplet_mnu.cpp appletop_mnu.cpp \ + browser_mnu.cpp client_mnu.cpp dirdrop_mnu.cpp \ + nonKDEButtonSettings.ui exe_dlg.cpp k_mnu.cpp k_mnu.skel\ + quickbrowser_mnu.cpp service_mnu.cpp \ + addextension_mnu.cpp extensionop_mnu.cpp \ + recentapps.cpp browser_dlg.cpp \ + removeapplet_mnu.cpp removeextension_mnu.cpp removecontainer_mnu.cpp \ + removebutton_mnu.cpp popupmenutitle.cpp hidebutton.cpp \ + addappletvisualfeedback.cpp + +libkicker_ui_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(top_builddir)/kdmlib/libdmctl.la + +libkicker_ui_la_METASOURCES = AUTO + +noinst_HEADERS = addapplet.h appletwidget.h addbutton_mnu.h addapplet_mnu.h appletop_mnu.h \ + browser_mnu.h client_mnu.h dirdrop_mnu.h exe_dlg.h k_mnu.h \ + quickbrowser_mnu.h service_mnu.h \ + addextension_mnu.h extensionop_mnu.h \ + recentapps.h browser_dlg.h \ + removeapplet_mnu.h removeextension_mnu.h removecontainer_mnu.h \ + removebutton_mnu.h popupmenutitle.h hidebutton.h addappletvisualfeedback.h + +removecontainer_mnu.lo: ../../libkicker/kickerSettings.h +removeextension_mnu.lo: ../../libkicker/kickerSettings.h +addextension_mnu.lo: ../core/extensionSettings.h +appletop_mnu.lo: ../../libkicker/kickerSettings.h +extensionop_mnu.lo: ../../libkicker/kickerSettings.h +k_mnu.lo: ../../libkicker/kickerSettings.h +removecontainer_mnu.lo: ../core/extensionSettings.h +removeextension_mnu.lo: ../core/extensionSettings.h +service_mnu.lo: ../../libkicker/kickerSettings.h +browser_mnu.lo: ../../libkicker/kickerSettings.h +recentapps.lo: ../../libkicker/kickerSettings.h + diff --git a/kicker/kicker/ui/addapplet.cpp b/kicker/kicker/ui/addapplet.cpp new file mode 100644 index 000000000..e7ac47c9c --- /dev/null +++ b/kicker/kicker/ui/addapplet.cpp @@ -0,0 +1,542 @@ +/***************************************************************** + +Copyright (c) 2005 Marc Cramdal +Copyright (c) 2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qcombobox.h> +#include <qdir.h> +#include <qframe.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpalette.h> +#include <qscrollview.h> +#include <qtimer.h> +#include <qsizepolicy.h> + +#include <kiconloader.h> +#include <kdebug.h> +#include <kglobalsettings.h> +#include <kpushbutton.h> +#include <kstandarddirs.h> +#include <kstdguiitem.h> + +#include <paneldrag.h> + +#include "addapplet.h" +#include "addappletvisualfeedback.h" +#include "appletwidget.h" +#include "appletview.h" +#include "container_applet.h" +#include "container_extension.h" +#include "containerarea.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "menuinfo.h" +#include "pluginmanager.h" + +AppletWidget::AppletWidget(const AppletInfo& info, bool odd, QWidget *parent) + : AppletItem(parent), + m_appletInfo(info), + m_odd(odd), + m_selected(false) +{ + setFocusPolicy(QWidget::StrongFocus); + setSelected(m_selected); + + itemTitle->setText("<h3>" + info.name() + "</h3>"); + itemTitle->installEventFilter(this); + + if (info.comment() != info.name()) + { + itemDescription->setText(info.comment()); + } + + itemDescription->installEventFilter(this); + + KIconLoader * ldr = KGlobal::iconLoader(); + QPixmap icon = ldr->loadIcon(info.icon(), KIcon::Panel, KIcon::SizeLarge); + itemPixmap->setPixmap(icon); + itemPixmap->installEventFilter(this); +} + +bool AppletWidget::eventFilter(QObject*, QEvent* e) +{ + if (e->type() == QEvent::MouseButtonPress) + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if (me->button() & LeftButton) + { + m_dragStart = me->pos(); + } + } + else if (m_dragStart.isNull()) + { + return false; + } + + if (e->type() == QEvent::MouseMove) + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if ((me->pos() - m_dragStart).manhattanLength() > + KGlobalSettings::dndEventDelay()) + { + AppletInfoDrag* drag = new AppletInfoDrag(m_appletInfo, this); + + if (itemPixmap->pixmap()) + { + drag->setPixmap(*itemPixmap->pixmap()); + } + + drag->dragCopy(); + + return true; + } + } + else if (e->type() == QEvent::MouseButtonRelease) + { + m_dragStart = QPoint(); + } + + return false; +} + +void AppletWidget::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Enter || + e->key() == Qt::Key_Return) + { + emit doubleClicked(this); + } + else if (e->key() == Qt::Key_Up) + { + QKeyEvent fakedKeyPress(QEvent::KeyPress, Qt::Key_BackTab, 0, 0); + QKeyEvent fakedKeyRelease(QEvent::KeyRelease, Key_BackTab, 0, 0); + QApplication::sendEvent(this, &fakedKeyPress); + QApplication::sendEvent(this, &fakedKeyRelease); + } + else if (e->key() == Qt::Key_Down) + { + QKeyEvent fakedKeyPress(QEvent::KeyPress, Qt::Key_Tab, 0, 0); + QKeyEvent fakedKeyRelease(QEvent::KeyRelease, Key_Escape, 0, 0); + QApplication::sendEvent(this, &fakedKeyPress); + QApplication::sendEvent(this, &fakedKeyRelease); + } + else + { + AppletItem::keyPressEvent(e); + } +} + +void AppletWidget::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == QMouseEvent::LeftButton) + { + emit clicked(this); + m_dragStart = e->pos(); + } + + setFocus(); + QWidget::mousePressEvent(e); +} + +void AppletWidget::mouseMoveEvent(QMouseEvent *e) +{ + if (e->button() == QMouseEvent::LeftButton && + !m_dragStart.isNull() && + (e->pos() - m_dragStart).manhattanLength() > + KGlobalSettings::dndEventDelay()) + { + AppletInfoDrag* drag = new AppletInfoDrag(m_appletInfo, this); + + if (itemPixmap->pixmap()) + { + drag->setPixmap(*itemPixmap->pixmap()); + } + + drag->dragCopy(); + } +} + +void AppletWidget::mouseReleaseEvent(QMouseEvent *e) +{ + m_dragStart = QPoint(); + QWidget::mouseReleaseEvent(e); +} + +void AppletWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (!e->button() == QMouseEvent::LeftButton) + { + AppletItem::mouseDoubleClickEvent(e); + return; + } + + emit doubleClicked(this); +} + +void AppletWidget::setSelected(bool selected) +{ + m_selected = selected; + + // for now just used to switch colours around =) + if (m_selected) + { + setPaletteBackgroundColor(KGlobalSettings::highlightColor()); + setPaletteForegroundColor(KGlobalSettings::highlightedTextColor()); + } + else if (m_odd) + { + setPaletteBackgroundColor(KGlobalSettings::baseColor()); + setPaletteForegroundColor(KGlobalSettings::textColor()); + } + else + { + setPaletteBackgroundColor(KGlobalSettings::alternateBackgroundColor()); + setPaletteForegroundColor(KGlobalSettings::textColor()); + } +} + +void AppletWidget::setOdd(bool odd) +{ + m_odd = odd; + setSelected(m_selected); +} + +void AppletWidget::focusInEvent(QFocusEvent*) +{ + emit clicked(this); +} + +AddAppletDialog::AddAppletDialog(ContainerArea* cArea, + QWidget* parent, + const char* name) + : KDialogBase(parent, name, false, i18n("Add Applet"), 0), + m_selectedApplet(0), + m_containerArea(cArea), + m_insertionPoint(Kicker::the()->insertionPoint()), + m_closing(false), + m_searchDelay(new QTimer(this)) +{ + m_mainWidget = new AppletView(this, "AddAppletDialog::m_mainWidget"); + m_mainWidget->appletScrollView->setResizePolicy(QScrollView::Manual); + m_mainWidget->appletScrollView->setHScrollBarMode(QScrollView::AlwaysOff); + m_mainWidget->appletScrollView->viewport()->setPaletteBackgroundColor(KGlobalSettings::baseColor()); + + setMainWidget(m_mainWidget); + + resize(configDialogSize("AddAppletDialog Settings")); + centerOnScreen(this); + + KGuiItem addGuiItem = KStdGuiItem::add(); + addGuiItem.setText(m_mainWidget->appletInstall->text()); + m_mainWidget->appletInstall->setEnabled(false); + m_mainWidget->appletInstall->setGuiItem(addGuiItem); + m_mainWidget->closeButton->setGuiItem(KStdGuiItem::close()); + + connect(m_mainWidget->appletSearch, SIGNAL(textChanged(const QString&)), this, SLOT(delayedSearch())); + connect(m_searchDelay, SIGNAL(timeout()), this, SLOT(search())); + connect(m_mainWidget->appletFilter, SIGNAL(activated(int)), this, SLOT(filter(int))); + connect(m_mainWidget->appletInstall, SIGNAL(clicked()), this, SLOT(addCurrentApplet())); + connect(m_mainWidget->closeButton, SIGNAL(clicked()), this, SLOT(close())); + + m_selectedType = AppletInfo::Undefined; + m_appletBox = 0; + + QTimer::singleShot(0, this, SLOT(populateApplets())); +} + +void AddAppletDialog::updateInsertionPoint() +{ + m_insertionPoint = Kicker::the()->insertionPoint(); +} + + +void AddAppletDialog::closeEvent(QCloseEvent* e) +{ + m_closing = true; + saveDialogSize("AddAppletDialog Settings"); + KDialogBase::closeEvent(e); +} + +void AddAppletDialog::resizeAppletView() +{ + int w, h; + QScrollView *v = m_mainWidget->appletScrollView; + + if (m_closing) + return; + + for (int i = 0; i < 3; i++) + { + m_appletBox->layout()->activate(); + w = v->visibleWidth(); + h = m_appletBox->layout()->minimumSize().height(); + v->resizeContents(w, QMAX(h, v->visibleHeight())); + if (w == m_appletBox->width() && h == m_appletBox->height()) + break; + m_appletBox->resize(w, h); + v->updateScrollBars(); + } +} + +bool AddAppletDialog::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::Resize) + QTimer::singleShot(0, this, SLOT(resizeAppletView())); + + return QObject::eventFilter(o, e); +} + +void AddAppletDialog::populateApplets() +{ + m_appletBox = new QWidget(m_mainWidget->appletScrollView->viewport()); + m_appletBox->setPaletteBackgroundColor(KGlobalSettings::baseColor()); + m_mainWidget->appletScrollView->addChild(m_appletBox, 0, 0); + m_appletBox->show(); + QVBoxLayout* layout = new QVBoxLayout(m_appletBox); + layout->setMargin(0); + + m_mainWidget->appletScrollView->installEventFilter(this); + + /* Three steps + * - First we load the applets + * - We load the special buttons + * - Then we begin to populate the scrollview with the AppletWidget(s) + */ + AppletInfo::List appletInfoList; + + // Loading applets + appletInfoList = PluginManager::applets(false, &appletInfoList); + + // Loading built in buttons + appletInfoList = PluginManager::builtinButtons(false, &appletInfoList); + + // Loading special buttons + appletInfoList = PluginManager::specialButtons(false, &appletInfoList); + + qHeapSort(appletInfoList); + + int i = 0; + bool odd = true; + QWidget* prevTabWidget = m_mainWidget->appletFilter; + + for (AppletInfo::List::iterator it = appletInfoList.begin(); + !m_closing && it != appletInfoList.end(); + ++i) + { + if ((*it).isHidden() || (*it).name().isEmpty() || + ((*it).isUniqueApplet() && + PluginManager::the()->hasInstance(*it))) + { + it = appletInfoList.erase(it); + --i; + continue; + } + + AppletWidget *itemWidget = new AppletWidget(*it, odd, m_appletBox); + + if (m_mainWidget->appletSearch->text().isEmpty() || + appletMatchesSearch(itemWidget, m_mainWidget->appletSearch->text())) + { + itemWidget->show(); + odd = !odd; + } + else + { + itemWidget->hide(); + } + + layout->insertWidget(i, itemWidget); + m_appletWidgetList.append(itemWidget); + setTabOrder(prevTabWidget, itemWidget); + prevTabWidget = itemWidget; + + connect(itemWidget, SIGNAL(clicked(AppletWidget*)), + this, SLOT(selectApplet(AppletWidget*))); + connect(itemWidget, SIGNAL(doubleClicked(AppletWidget*)), + this, SLOT(addApplet(AppletWidget*))); + + if (m_closing) + { + return; + } + + ++it; + } + + resizeAppletView(); + + m_mainWidget->closeButton->setEnabled(true); +} + +void AddAppletDialog::selectApplet(AppletWidget *applet) +{ + m_mainWidget->appletInstall->setEnabled(true); + + if (m_selectedApplet) + { + m_selectedApplet->setSelected(false); + } + + m_selectedApplet = applet; + + if (m_selectedApplet) + { + m_selectedApplet->setSelected(true); + } +} + +void AddAppletDialog::addCurrentApplet() +{ + addApplet(m_selectedApplet); +} + +void AddAppletDialog::addApplet(AppletWidget* applet) +{ + if (!applet) + { + return; + } + + QPoint prevInsertionPoint = Kicker::the()->insertionPoint(); + Kicker::the()->setInsertionPoint(m_insertionPoint); + + const QWidget* appletContainer = 0; + + if (applet->info().type() == AppletInfo::Applet) + { + appletContainer = m_containerArea->addApplet(applet->info()); + + if (applet->info().isUniqueApplet() && + PluginManager::the()->hasInstance(applet->info())) + { + applet->hide(); + + // reset the odd/even colouring from this item on down in the list + bool odd = applet->odd(); + AppletWidget::List::const_iterator it = m_appletWidgetList.find(applet); + for (; it != m_appletWidgetList.constEnd(); ++it) + { + if ((*it)->isHidden()) + { + continue; + } + + (*it)->setOdd(odd); + odd = !odd; + } + } + } + else if (applet->info().type() & AppletInfo::Button) + { + appletContainer = m_containerArea->addButton(applet->info()); + } + + if (appletContainer) + { + ExtensionContainer* ec = + dynamic_cast<ExtensionContainer*>(m_containerArea->topLevelWidget()); + + if (ec) + { + // unhide the panel and keep it unhidden for at least the time the + // helper tip will be there + ec->unhideIfHidden(KickerSettings::mouseOversSpeed() + 2500); + } + + new AddAppletVisualFeedback(applet, appletContainer, + m_containerArea->popupDirection()); + } + + Kicker::the()->setInsertionPoint(prevInsertionPoint); +} + +bool AddAppletDialog::appletMatchesSearch(const AppletWidget* w, + const QString& s) +{ + if (w->info().type() == AppletInfo::Applet && + w->info().isUniqueApplet() && + PluginManager::the()->hasInstance(w->info())) + { + return false; + } + + return (m_selectedType == AppletInfo::Undefined || + w->info().type() & m_selectedType) && + (w->info().name().contains(s, false) || + w->info().comment().contains(s, false)); +} + +void AddAppletDialog::delayedSearch() +{ + if (!m_searchDelay->isActive()) + { + m_searchDelay->start(300, true); + } +} + +void AddAppletDialog::search() +{ + QString s = m_mainWidget->appletSearch->text(); + bool odd = true; + AppletWidget::List::const_iterator it = m_appletWidgetList.constBegin(); + AppletWidget::List::const_iterator itEnd = m_appletWidgetList.constEnd(); + + for (; it != itEnd; ++it) + { + AppletWidget* w = *it; + if (appletMatchesSearch(w, s)) + { + w->setOdd(odd); + w->show(); + odd = !odd; + } + else + { + w->hide(); + } + } + + QTimer::singleShot(0, this, SLOT(resizeAppletView())); +} + +void AddAppletDialog::filter(int i) +{ + m_selectedType = AppletInfo::Undefined; + + if (i == 1) + { + m_selectedType = AppletInfo::Applet; + } + else if (i == 2) + { + m_selectedType = AppletInfo::Button; + } + + search(); +} + +#include "addapplet.moc" +#include "appletwidget.moc" + diff --git a/kicker/kicker/ui/addapplet.h b/kicker/kicker/ui/addapplet.h new file mode 100644 index 000000000..d2ce50a00 --- /dev/null +++ b/kicker/kicker/ui/addapplet.h @@ -0,0 +1,82 @@ +/***************************************************************** + +Copyright (c) 2005 Marc Cramdal +Copyright (c) 2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __addapplet_h__ +#define __addapplet_h__ + +#include <qstringlist.h> +#include <qpixmap.h> +#include <qvaluelist.h> + +#include <klocale.h> +#include <kdialogbase.h> + +#include "appletinfo.h" + +class ContainerArea; +class AppletView; +class AppletWidget; +class QTimer; + +class AddAppletDialog : public KDialogBase +{ + Q_OBJECT + + public: + AddAppletDialog(ContainerArea* cArea, QWidget* parent, const char* name); + void updateInsertionPoint(); + + protected: + void closeEvent(QCloseEvent*); + bool eventFilter(QObject *o, QEvent *e); + + private slots: + void populateApplets(); + void addCurrentApplet(); + void addApplet(AppletWidget* applet); + void delayedSearch(); + void search(); + void filter(int i); + void selectApplet(AppletWidget* applet); + void resizeAppletView(); + + private: + bool appletMatchesSearch(const AppletWidget* w, const QString& s); + + AppletView *m_mainWidget; + QWidget *m_appletBox; + + AppletInfo::List m_applets; + + QValueList<AppletWidget*> m_appletWidgetList; + AppletWidget* m_selectedApplet; + + ContainerArea* m_containerArea; + AppletInfo::AppletType m_selectedType; + QPoint m_insertionPoint; + bool m_closing; + QTimer *m_searchDelay; +}; + +#endif diff --git a/kicker/kicker/ui/addapplet_mnu.cpp b/kicker/kicker/ui/addapplet_mnu.cpp new file mode 100644 index 000000000..3c3a3db87 --- /dev/null +++ b/kicker/kicker/ui/addapplet_mnu.cpp @@ -0,0 +1,75 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <kiconloader.h> + +#include "pluginmanager.h" +#include "containerarea.h" + +#include "addapplet_mnu.h" +#include "addapplet_mnu.moc" + +PanelAddAppletMenu::PanelAddAppletMenu(ContainerArea* cArea, QWidget *parent, const char *name) + : QPopupMenu(parent, name), containerArea(cArea) +{ + setCheckable(true); + connect(this, SIGNAL(activated(int)), SLOT(slotExec(int))); + connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); +} + +void PanelAddAppletMenu::slotAboutToShow() +{ + clear(); + + applets = PluginManager::applets(); + + AppletInfo::List::const_iterator it = applets.constBegin(); + for (int i = 0; it != applets.constEnd(); ++it, ++i) + { + const AppletInfo& ai = (*it); + if (ai.isHidden()) + { + continue; + } + + if (ai.icon().isEmpty() || ai.icon() == "unknown") + { + insertItem(ai.name().replace( "&", "&&" ), i); + } + else + { + insertItem(SmallIconSet(ai.icon()), ai.name().replace( "&", "&&" ), i); + } + + if (ai.isUniqueApplet() && PluginManager::the()->hasInstance(ai)) + { + setItemEnabled( i, false ); + setItemChecked( i, true ); + } + } +} + +void PanelAddAppletMenu::slotExec(int id) +{ + containerArea->addApplet( applets[id].desktopFile() ); +} diff --git a/kicker/kicker/ui/addapplet_mnu.h b/kicker/kicker/ui/addapplet_mnu.h new file mode 100644 index 000000000..260de26dd --- /dev/null +++ b/kicker/kicker/ui/addapplet_mnu.h @@ -0,0 +1,50 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __addapplet_mnu_h__ +#define __addapplet_mnu_h__ + +#include <qvaluelist.h> +#include <qpopupmenu.h> + +#include "appletinfo.h" + +class ContainerArea; + +class PanelAddAppletMenu : public QPopupMenu +{ + Q_OBJECT + +public: + PanelAddAppletMenu(ContainerArea *cArea, QWidget *parent=0, const char *name=0); + +protected slots: + virtual void slotExec(int id); + virtual void slotAboutToShow(); + +private: + AppletInfo::List applets; + ContainerArea* containerArea; +}; + +#endif diff --git a/kicker/kicker/ui/addappletvisualfeedback.cpp b/kicker/kicker/ui/addappletvisualfeedback.cpp new file mode 100644 index 000000000..ce6e618a7 --- /dev/null +++ b/kicker/kicker/ui/addappletvisualfeedback.cpp @@ -0,0 +1,230 @@ +/***************************************************************** + +Copyright (c) 2004-2005 Aaron J. Seigo <aseigo@kde.org> +Copyright (c) 2004 Zack Rusin <zrusin@kde.org> + Sami Kyostil <skyostil@kempele.fi> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qsimplerichtext.h> +#include <qtimer.h> + +#include <kdialog.h> +#include <klocale.h> + +#include "global.h" + +#include "appletinfo.h" +#include "appletwidget.h" +#include "addappletvisualfeedback.h" +#include "kickerSettings.h" + +#define DEFAULT_FRAMES_PER_SECOND 30 + +AddAppletVisualFeedback::AddAppletVisualFeedback(AppletWidget* widget, + const QWidget* target, + KPanelApplet::Direction direction) + : QWidget(0, "animtt", WX11BypassWM), + m_target(target), + m_direction(direction), + m_icon(*widget->itemPixmap->pixmap()), + m_richText(0), + m_dissolveDelta(-1), + m_frames(1), + m_dirty(false) +{ + setFocusPolicy(NoFocus); + setBackgroundMode(NoBackground); + connect(&m_moveTimer, SIGNAL(timeout()), SLOT(swoopCloser())); + + QString m = "<qt><h3>" + i18n("%1 Added").arg(widget->info().name()); + + if (widget->info().name() != widget->info().comment()) + { + m += "</h3><p>" + widget->info().comment() + "</p></qt>"; + } + + m_richText = new QSimpleRichText(m, font()); + m_richText->setWidth(400); + + displayInternal(); + + m_destination = KickerLib::popupPosition(m_direction, this, m_target); + QPoint startAt = widget->itemPixmap->geometry().topLeft(); + startAt = widget->itemPixmap->mapToGlobal(startAt); + move(startAt); + + m_frames = (m_destination - startAt).manhattanLength() / 20; + m_moveTimer.start(10); + + show(); +} + +AddAppletVisualFeedback::~AddAppletVisualFeedback() +{ + delete m_richText; +} + +void AddAppletVisualFeedback::paintEvent(QPaintEvent * e) +{ + if (m_dirty) + { + displayInternal(); + m_dirty = false; + } + + QPainter p(this); + p.drawPixmap(e->rect().topLeft(), m_pixmap, e->rect()); +} + +void AddAppletVisualFeedback::mousePressEvent(QMouseEvent *) +{ + m_moveTimer.stop(); + hide(); + deleteLater(); +} + +void AddAppletVisualFeedback::makeMask() +{ + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::white); + maskPainter.drawRoundRect(m_mask.rect(), 1600 / m_mask.rect().width(), + 1600 / m_mask.rect().height()); + setMask(m_mask); +} + +void AddAppletVisualFeedback::displayInternal() +{ + // determine text rectangle + QRect textRect(0, 0, 0, 0); + + if (m_frames < 1) + { + textRect.setWidth(m_richText->widthUsed()); + textRect.setHeight(m_richText->height()); + textRect.moveBy(-textRect.left(), -textRect.top()); + textRect.addCoords(0, 0, 2, 2); + } + + int margin = KDialog::marginHint(); + int height = QMAX(m_icon.height(), textRect.height()) + 2 * margin; + int textX = m_icon.isNull() ? margin : 2 + m_icon.width() + 2 * margin; + int width = textX; + + if (m_frames < 1) + { + width += textRect.width() + margin; + } + + // resize pixmap, mask and widget + m_mask.resize(width, height); + m_pixmap.resize(width, height); + resize(width, height); + + if (m_frames < 1) + { + move(KickerLib::popupPosition(m_direction, this, m_target)); + } + + // create and set transparency mask + makeMask(); + + // draw background + QPainter bufferPainter(&m_pixmap); + bufferPainter.setPen(Qt::black); + bufferPainter.setBrush(colorGroup().background()); + bufferPainter.drawRoundRect(0, 0, width, height, + 1600 / width, 1600 / height); + + // draw icon if present + if (!m_icon.isNull()) + { + bufferPainter.drawPixmap(margin, + margin, + m_icon, 0, 0, + m_icon.width(), m_icon.height()); + } + + if (m_frames < 1) + { + int textY = (height - textRect.height()) / 2; + + // draw text shadow + QColorGroup cg = colorGroup(); + cg.setColor(QColorGroup::Text, cg.background().dark(115)); + int shadowOffset = QApplication::reverseLayout() ? -1 : 1; + m_richText->draw(&bufferPainter, 5 + textX + shadowOffset, + textY + 1, QRect(), cg); + + // draw text + cg = colorGroup(); + m_richText->draw(&bufferPainter, 5 + textX, textY, rect(), cg); + } +} + +void AddAppletVisualFeedback::swoopCloser() +{ + if (m_destination.isNull() || m_frames == 0) + { + return; + } + + QPoint loc = geometry().topLeft(); + bool isLeft = m_destination.x() > loc.x(); + if (loc.x() != m_destination.x()) + { + int newX = loc.x() + ((m_destination.x() - loc.x()) / m_frames * 2); + if ((m_destination.x() > newX) != isLeft) + { + newX = m_destination.x(); + } + loc.setX(newX); + } + + if (loc.y() != m_destination.y()) + { + loc.setY(loc.y() + ((m_destination.y() - loc.y()) / m_frames)); + } + + move(loc); + --m_frames; + + if (m_frames < 1) + { + m_moveTimer.stop(); + displayInternal(); + QTimer::singleShot(2000, this, SLOT(deleteLater())); + } +} + +void AddAppletVisualFeedback::internalUpdate() +{ + m_dirty = true; + repaint(false); +} + +#include "addappletvisualfeedback.moc" diff --git a/kicker/kicker/ui/addappletvisualfeedback.h b/kicker/kicker/ui/addappletvisualfeedback.h new file mode 100644 index 000000000..084154704 --- /dev/null +++ b/kicker/kicker/ui/addappletvisualfeedback.h @@ -0,0 +1,80 @@ +/***************************************************************** + +Copyright (c) 2004-2005 Aaron J. Seigo <aseigo@kde.org> +Copyright (c) 2004 Zack Rusin <zrusin@kde.org> + Sami Kyostil <skyostil@kempele.fi> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef ADDAPPLETVISUALFEEDBACK_H +#define ADDAPPLETVISUALFEEDBACK_H + +#include <qbitmap.h> +#include <qpixmap.h> +#include <qtimer.h> +#include <qwidget.h> + +#include <kpanelapplet.h> + +class AppletItem; +class QPaintEvent; +class QSimpleRichText; +class QTimer; + +class AddAppletVisualFeedback : QWidget +{ + Q_OBJECT + + public: + AddAppletVisualFeedback(AppletWidget* parent, + const QWidget* destination, + KPanelApplet::Direction direction); + ~AddAppletVisualFeedback(); + + protected slots: + void internalUpdate(); + void swoopCloser(); + + protected: + void paintEvent(QPaintEvent * e); + void mousePressEvent(QMouseEvent * e); + + void makeMask(); + void displayInternal(); + + private: + const QWidget* m_target; + KPanelApplet::Direction m_direction; + QBitmap m_mask; + QPixmap m_pixmap; + QPixmap m_icon; + QSimpleRichText* m_richText; + + int m_dissolveSize; + int m_dissolveDelta; + int m_frames; + + QTimer m_moveTimer; + bool m_dirty; + + QPoint m_destination; +}; + +#endif diff --git a/kicker/kicker/ui/addbutton_mnu.cpp b/kicker/kicker/ui/addbutton_mnu.cpp new file mode 100644 index 000000000..65a60eea4 --- /dev/null +++ b/kicker/kicker/ui/addbutton_mnu.cpp @@ -0,0 +1,73 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qdragobject.h> + +#include <ksycocaentry.h> +#include <kservice.h> +#include <kservicegroup.h> +#include <kstandarddirs.h> +#include <kdebug.h> + +#include "addbutton_mnu.h" +#include "addbutton_mnu.moc" +#include "containerarea.h" + +PanelAddButtonMenu::PanelAddButtonMenu(ContainerArea* cArea, const QString & label, + const QString & relPath, QWidget * parent, const char * name, const QString& _inlineHeader) + : PanelServiceMenu(label, relPath, parent, name, true, _inlineHeader), containerArea(cArea) +{ +} + +PanelAddButtonMenu::PanelAddButtonMenu(ContainerArea* cArea, QWidget * parent, const char * name, const QString& _inlineHeader) + : PanelServiceMenu(QString::null, QString::null, parent, name, true, _inlineHeader), containerArea(cArea) +{ +} + +void PanelAddButtonMenu::slotExec(int id) +{ + if (!entryMap_.contains(id)) + return; + + KSycocaEntry * e = entryMap_[id]; + + if (e->isType(KST_KServiceGroup)) { + KServiceGroup::Ptr g = static_cast<KServiceGroup *>(e); + containerArea->addServiceMenuButton(g->relPath()); + } else if (e->isType(KST_KService)) { + KService::Ptr service = static_cast<KService *>(e); + containerArea->addServiceButton( service->desktopEntryPath() ); + } +} + +PanelServiceMenu * PanelAddButtonMenu::newSubMenu(const QString & label, const QString & relPath, + QWidget * parent, const char * name, const QString& _inlineHeader) +{ + return new PanelAddButtonMenu(containerArea, label, relPath, parent, name, _inlineHeader); +} + +void PanelAddButtonMenu::addNonKDEApp() +{ + containerArea->addNonKDEAppButton(); +} + diff --git a/kicker/kicker/ui/addbutton_mnu.h b/kicker/kicker/ui/addbutton_mnu.h new file mode 100644 index 000000000..8a9a7e348 --- /dev/null +++ b/kicker/kicker/ui/addbutton_mnu.h @@ -0,0 +1,51 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __addbutton_mnu_h__ +#define __addbutton_mnu_h__ + +#include "service_mnu.h" + +class ContainerArea; + +class PanelAddButtonMenu : public PanelServiceMenu +{ + Q_OBJECT + +public: + PanelAddButtonMenu(ContainerArea* cArea, const QString & label, const QString & relPath, + QWidget * parent = 0, const char * name = 0,const QString& _inlineHeader= QString::null); + PanelAddButtonMenu(ContainerArea* cArea, QWidget * parent = 0, const char * name = 0, const QString& _inlineHeader= QString::null); + +protected slots: + virtual void slotExec(int id); + virtual void addNonKDEApp(); + +protected: + virtual PanelServiceMenu * newSubMenu(const QString & label, const QString & relPath, + QWidget * parent, const char * name, const QString & _inlineHeader=QString::null); +private: + ContainerArea *containerArea; +}; + +#endif diff --git a/kicker/kicker/ui/addextension_mnu.cpp b/kicker/kicker/ui/addextension_mnu.cpp new file mode 100644 index 000000000..4ca467f46 --- /dev/null +++ b/kicker/kicker/ui/addextension_mnu.cpp @@ -0,0 +1,58 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "extensionmanager.h" +#include "pluginmanager.h" + +#include "addextension_mnu.h" +#include "addextension_mnu.moc" + +PanelAddExtensionMenu::PanelAddExtensionMenu(QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + setCheckable(true); + connect(this, SIGNAL(activated(int)), SLOT(slotExec(int))); + connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); +} + +void PanelAddExtensionMenu::slotAboutToShow() +{ + clear(); + + extensions = PluginManager::extensions(); + + AppletInfo::List::const_iterator it = extensions.constBegin(); + for( int i = 0; it != extensions.constEnd(); ++it, ++i ) { + const AppletInfo& ai = (*it); + insertItem( ai.name().replace( "&", "&&" ), i ); + if ( ai.isUniqueApplet() && PluginManager::the()->hasInstance(ai) ) { + setItemEnabled( i, false ); + setItemChecked( i, true ); + } + } +} + +void PanelAddExtensionMenu::slotExec(int id) +{ + ExtensionManager::the()->addExtension( extensions[id].desktopFile() ); +} diff --git a/kicker/kicker/ui/addextension_mnu.h b/kicker/kicker/ui/addextension_mnu.h new file mode 100644 index 000000000..60db0c201 --- /dev/null +++ b/kicker/kicker/ui/addextension_mnu.h @@ -0,0 +1,47 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __addextension_mnu_h__ +#define __addextension_mnu_h__ + +#include <qvaluelist.h> +#include <qpopupmenu.h> + +#include "appletinfo.h" + +class PanelAddExtensionMenu : public QPopupMenu +{ + Q_OBJECT + +public: + PanelAddExtensionMenu(QWidget *parent=0, const char *name=0); + +protected slots: + virtual void slotExec(int id); + virtual void slotAboutToShow(); + +private: + AppletInfo::List extensions; +}; + +#endif diff --git a/kicker/kicker/ui/appletitem.ui b/kicker/kicker/ui/appletitem.ui new file mode 100644 index 000000000..d9cc2d9b0 --- /dev/null +++ b/kicker/kicker/ui/appletitem.ui @@ -0,0 +1,129 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AppletItem</class> +<widget class="QWidget"> + <property name="name"> + <cstring>AppletItem</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>506</width> + <height>80</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>80</height> + </size> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>itemTitle</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="textFormat"> + <enum>RichText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>itemDescription</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="textFormat"> + <enum>RichText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>itemPixmap</cstring> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kicker/kicker/ui/appletop_mnu.cpp b/kicker/kicker/ui/appletop_mnu.cpp new file mode 100644 index 000000000..435911bbe --- /dev/null +++ b/kicker/kicker/ui/appletop_mnu.cpp @@ -0,0 +1,208 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kiconloader.h> +#include <kpanelapplet.h> +#include <kstdguiitem.h> + +#include "kicker.h" +#include "appletop_mnu.h" +#include "container_button.h" +#include "containerarea.h" + +PanelAppletOpMenu::PanelAppletOpMenu(int actions, QPopupMenu *opMenu, const QPopupMenu* appletsMenu, + const QString & title, const QString &icon, + QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + bool needSeparator = false; + bool isButton = (parent && parent->inherits("ButtonContainer")); + bool isMenu = false; + QString titleText = title; + titleText = titleText.replace('&', "&&"); + if (isButton) + { + isMenu = static_cast<ButtonContainer*>(parent)->isAMenu(); + } + + if (!Kicker::the()->isImmutable()) + { + QString text = isButton ? (isMenu ? i18n("&Move %1 Menu") : + i18n("&Move %1 Button")) : + i18n("&Move %1"); + insertItem(SmallIcon("move"), text.arg(titleText), Move); + + // we look for a container area to see if we can add containers + // this is part of the kiosk support in kicker, allowing + // one to block users from adding new containers + ContainerArea* area = 0; + QObject* findTheArea = parent ? parent->parent() : 0; + while (findTheArea) + { + area = dynamic_cast<ContainerArea*>(findTheArea); + + if (area) + { + break; + } + + findTheArea = findTheArea->parent(); + } + + if (!area || area->canAddContainers()) + { + text = isButton ? (isMenu ? i18n("&Remove %1 Menu") : + i18n("&Remove %1 Button")) : + i18n("&Remove %1"); + insertItem(SmallIcon("remove"), text.arg(titleText), Remove); + needSeparator = true; + } + } + + if (actions & KPanelApplet::ReportBug) + { + if (needSeparator) + { + insertSeparator(); + needSeparator = false; + } + + insertItem(i18n("Report &Bug..."), ReportBug); + } + + if (actions & KPanelApplet::About) + { + if (needSeparator) + { + insertSeparator(); + } + + QPixmap iconPix(kapp->iconLoader()->loadIcon(icon, + KIcon::Small, 0, + KIcon::DefaultState, + 0, true)); + insertItem(iconPix, i18n("&About %1").arg( titleText ), About); + needSeparator = !(actions & KPanelApplet::Help); + } + + if (actions & KPanelApplet::Help) + { + if (needSeparator) + { + insertSeparator(); + } + + insertItem(SmallIcon("help"), KStdGuiItem::help().text(), Help); + needSeparator = true; + } + + if (!Kicker::the()->isImmutable() && (actions & KPanelApplet::Preferences)) + { + if (isButton) + { + insertItem(SmallIcon("configure"), + i18n("&Configure %1 Button...").arg(titleText), Preferences); + } + else + { + insertItem(SmallIcon("configure"), + i18n("&Configure %1...").arg(titleText), Preferences); + } + needSeparator = true; + } + + if (appletsMenu) + { + if (needSeparator) + { + insertSeparator(); + needSeparator = false; + } + + QString text = title.isEmpty() ? i18n("Applet Menu") : + i18n("%1 Menu").arg(titleText); + + // the 2 const_cast's below prevents const_cast'ing in multiple places + // elsewhere in the kicker code base. it's ugly, but unavoidable + // unless either QPopupMenu one day allows inserting const + // QPopupMenu's or we uglify other bits of kicker's API, + // notably KPanelApplet::customMeu() + if (icon.isEmpty()) + { + insertItem(text, const_cast<QPopupMenu*>(appletsMenu)); + } + else + { + insertItem(SmallIcon(icon), text, + const_cast<QPopupMenu*>(appletsMenu)); + } + } + + if ((actions & PanelAppletOpMenu::KMenuEditor) && kapp->authorizeKAction("menuedit")) + { + if (needSeparator) + { + insertSeparator(); + needSeparator = false; + } + + insertItem(SmallIcon("kmenuedit"), i18n("&Menu Editor"), Preferences); + } + + if ((actions & PanelAppletOpMenu::BookmarkEditor) && + kapp->authorizeKAction("edit_bookmarks")) + { + if (needSeparator) + { + insertSeparator(); + } + needSeparator = false; + + // NOTE: keditbookmarks is from konqueror. seeing as this is in kdebase + // as well this should be ok? + insertItem(SmallIcon("keditbookmarks"), + i18n("&Edit Bookmarks"), + Preferences); + } + + if (needSeparator) + { + insertSeparator(); + } + + insertItem(SmallIcon("panel"), i18n("Panel Menu"), opMenu); + adjustSize(); +} + +void PanelAppletOpMenu::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Escape) + { + emit escapePressed(); + } + + QPopupMenu::keyPressEvent(e); +} + +#include "appletop_mnu.moc" diff --git a/kicker/kicker/ui/appletop_mnu.h b/kicker/kicker/ui/appletop_mnu.h new file mode 100644 index 000000000..25f03ada6 --- /dev/null +++ b/kicker/kicker/ui/appletop_mnu.h @@ -0,0 +1,55 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef PANEL_APPLET_OP_MENU_H +#define PANEL_APPLET_OP_MENU_H + +#include <qpopupmenu.h> + +class AppletInfo; + +// The button operations menu (usually right click) +class PanelAppletOpMenu : public QPopupMenu +{ +Q_OBJECT + +public: + enum OpButton{Move = 9900, Remove = 9901, Help = 9902, About = 9903, Preferences = 9904, ReportBug = 9905 }; + + // Note: these entries have to be | and &-able with KPanelApplet::Actions! + // they also are treated just like KPanelApplet::Preferences on selection + // KDE4: look at merging them there? perhaps under a generic "Editor" option? + enum { KMenuEditor = 1048576, BookmarkEditor = 2097152 }; + PanelAppletOpMenu(int actions, QPopupMenu *opMenu, const QPopupMenu* appletsMenu = 0, + const QString &title = 0, const QString &icon = 0, + QWidget *parent=0, const char *name=0); + +signals: + void escapePressed(); + +protected: + void keyPressEvent(QKeyEvent* e); +}; + + +#endif // PANEL_APPLET_OP_MENU_H diff --git a/kicker/kicker/ui/appletview.ui b/kicker/kicker/ui/appletview.ui new file mode 100644 index 000000000..a2fa1e91b --- /dev/null +++ b/kicker/kicker/ui/appletview.ui @@ -0,0 +1,204 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AppletView</class> +<widget class="QWidget"> + <property name="name"> + <cstring>AppletView</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>490</width> + <height>334</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>&Search:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>appletSearch</cstring> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>appletSearch</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>10</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="whatsThis" stdset="0"> + <string><qt>Type here some text to filter on the applet names and comments</qt></string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>S&how:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>appletFilter</cstring> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>All</string> + </property> + </item> + <item> + <property name="text"> + <string>Applets</string> + </property> + </item> + <item> + <property name="text"> + <string>Special Buttons</string> + </property> + </item> + <property name="name"> + <cstring>appletFilter</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="whatsThis" stdset="0"> + <string><qt>Select here the only applet category that you want to show</qt></string> + </property> + </widget> + </hbox> + </widget> + <widget class="QScrollView"> + <property name="name"> + <cstring>appletScrollView</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string><qt>This is the applet list. Select an applet and click on <b>Add to panel</b> to add it</qt></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>284</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>appletInstall</cstring> + </property> + <property name="text"> + <string>&Add to Panel</string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>closeButton</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>QScrollView</class> + <header location="global">qscrollview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="872">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032f49444154789cb5953148254718c77f1e5b7c030ab3e0c12e5ce00927f88a14af7d87c5590ac29d6013b0497b844008a9120e1248938354a6b1482131cde5a510b4f03081f07c8d4421c2063cd85708bbe0831938613ec8c0a5588dd1dc33452e5f33bb33c36f7ffbed7fd889fe7e9fcb7ad07df09ab750fdfdfec4c425787b6bfb757bae8df79e6a54e1bcc36008845b47e71dc549c1e06000f10a9e5c9a3effee39690ef92cb4a25e2c3b4804709844807035cfd57d7122f0ad65f0c25f0703d4a39af41d28473fa0af4a42548c81f007f85aa86a4510cc34cccc8288420405640ad2bbcadfeb2fb01b39021e7d5513a2c74c59ca43d8db510e0f6a24018d8a2496ecbeb0b892d29d0f08cdbc9d149ac7dc0057bea2831262853196fd5d6573dd43046b85fcbe2002d55019be54bef9a2a45ecd585e059106fe46639318403153427908bd0be8e2a38c874b90e70692806acade4ea0b7eee96d0cc9b2360b8f0d92e835e33b97172106400801b6b73c1a95c54719cbef439a2b9a54f833c3f68f8ec59594f73eb090089b1b153afa67e4ae1b270e5fa7144725d636a6228d853fcf59fbca511e7bdc193cf92467b0eb297f578a2220721d7ccdd82442553b48206f417a1714c5fb94b5cf2b8a638f58a13b9fc2a4a3ddb16854aa53d03806dcf4180481a8d8c98b8f7296b3f6a5a33c6ee2652785fc1ea4d2bcaf248246901bca377a0c661a482cc5505135ecbd088de9a490ddb30c8735cf9e5614872955a96854665a066e4f85a33d0bad96500f95bd9dc0f26a8a3b53ba0f53f20c9e3d85e1cb9a4f3facd0734f9659da1da8ea5b7a0c02a22cae081a95deba676fc7f1e4a39cce7ca0d5097cfc594e9659fca88608dd25cbccdcbfe6384014baf3509f66f436866c7e0d835d4ffb5d0b0954a5c38fb4e92d4af18b521c19ac8c39796ee42ecebe22c0f2aa90656d7adf5714c74a71346c7647b0d39685c7965f7f52aa738fc6947a34c6b83829284a41d2c6441258580a74e7738a22509d36d0bc65687760660e8a25033187c451fec69bc1838301ac0b69de444ad53779c32317bb2481f2d437b9dd6adae13d14874a558f3126c2e0e7cbc59be3b81abf7e67ecca7fac3bd0fca3fe17f0db86f7f7fb137f0208c29bb28f971c5b0000000049454e44ae426082</data> + </image> +</images> +<tabstops> + <tabstop>appletSearch</tabstop> + <tabstop>appletFilter</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>qscrollview.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kicker/kicker/ui/appletwidget.h b/kicker/kicker/ui/appletwidget.h new file mode 100644 index 000000000..77d05c2b3 --- /dev/null +++ b/kicker/kicker/ui/appletwidget.h @@ -0,0 +1,72 @@ +/***************************************************************** + +Copyright (c) 2005 Marc Cramdal +Copyright (c) 2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _appletwidget_h_ +#define _appletwidget_h_ + +#include <qpoint.h> +#include <qvaluelist.h> + +#include <klocale.h> +#include <kdialogbase.h> + +#include "appletinfo.h" +#include "appletitem.h" + +class AppletWidget: public AppletItem +{ + Q_OBJECT + + public: + typedef QValueList<AppletWidget*> List; + + AppletWidget(const AppletInfo& info, bool odd, QWidget *parent); + const AppletInfo& info() const { return m_appletInfo; } + virtual bool eventFilter(QObject* watched, QEvent* e); + + void setSelected(bool selected); + void setOdd(bool odd); + bool odd() { return m_odd; } + + signals: + void clicked(AppletWidget*); + void doubleClicked(AppletWidget*); + + protected: + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent* e); + + private: + AppletInfo m_appletInfo; + bool m_odd; + bool m_selected; + QPoint m_dragStart; +}; + +#endif + diff --git a/kicker/kicker/ui/browser_dlg.cpp b/kicker/kicker/ui/browser_dlg.cpp new file mode 100644 index 000000000..1fd5d47f6 --- /dev/null +++ b/kicker/kicker/ui/browser_dlg.cpp @@ -0,0 +1,114 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlabel.h> +#include <qlayout.h> +#include <qvbox.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kicondialog.h> +#include <kfiledialog.h> +#include <klineedit.h> +#include <kmessagebox.h> + +#include "browser_dlg.h" +#include "browser_dlg.moc" + +PanelBrowserDialog::PanelBrowserDialog( const QString& path, const QString &icon, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Quick Browser Configuration" ), Ok|Cancel, Ok, true ) +{ + setMinimumWidth( 300 ); + + QVBox *page = makeVBoxMainWidget(); + + QHBox *hbox2 = new QHBox( page ); + hbox2->setSpacing( KDialog::spacingHint() ); + QLabel *label1 = new QLabel( i18n( "Button icon:" ), hbox2 ); + + iconBtn = new KIconButton( hbox2 ); + iconBtn->setFixedSize( 50, 50 ); + iconBtn->setIconType( KIcon::Panel, KIcon::FileSystem ); + label1->setBuddy( iconBtn ); + + QHBox *hbox1 = new QHBox( page ); + hbox1->setSpacing( KDialog::spacingHint() ); + QLabel *label2 = new QLabel( i18n ( "Path:" ), hbox1 ); + pathInput = new KLineEdit( hbox1 ); + connect( pathInput, SIGNAL( textChanged ( const QString & )), this, SLOT( slotPathChanged( const QString & ))); + + pathInput->setText( path ); + pathInput->setFocus(); + label2->setBuddy( pathInput ); + browseBtn = new QPushButton( i18n( "&Browse..." ), hbox1 ); + if ( icon.isEmpty() ) { + KURL u; + u.setPath( path ); + iconBtn->setIcon( KMimeType::iconForURL( u ) ); + } + else + iconBtn->setIcon( icon ); + + connect( browseBtn, SIGNAL( clicked() ), this, SLOT( browse() ) ); +} + +PanelBrowserDialog::~PanelBrowserDialog() +{ + +} + +void PanelBrowserDialog::slotPathChanged( const QString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +void PanelBrowserDialog::browse() +{ + QString dir = KFileDialog::getExistingDirectory( pathInput->text(), 0, i18n( "Select Folder" ) ); + if ( !dir.isEmpty() ) { + pathInput->setText( dir ); + KURL u; + u.setPath( dir ); + iconBtn->setIcon( KMimeType::iconForURL( u ) ); + } +} + +void PanelBrowserDialog::slotOk() +{ + QDir dir(path()); + if( !dir.exists() ) { + KMessageBox::sorry( this, i18n("'%1' is not a valid folder.").arg(path()) ); + return; + } + KDialogBase::slotOk(); +} + +const QString PanelBrowserDialog::icon() +{ + return iconBtn->icon(); +} + +QString PanelBrowserDialog::path() +{ + return pathInput->text(); +} diff --git a/kicker/kicker/ui/browser_dlg.h b/kicker/kicker/ui/browser_dlg.h new file mode 100644 index 000000000..dc675c11c --- /dev/null +++ b/kicker/kicker/ui/browser_dlg.h @@ -0,0 +1,53 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __browser_dlg_h__ +#define __browser_dlg_h__ + +#include <kdialogbase.h> + +class KIconButton; +class KLineEdit; + +class PanelBrowserDialog : public KDialogBase +{ + Q_OBJECT + +public: + PanelBrowserDialog( const QString &path = QString::null, const QString &icon = QString::null, QWidget *parent = 0, const char *name = 0 ); + ~PanelBrowserDialog(); + + const QString icon(); + QString path(); + +protected slots: + void browse(); + virtual void slotOk(); + void slotPathChanged( const QString &_text ); +protected: + KIconButton *iconBtn; + KLineEdit *pathInput; + QPushButton *browseBtn; +}; + +#endif diff --git a/kicker/kicker/ui/browser_mnu.cpp b/kicker/kicker/ui/browser_mnu.cpp new file mode 100644 index 000000000..9561881eb --- /dev/null +++ b/kicker/kicker/ui/browser_mnu.cpp @@ -0,0 +1,552 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qdir.h> +#include <qpixmap.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kdirwatch.h> +#include <kfileitem.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <kio/global.h> +#include <klocale.h> +#include <kmimetype.h> +#include <konq_operations.h> +#include <kprocess.h> +#include <krun.h> +#include <ksimpleconfig.h> +#include <kstringhandler.h> +#include <kurldrag.h> + +#include "kickerSettings.h" + +#include "browser_mnu.h" +#include "browser_mnu.moc" + +#define CICON(a) (*_icons)[a] + +QMap<QString, QPixmap> *PanelBrowserMenu::_icons = 0; + +PanelBrowserMenu::PanelBrowserMenu(QString path, QWidget *parent, const char *name, int startid) + : KPanelMenu(path, parent, name) + , _mimecheckTimer(0) + , _startid(startid) + , _dirty(false) + , _filesOnly(false) +{ + _lastpress = QPoint(-1, -1); + setAcceptDrops(true); // Should depend on permissions of path. + + // we are not interested for dirty events on files inside the + // directory (see slotClearIfNeeded) + connect( &_dirWatch, SIGNAL(dirty(const QString&)), + this, SLOT(slotClearIfNeeded(const QString&)) ); + connect( &_dirWatch, SIGNAL(created(const QString&)), + this, SLOT(slotClear()) ); + connect( &_dirWatch, SIGNAL(deleted(const QString&)), + this, SLOT(slotClear()) ); + + kdDebug() << "PanelBrowserMenu Constructor " << path << endl; +} + +PanelBrowserMenu::~PanelBrowserMenu() +{ + kdDebug() << "PanelBrowserMenu Destructor " << path() << endl; +} + +void PanelBrowserMenu::slotClearIfNeeded(const QString& p) +{ + if (p == path()) + slotClear(); +} + +void PanelBrowserMenu::initialize() +{ + _lastpress = QPoint(-1, -1); + + // don't change menu if already visible + if (isVisible()) + return; + + if (_dirty) { + // directory content changed while menu was visible + slotClear(); + setInitialized(false); + _dirty = false; + } + + if (initialized()) return; + setInitialized(true); + + // start watching if not already done + if (!_dirWatch.contains(path())) + _dirWatch.addDir( path() ); + + // setup icon map + initIconMap(); + + // clear maps + _filemap.clear(); + _mimemap.clear(); + + int filter = QDir::Dirs | QDir::Files; + if (KickerSettings::showHiddenFiles()) + { + filter |= QDir::Hidden; + } + + QDir dir(path(), QString::null, QDir::DirsFirst | QDir::Name | QDir::IgnoreCase, filter); + + // does the directory exist? + if (!dir.exists()) { + insertItem(i18n("Failed to Read Folder")); + return; + } + + // get entry list + const QFileInfoList *list = dir.entryInfoList(); + + // no list -> read error + if (!list) { + insertItem(i18n("Failed to Read Folder")); + return; + } + + KURL url; + url.setPath(path()); + if (!kapp->authorizeURLAction("list", KURL(), url)) + { + insertItem(i18n("Not Authorized to Read Folder")); + return; + } + + // insert file manager and terminal entries + // only the first part menu got them + if(_startid == 0 && !_filesOnly) { + insertTitle(path()); + insertItem(CICON("kfm"), i18n("Open in File Manager"), this, SLOT(slotOpenFileManager())); + if (kapp->authorize("shell_access")) + insertItem(CICON("terminal"), i18n("Open in Terminal"), this, SLOT(slotOpenTerminal())); + } + + + bool first_entry = true; + bool dirfile_separator = false; + unsigned int item_count = 0; + int run_id = _startid; + + // get list iterator + QFileInfoListIterator it(*list); + + // jump to startid + it += _startid; + + // iterate over entry list + for (; it.current(); ++it) + { + // bump id + run_id++; + + QFileInfo *fi = it.current(); + // handle directories + if (fi->isDir()) + { + QString name = fi->fileName(); + + // ignore . and .. entries + if (name == "." || name == "..") continue; + + QPixmap icon; + QString path = fi->absFilePath(); + + // parse .directory if it does exist + if (QFile::exists(path + "/.directory")) { + + KSimpleConfig c(path + "/.directory", true); + c.setDesktopGroup(); + QString iconPath = c.readEntry("Icon"); + + if ( iconPath.startsWith("./") ) + iconPath = path + '/' + iconPath.mid(2); + + icon = KGlobal::iconLoader()->loadIcon(iconPath, + KIcon::Small, KIcon::SizeSmall, + KIcon::DefaultState, 0, true); + if(icon.isNull()) + icon = CICON("folder"); + name = c.readEntry("Name", name); + } + + // use cached folder icon for directories without special icon + if (icon.isNull()) + icon = CICON("folder"); + + // insert separator if we are the first menu entry + if(first_entry) { + if (_startid == 0 && !_filesOnly) + insertSeparator(); + first_entry = false; + } + + // append menu entry + PanelBrowserMenu *submenu = new PanelBrowserMenu(path, this); + submenu->_filesOnly = _filesOnly; + append(icon, name, submenu); + + // bump item count + item_count++; + + dirfile_separator = true; + } + // handle files + else if(fi->isFile()) + { + QString name = fi->fileName(); + QString title = KIO::decodeFileName(name); + + QPixmap icon; + QString path = fi->absFilePath(); + + bool mimecheck = false; + + // .desktop files + if(KDesktopFile::isDesktopFile(path)) + { + KSimpleConfig c(path, true); + c.setDesktopGroup(); + title = c.readEntry("Name", title); + + QString s = c.readEntry("Icon"); + if(!_icons->contains(s)) { + icon = KGlobal::iconLoader()->loadIcon(s, KIcon::Small, KIcon::SizeSmall, + KIcon::DefaultState, 0, true); + + if(icon.isNull()) { + QString type = c.readEntry("Type", "Application"); + if (type == "Directory") + icon = CICON("folder"); + else if (type == "Mimetype") + icon = CICON("txt"); + else if (type == "FSDevice") + icon = CICON("chardevice"); + else + icon = CICON("exec"); + } + else + _icons->insert(s, icon); + } + else + icon = CICON(s); + } + else { + // set unknown icon + icon = CICON("unknown"); + + // mark for delayed mimetime check + mimecheck = true; + } + + // insert separator if we are the first menu entry + if(first_entry) { + if(_startid == 0 && !_filesOnly) + insertSeparator(); + first_entry = false; + } + + // insert separator if we we first file after at least one directory + if (dirfile_separator) { + insertSeparator(); + dirfile_separator = false; + } + + // append file entry + append(icon, title, name, mimecheck); + + // bump item count + item_count++; + } + + if (item_count == KickerSettings::maxEntries2()) + { + // Only insert a "More" item if there are actually more items. + ++it; + if( it.current() ) { + insertSeparator(); + append(CICON("kdisknav"), i18n("More"), new PanelBrowserMenu(path(), this, 0, run_id)); + } + break; + } + } + +#if 0 + // WABA: tear off handles don't work together with dynamically updated + // menus. We can't update the menu while torn off, and we don't know + // when it is torn off. + if(KGlobalSettings::insertTearOffHandle() && item_count > 0) + insertTearOffHandle(); +#endif + + adjustSize(); + + QString dirname = path(); + + int maxlen = contentsRect().width() - 40; + if(item_count == 0) + maxlen = fontMetrics().width(dirname); + + if (fontMetrics().width(dirname) > maxlen) { + while ((!dirname.isEmpty()) && (fontMetrics().width(dirname) > (maxlen - fontMetrics().width("...")))) + dirname = dirname.remove(0, 1); + dirname.prepend("..."); + } + setCaption(dirname); + + // setup and start delayed mimetype check timer + if(_mimemap.count() > 0) { + + if(!_mimecheckTimer) + _mimecheckTimer = new QTimer(this); + + connect(_mimecheckTimer, SIGNAL(timeout()), SLOT(slotMimeCheck())); + _mimecheckTimer->start(0); + } +} + +void PanelBrowserMenu::append(const QPixmap &pixmap, const QString &title, const QString &file, bool mimecheck) +{ + // avoid &'s being converted to accelerators + QString newTitle = title; + newTitle = KStringHandler::cEmSqueeze( newTitle, fontMetrics(), 20 ); + newTitle.replace("&", "&&"); + + // insert menu item + int id = insertItem(pixmap, newTitle); + + // insert into file map + _filemap.insert(id, file); + + // insert into mimetype check map + if(mimecheck) + _mimemap.insert(id, true); +} + +void PanelBrowserMenu::append(const QPixmap &pixmap, const QString &title, PanelBrowserMenu *subMenu) +{ + // avoid &'s being converted to accelerators + QString newTitle = title; + newTitle = KStringHandler::cEmSqueeze( newTitle, fontMetrics(), 20 ); + newTitle.replace("&", "&&"); + + // insert submenu + insertItem(pixmap, newTitle, subMenu); + // remember submenu for later deletion + _subMenus.append(subMenu); +} + +void PanelBrowserMenu::mousePressEvent(QMouseEvent *e) +{ + QPopupMenu::mousePressEvent(e); + _lastpress = e->pos(); +} + +void PanelBrowserMenu::mouseMoveEvent(QMouseEvent *e) +{ + QPopupMenu::mouseMoveEvent(e); + + if (!(e->state() & LeftButton)) return; + if(_lastpress == QPoint(-1, -1)) return; + + // DND delay + if((_lastpress - e->pos()).manhattanLength() < 12) return; + + // get id + int id = idAt(_lastpress); + if(!_filemap.contains(id)) return; + + // reset _lastpress + _lastpress = QPoint(-1, -1); + + // start drag + KURL url; + url.setPath(path() + "/" + _filemap[id]); + KURL::List files(url); + KURLDrag *d = new KURLDrag(files, this); + connect(d, SIGNAL(destroyed()), this, SLOT(slotDragObjectDestroyed())); + d->setPixmap(iconSet(id)->pixmap()); + d->drag(); +} + +void PanelBrowserMenu::slotDragObjectDestroyed() +{ + if (KURLDrag::target() != this) + { + close(); + } +} + +void PanelBrowserMenu::dragEnterEvent( QDragEnterEvent *ev ) +{ + if (KURLDrag::canDecode(ev)) + { + ev->accept(); + } + KPanelMenu::dragEnterEvent(ev); +} + +void PanelBrowserMenu::dragMoveEvent(QDragMoveEvent *ev) +{ + QMouseEvent mev(QEvent::MouseMove, ev->pos(), Qt::NoButton, Qt::LeftButton); + QPopupMenu::mouseMoveEvent(&mev); +} + +void PanelBrowserMenu::dropEvent( QDropEvent *ev ) +{ + KURL u( path() ); + KFileItem item( u, QString::fromLatin1( "inode/directory" ), KFileItem::Unknown ); + KonqOperations::doDrop( &item, u, ev, this ); + KPanelMenu::dropEvent(ev); + // ### TODO: Update list +} + +void PanelBrowserMenu::slotExec(int id) +{ + kapp->propagateSessionManager(); + + if(!_filemap.contains(id)) return; + + KURL url; + url.setPath(path() + "/" + _filemap[id]); + new KRun(url, 0, true); // will delete itself + _lastpress = QPoint(-1, -1); +} + +void PanelBrowserMenu::slotOpenTerminal() +{ + KConfig * config = kapp->config(); + config->setGroup("General"); + QString term = config->readPathEntry("TerminalApplication", "konsole"); + + KProcess proc; + proc << term; + if (term == "konsole") + proc << "--workdir" << path(); + else + proc.setWorkingDirectory(path()); + proc.start(KProcess::DontCare); +} + +void PanelBrowserMenu::slotOpenFileManager() +{ + new KRun(path()); +} + +void PanelBrowserMenu::slotMimeCheck() +{ + // get the first map entry + QMap<int, bool>::Iterator it = _mimemap.begin(); + + // no mime types left to check -> stop timer + if(it == _mimemap.end()) { + _mimecheckTimer->stop(); + delete _mimecheckTimer; + _mimecheckTimer = 0; + return; + } + + int id = it.key(); + QString file = _filemap[id]; + + _mimemap.remove(it); + + KURL url; + url.setPath( path() + '/' + file ); + +// KMimeType::Ptr mt = KMimeType::findByURL(url, 0, true, false); +// QString icon(mt->icon(url, true)); + QString icon = KMimeType::iconForURL( url ); +// kdDebug() << url.url() << ": " << icon << endl; + + file = KStringHandler::cEmSqueeze( file, fontMetrics(), 20 ); + file.replace("&", "&&"); + + if(!_icons->contains(icon)) { + QPixmap pm = SmallIcon(icon); + if( pm.height() > 16 ) + { + QPixmap cropped( 16, 16 ); + copyBlt( &cropped, 0, 0, &pm, 0, 0, 16, 16 ); + pm = cropped; + } + _icons->insert(icon, pm); + changeItem(id, pm, file); + } + else + changeItem(id, CICON(icon), file); +} + +void PanelBrowserMenu::slotClear() +{ + // no need to watch any further + if (_dirWatch.contains(path())) + _dirWatch.removeDir( path() ); + + // don't change menu if already visible + if (isVisible()) { + _dirty = true; + return; + } + KPanelMenu::slotClear(); + + for (QValueVector<PanelBrowserMenu*>::iterator it = _subMenus.begin(); + it != _subMenus.end(); + ++it) + { + delete *it; + } + _subMenus.clear(); // deletes submenus +} + +void PanelBrowserMenu::initIconMap() +{ + if(_icons) return; + +// kdDebug() << "PanelBrowserMenu::initIconMap" << endl; + + _icons = new QMap<QString, QPixmap>; + + _icons->insert("folder", SmallIcon("folder")); + _icons->insert("unknown", SmallIcon("mime_empty")); + _icons->insert("folder_open", SmallIcon("folder_open")); + _icons->insert("kdisknav", SmallIcon("kdisknav")); + _icons->insert("kfm", SmallIcon("kfm")); + _icons->insert("terminal", SmallIcon("terminal")); + _icons->insert("txt", SmallIcon("txt")); + _icons->insert("exec", SmallIcon("exec")); + _icons->insert("chardevice", SmallIcon("chardevice")); +} + +// vim: sw=4 et diff --git a/kicker/kicker/ui/browser_mnu.h b/kicker/kicker/ui/browser_mnu.h new file mode 100644 index 000000000..5999db2cb --- /dev/null +++ b/kicker/kicker/ui/browser_mnu.h @@ -0,0 +1,81 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __browser_mnu_h__ +#define __browser_mnu_h__ + +#include <qmap.h> +#include <qvaluevector.h> +#include <kpanelmenu.h> +#include <kdirwatch.h> + +class PanelBrowserMenu : public KPanelMenu +{ + Q_OBJECT + +public: + PanelBrowserMenu(QString path, QWidget *parent = 0, const char *name = 0, int startid = 0); + ~PanelBrowserMenu(); + + void append(const QPixmap &pixmap, const QString &title, const QString &filename, bool mimecheck); + void append(const QPixmap &pixmap, const QString &title, PanelBrowserMenu *subMenu); + +public slots: + void initialize(); + +protected slots: + void slotExec(int id); + void slotOpenTerminal(); + void slotOpenFileManager(); + void slotMimeCheck(); + void slotClearIfNeeded(const QString&); + void slotClear(); + void slotDragObjectDestroyed(); + +protected: + void mousePressEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + void dropEvent(QDropEvent *ev); + void dragEnterEvent(QDragEnterEvent *ev); + void dragMoveEvent(QDragMoveEvent *); + void initIconMap(); + + QPoint _lastpress; + QMap<int, QString> _filemap; + QMap<int, bool> _mimemap; + QTimer *_mimecheckTimer; + KDirWatch _dirWatch; + QValueVector<PanelBrowserMenu*> _subMenus; + + int _startid; + bool _dirty; + + // With this flag set to 'true' the menu only displays files and + // directories. i.e. the "Open in File Manager" and "Open in Terminal" + // entries are not inserted in the menu and its submenus. + bool _filesOnly; + + static QMap<QString, QPixmap> *_icons; +}; + +#endif diff --git a/kicker/kicker/ui/client_mnu.cpp b/kicker/kicker/ui/client_mnu.cpp new file mode 100644 index 000000000..f098e40d4 --- /dev/null +++ b/kicker/kicker/ui/client_mnu.cpp @@ -0,0 +1,139 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qpixmap.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <dcopclient.h> + +#include "client_mnu.h" +#include "client_mnu.moc" + +KickerClientMenu::KickerClientMenu( QWidget * parent, const char *name ) + : QPopupMenu( parent, name), DCOPObject( name ) +{ +} + +KickerClientMenu::~KickerClientMenu() +{ +} + +void KickerClientMenu::clear() +{ + QPopupMenu::clear(); +} + +void KickerClientMenu::insertItem( QPixmap icon, QString text, int id ) +{ + int globalid = QPopupMenu::insertItem( icon, text, this, SLOT( slotActivated(int) ) ); + setItemParameter( globalid, id ); +} + +void KickerClientMenu::insertItem( QString text, int id ) +{ + int globalid = QPopupMenu::insertItem( text, this, SLOT( slotActivated(int) ) ); + setItemParameter( globalid, id ); +} + +QCString KickerClientMenu::insertMenu( QPixmap icon, QString text, int id ) +{ + QString subname("%1-submenu%2"); + QCString subid = subname.arg(objId()).arg(id).local8Bit(); + KickerClientMenu *sub = new KickerClientMenu(this, subid); + int globalid = QPopupMenu::insertItem( icon, text, sub, id); + setItemParameter( globalid, id ); + + return subid; +} + +void KickerClientMenu::connectDCOPSignal( QCString signal, QCString appId, QCString objId ) +{ + // very primitive right now + if ( signal == "activated(int)" ) { + app = appId; + obj = objId; + } else { + kdWarning() << "DCOP: no such signal " << className() << "::" << signal.data() << endl; + } +} + +bool KickerClientMenu::process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &replyData) +{ + if ( fun == "clear()" ) { + clear(); + replyType = "void"; + return true; + } + else if ( fun == "insertItem(QPixmap,QString,int)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QPixmap icon; + QString text; + int id; + dataStream >> icon >> text >> id; + insertItem( icon, text, id ); + replyType = "void"; + return true; + } + else if ( fun == "insertMenu(QPixmap,QString,int)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QPixmap icon; + QString text; + int id; + dataStream >> icon >> text >> id; + QCString ref = insertMenu( icon, text, id ); + replyType = "QCString"; + QDataStream replyStream( replyData, IO_WriteOnly ); + replyStream << ref; + return true; + } + else if ( fun == "insertItem(QString,int)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QString text; + int id; + dataStream >> text >> id; + insertItem( text, id ); + replyType = "void"; + return true; + } + else if ( fun == "connectDCOPSignal(QCString,QCString,QCString)" ) { + QDataStream dataStream( data, IO_ReadOnly ); + QCString signal, appId, objId; + dataStream >> signal >> appId >> objId; + connectDCOPSignal( signal, appId, objId ); + replyType = "void"; + return true; + } + return false; +} + +void KickerClientMenu::slotActivated(int id) +{ + if ( !app.isEmpty() ) { + QByteArray data; + QDataStream dataStream( data, IO_WriteOnly ); + dataStream << id; + kapp->dcopClient()->send( app, obj, "activated(int)", data ); + } +} diff --git a/kicker/kicker/ui/client_mnu.h b/kicker/kicker/ui/client_mnu.h new file mode 100644 index 000000000..fe8e4a113 --- /dev/null +++ b/kicker/kicker/ui/client_mnu.h @@ -0,0 +1,81 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef PANEL_CLIENTMENU_H +#define PANEL_CLIENTMENU_H + +#include <qstringlist.h> +#include <qpopupmenu.h> + +#include <dcopobject.h> + + +class PanelKMenu; + +// Classes to handle client application menus. Used by PanelKButton, which +// also manages the toplevel K Button Menu. + +/** + * Small additions to QPopupMenu to contain data we need for DCop handling + */ +class KickerClientMenu : public QPopupMenu, DCOPObject +{ + Q_OBJECT +public: + KickerClientMenu( QWidget *parent=0, const char *name=0); + ~KickerClientMenu(); + + // dcop exported + void clear(); + void insertItem( QPixmap icon, QString text, int id ); + void insertItem( QString text, int id ); + + QCString insertMenu( QPixmap icon, QString test, int id ); + + // dcop signals: + // void activated(int) + + void connectDCOPSignal( QCString signal, QCString appId, QCString objId ); + + // dcop internal + virtual bool process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &reply); + +protected slots: + void slotActivated(int id); + +private: + QCString app, obj; // for the signal + + // for the panel menu, internal + friend class PanelKMenu; + QString text; + QPixmap icon; + + // for the KickerClientMenu, internal + friend class MenuManager; + int idInParentMenu; + QCString createdBy; +}; + +#endif diff --git a/kicker/kicker/ui/dirdrop_mnu.cpp b/kicker/kicker/ui/dirdrop_mnu.cpp new file mode 100644 index 000000000..2f64fdd12 --- /dev/null +++ b/kicker/kicker/ui/dirdrop_mnu.cpp @@ -0,0 +1,39 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kiconloader.h> + +#include "dirdrop_mnu.h" + +PanelDirDropMenu::PanelDirDropMenu(QWidget *parent, const char *name) + :QPopupMenu(parent, name) +{ + insertItem(SmallIconSet("folder"), i18n("Add as &File Manager URL"), Url); + setAccel(CTRL+Key_F, Url); + insertItem(SmallIconSet("kdisknav"), i18n("Add as Quick&Browser"), Browser); + setAccel(CTRL+Key_B, Browser); + adjustSize(); +} + + diff --git a/kicker/kicker/ui/dirdrop_mnu.h b/kicker/kicker/ui/dirdrop_mnu.h new file mode 100644 index 000000000..15fa799c2 --- /dev/null +++ b/kicker/kicker/ui/dirdrop_mnu.h @@ -0,0 +1,37 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __dirdrop_mnu_h__ +#define __dirdrop_mnu_h__ + +#include <qpopupmenu.h> + +// The directory dropped menu +class PanelDirDropMenu : public QPopupMenu +{ +public: + enum OpButton{Url=1, Browser}; + PanelDirDropMenu(QWidget *parent=0, const char *name=0); +}; + +#endif diff --git a/kicker/kicker/ui/exe_dlg.cpp b/kicker/kicker/ui/exe_dlg.cpp new file mode 100644 index 000000000..19583444e --- /dev/null +++ b/kicker/kicker/ui/exe_dlg.cpp @@ -0,0 +1,204 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qfileinfo.h> + +#include <klocale.h> +#include <kiconloader.h> + +#include <qcheckbox.h> +#include <qdir.h> +#include <qfileinfo.h> +#include <qlineedit.h> +#include <qvbox.h> + +#include <kicondialog.h> +#include <kmessagebox.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <kurlcompletion.h> +#include <kurlrequester.h> +#include <kurl.h> + +#include <kdebug.h> + +#include "exe_dlg.h" +#include "nonKDEButtonSettings.h" + +PanelExeDialog::PanelExeDialog(const QString& title, const QString& description, + const QString &path, const QString &icon, + const QString &cmd, bool inTerm, + QWidget *parent, const char *name) + : KDialogBase(parent, name, false, i18n("Non-KDE Application Configuration"), Ok|Cancel, Ok, true), + m_icon(icon.isEmpty() ? "exec" : icon), + m_iconChanged(false) +{ + setCaption(i18n("Non-KDE Application Configuration")); + QFileInfo fi(path); + + ui = new NonKDEButtonSettings(makeVBoxMainWidget()); + fillCompletion(); + + ui->m_title->setText(title); + ui->m_description->setText(description); + ui->m_exec->setURL(path); + ui->m_commandLine->setText(cmd); + ui->m_inTerm->setChecked(inTerm); + ui->m_icon->setIconType(KIcon::Panel, KIcon::Application); + + updateIcon(); + + connect(ui->m_exec, SIGNAL(urlSelected(const QString &)), + this, SLOT(slotSelect(const QString &))); + connect(ui->m_exec, SIGNAL(textChanged(const QString &)), + this, SLOT(slotTextChanged(const QString &))); + connect(ui->m_exec, SIGNAL(returnPressed()), + this, SLOT(slotReturnPressed())); + connect(ui->m_icon, SIGNAL(iconChanged(QString)), + this, SLOT(slotIconChanged(QString))); + + // leave decent space for the commandline + resize(sizeHint().width() > 300 ? sizeHint().width() : 300, + sizeHint().height()); +} + +void PanelExeDialog::slotOk() +{ + KDialogBase::slotOk(); + // WARNING! we get delete after this, so don't do anything after it! + emit updateSettings(this); +} + +bool PanelExeDialog::useTerminal() const +{ + return ui->m_inTerm->isChecked(); +} + +QString PanelExeDialog::title() const +{ + return ui->m_title->text(); +} + +QString PanelExeDialog::description() const +{ + return ui->m_description->text(); +} + +QString PanelExeDialog::commandLine() const +{ + return ui->m_commandLine->text(); +} + +QString PanelExeDialog::iconPath() const +{ + return ui->m_icon->icon(); +} + +QString PanelExeDialog::command() const +{ + return ui->m_exec->url(); +} + +void PanelExeDialog::updateIcon() +{ + if(!m_icon.isEmpty()) + ui->m_icon->setIcon(m_icon); +} + +void PanelExeDialog::fillCompletion() +{ + KCompletion *comp = ui->m_exec->completionObject(); + QStringList exePaths = KStandardDirs::systemPaths(); + + for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); it++) + { + QDir d( (*it) ); + d.setFilter( QDir::Files | QDir::Executable ); + + const QFileInfoList *list = d.entryInfoList(); + if (!list) + continue; + + QFileInfoListIterator it2( *list ); + QFileInfo *fi; + + while ( (fi = it2.current()) != 0 ) { + m_partialPath2full.insert(fi->fileName(), fi->filePath(), false); + comp->addItem(fi->fileName()); + comp->addItem(fi->filePath()); + ++it2; + } + } +} + +void PanelExeDialog::slotIconChanged(QString) +{ + m_iconChanged = true; +} + +void PanelExeDialog::slotTextChanged(const QString &str) +{ + if (m_iconChanged) + { + return; + } + + QString exeLocation = str; + QMap<QString, QString>::iterator it = m_partialPath2full.find(str); + + if (it != m_partialPath2full.end()) + exeLocation = it.data(); + KMimeType::pixmapForURL(KURL( exeLocation ), 0, KIcon::Panel, 0, KIcon::DefaultState, &m_icon); + updateIcon(); +} + +void PanelExeDialog::slotReturnPressed() +{ + if (m_partialPath2full.contains(ui->m_exec->url())) + ui->m_exec->setURL(m_partialPath2full[ui->m_exec->url()]); +} + +void PanelExeDialog::slotSelect(const QString& exec) +{ + if ( exec.isEmpty() ) + return; + + QFileInfo fi(exec); + if (!fi.isExecutable()) + { + if(KMessageBox::warningYesNo(0, i18n("The selected file is not executable.\n" + "Do you want to select another file?"), i18n("Not Executable"), i18n("Select Other"), KStdGuiItem::cancel()) + == KMessageBox::Yes) + { + ui->m_exec->button()->animateClick(); + } + + return; + } + + KMimeType::pixmapForURL(KURL( exec ), 0, KIcon::Panel, 0, KIcon::DefaultState, &m_icon); + updateIcon(); +} + +#include "exe_dlg.moc" + diff --git a/kicker/kicker/ui/exe_dlg.h b/kicker/kicker/ui/exe_dlg.h new file mode 100644 index 000000000..f7624fa35 --- /dev/null +++ b/kicker/kicker/ui/exe_dlg.h @@ -0,0 +1,65 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __exe_dlg_h__ +#define __exe_dlg_h__ + +#include <kdialogbase.h> +class NonKDEButtonSettings; + +class PanelExeDialog : public KDialogBase +{ + Q_OBJECT +public: + PanelExeDialog(const QString& title, const QString& description, + const QString &path, const QString &pixmap=QString::null, + const QString &cmd=QString::null, bool inTerm=false, + QWidget *parent=0, const char *name=0); + QString iconPath() const; + QString command() const; + QString commandLine() const; + QString title() const; + QString description() const; + bool useTerminal() const; + +signals: + void updateSettings(PanelExeDialog*); + +protected slots: + void slotSelect(const QString& exec); + void slotTextChanged(const QString &); + void slotReturnPressed(); + void slotIconChanged(QString); + void slotOk(); + +protected: + void fillCompletion(); + void updateIcon(); + + NonKDEButtonSettings* ui; + QString m_icon; + QMap<QString, QString> m_partialPath2full; + bool m_iconChanged; +}; + +#endif diff --git a/kicker/kicker/ui/extensionop_mnu.cpp b/kicker/kicker/ui/extensionop_mnu.cpp new file mode 100644 index 000000000..9389f9cd4 --- /dev/null +++ b/kicker/kicker/ui/extensionop_mnu.cpp @@ -0,0 +1,66 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kiconloader.h> +#include <kpanelextension.h> +#include <kstdguiitem.h> + +#include "kicker.h" +#include "extensionop_mnu.h" + +PanelExtensionOpMenu::PanelExtensionOpMenu(const QString& extension, int actions, QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + if (!Kicker::the()->isImmutable()) + { + insertItem(SmallIcon("remove"), i18n("&Remove"), Remove); + } + + if (actions & KPanelExtension::ReportBug) + { + insertSeparator(); + insertItem(i18n("Report &Bug..."), ReportBug); + } + + if (actions & KPanelExtension::Help + || actions & KPanelExtension::About) + insertSeparator(); + + if (actions & KPanelExtension::About) + { + insertItem(i18n("&About"), About); + } + + if (actions & KPanelExtension::Help) + { + insertItem(SmallIcon("help"), KStdGuiItem::help().text(), Help); + } + + if (!Kicker::the()->isImmutable() && (actions & KPanelExtension::Preferences)) { + insertSeparator(); + insertItem(SmallIcon("configure"), i18n("&Configure %1...").arg(extension), Preferences); + } + + adjustSize(); +} diff --git a/kicker/kicker/ui/extensionop_mnu.h b/kicker/kicker/ui/extensionop_mnu.h new file mode 100644 index 000000000..85bf914af --- /dev/null +++ b/kicker/kicker/ui/extensionop_mnu.h @@ -0,0 +1,36 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __extensionop_mnu_h__ +#define __extensionop_mnu_h__ + +#include <qpopupmenu.h> + +class PanelExtensionOpMenu : public QPopupMenu +{ +public: + enum OpButton{Move = 9900, Remove = 9901, Help = 9902, About = 9903, Preferences = 9904, ReportBug = 9905, Shade = 9906 }; + PanelExtensionOpMenu(const QString& extension, int actions, QWidget *parent=0, const char *name=0); +}; + +#endif diff --git a/kicker/kicker/ui/hidebutton.cpp b/kicker/kicker/ui/hidebutton.cpp new file mode 100644 index 000000000..31d614006 --- /dev/null +++ b/kicker/kicker/ui/hidebutton.cpp @@ -0,0 +1,202 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan <nhasan@kde.org> + Copyright (C) 2004 Aaron J. Seigo <aseigo@kde.org> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "hidebutton.h" + +#include <qpainter.h> + +#include <kapplication.h> +#include <kcursor.h> +#include <kglobalsettings.h> +#include <kiconeffect.h> +#include <kiconloader.h> +#include <kicontheme.h> +#include <kipc.h> +#include <kstandarddirs.h> + +HideButton::HideButton(QWidget *parent, const char *name) + : QButton(parent, name), + m_highlight(false), + m_arrow(Qt::LeftArrow) +{ + setBackgroundOrigin(AncestorOrigin); + + connect(kapp, SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int))); + connect(kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int))); + + kapp->addKipcEventMask(KIPC::SettingsChanged); + kapp->addKipcEventMask(KIPC::IconChanged); + + slotSettingsChanged(KApplication::SETTINGS_MOUSE); +} + +void HideButton::drawButton(QPainter *p) +{ + if (m_arrow == Qt::LeftArrow) + { + p->setPen(colorGroup().mid()); + p->drawLine(width()-1, 0, width()-1, height()); + } + else if (m_arrow == Qt::RightArrow) + { + p->setPen(colorGroup().mid()); + p->drawLine(0, 0, 0, height()); + } + else if (m_arrow == Qt::UpArrow) + { + p->setPen(colorGroup().mid()); + p->drawLine(0, height()-1, width(), height()-1); + } + else if (m_arrow == Qt::DownArrow) + { + p->setPen(colorGroup().mid()); + p->drawLine(0, 0, width(), 0); + } + + drawButtonLabel(p); +} + +void HideButton::drawButtonLabel(QPainter *p) +{ + if (pixmap()) + { + QPixmap pix = m_highlight? m_activeIcon : m_normalIcon; + + if (isOn() || isDown()) + { + p->translate(2, 2); + } + + QPoint origin(2, 2); + + if (pix.height() < (height() - 4)) + { + origin.setY(origin.y() + ((height() - pix.height()) / 2)); + } + + if (pix.width() < (width() - 4)) + { + origin.setX(origin.x() + ((width() - pix.width()) / 2)); + } + + p->drawPixmap(origin, pix); + } +} + +void HideButton::setPixmap(const QPixmap &pix) +{ + QButton::setPixmap(pix); + generateIcons(); +} + +void HideButton::setArrowType(Qt::ArrowType arrow) +{ + m_arrow = arrow; + switch (arrow) + { + case Qt::LeftArrow: + setPixmap(SmallIcon("1leftarrow")); + break; + + case Qt::RightArrow: + setPixmap(SmallIcon("1rightarrow")); + break; + + case Qt::UpArrow: + setPixmap(SmallIcon("1uparrow")); + break; + + case Qt::DownArrow: + default: + setPixmap(SmallIcon("1downarrow")); + break; + } +} + +void HideButton::generateIcons() +{ + if (!pixmap()) + { + return; + } + + QImage image = pixmap()->convertToImage(); + image = image.smoothScale(size() - QSize(4, 4), QImage::ScaleMin); + + KIconEffect effect; + + m_normalIcon = effect.apply(image, KIcon::Panel, KIcon::DefaultState); + m_activeIcon = effect.apply(image, KIcon::Panel, KIcon::ActiveState); +} + +void HideButton::slotSettingsChanged(int category) +{ + if (category != KApplication::SETTINGS_MOUSE) + { + return; + } + + bool changeCursor = KGlobalSettings::changeCursorOverIcon(); + + if (changeCursor) + { + setCursor(KCursor::handCursor()); + } + else + { + unsetCursor(); + } +} + +void HideButton::slotIconChanged(int group) +{ + if (group != KIcon::Panel) + { + return; + } + + generateIcons(); + repaint(false); +} + +void HideButton::enterEvent(QEvent *e) +{ + m_highlight = true; + + repaint(false); + QButton::enterEvent(e); +} + +void HideButton::leaveEvent(QEvent *e) +{ + m_highlight = false; + + repaint(false); + QButton::enterEvent(e); +} + +void HideButton::resizeEvent(QResizeEvent *) +{ + generateIcons(); +} + +#include "hidebutton.moc" + +// vim:ts=4:sw=4:et diff --git a/kicker/kicker/ui/hidebutton.h b/kicker/kicker/ui/hidebutton.h new file mode 100644 index 000000000..da387cde7 --- /dev/null +++ b/kicker/kicker/ui/hidebutton.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan <nhasan@kde.org> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef HIDEBUTTON_H +#define HIDEBUTTON_H + +#include <qbutton.h> +#include <qpixmap.h> + +class HideButton : public QButton +{ + Q_OBJECT + + public: + HideButton(QWidget *parent, const char *name = 0); + void setArrowType(Qt::ArrowType arrow); + void setPixmap(const QPixmap &pix); + + protected: + void drawButton(QPainter *p); + void drawButtonLabel(QPainter *p); + void generateIcons(); + + void enterEvent(QEvent *e); + void leaveEvent( QEvent *e ); + void resizeEvent(QResizeEvent *e); + + bool m_highlight; + QPixmap m_normalIcon; + QPixmap m_activeIcon; + Qt::ArrowType m_arrow; + + protected slots: + void slotSettingsChanged( int category ); + void slotIconChanged( int group ); +}; + +#endif // HIDEBUTTON_H + +// vim:ts=4:sw=4:et diff --git a/kicker/kicker/ui/k_mnu.cpp b/kicker/kicker/ui/k_mnu.cpp new file mode 100644 index 000000000..609ce84be --- /dev/null +++ b/kicker/kicker/ui/k_mnu.cpp @@ -0,0 +1,739 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <dmctl.h> + +#include <qimage.h> +#include <qpainter.h> +#include <qstyle.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kaboutkde.h> +#include <kaction.h> +#include <kbookmarkmenu.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kwin.h> + +#include "client_mnu.h" +#include "container_base.h" +#include "global.h" +#include "kbutton.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "konqbookmarkmanager.h" +#include "menuinfo.h" +#include "menumanager.h" +#include "popupmenutitle.h" +#include "quickbrowser_mnu.h" +#include "recentapps.h" + +#include "k_mnu.h" +#include "k_mnu.moc" + +PanelKMenu::PanelKMenu() + : PanelServiceMenu(QString::null, QString::null, 0, "KMenu") + , bookmarkMenu(0) + , bookmarkOwner(0) +{ + static const QCString dcopObjId("KMenu"); + DCOPObject::setObjId(dcopObjId); + // set the first client id to some arbitrarily large value. + client_id = 10000; + // Don't automatically clear the main menu. + disableAutoClear(); + actionCollection = new KActionCollection(this); + setCaption(i18n("K Menu")); + connect(Kicker::the(), SIGNAL(configurationChanged()), + this, SLOT(configChanged())); + DCOPClient *dcopClient = KApplication::dcopClient(); + dcopClient->connectDCOPSignal(0, "appLauncher", + "serviceStartedByStorageId(QString,QString)", + dcopObjId, + "slotServiceStartedByStorageId(QString,QString)", + false); +} + +PanelKMenu::~PanelKMenu() +{ + clearSubmenus(); + delete bookmarkMenu; + delete bookmarkOwner; +} + +void PanelKMenu::slotServiceStartedByStorageId(QString starter, + QString storageId) +{ + if (starter != "kmenu") + { + kdDebug() << "KMenu - updating recently used applications: " << + storageId << endl; + KService::Ptr service = KService::serviceByStorageId(storageId); + updateRecentlyUsedApps(service); + } +} + + +bool PanelKMenu::loadSidePixmap() +{ + if (!KickerSettings::useSidePixmap()) + { + return false; + } + + QString sideName = KickerSettings::sidePixmapName(); + QString sideTileName = KickerSettings::sideTileName(); + + QImage image; + image.load(locate("data", "kicker/pics/" + sideName)); + + if (image.isNull()) + { + kdDebug(1210) << "Can't find a side pixmap" << endl; + return false; + } + + KickerLib::colorize(image); + sidePixmap.convertFromImage(image); + + image.load(locate("data", "kicker/pics/" + sideTileName)); + + if (image.isNull()) + { + kdDebug(1210) << "Can't find a side tile pixmap" << endl; + return false; + } + + KickerLib::colorize(image); + sideTilePixmap.convertFromImage(image); + + if (sidePixmap.width() != sideTilePixmap.width()) + { + kdDebug(1210) << "Pixmaps have to be the same size" << endl; + return false; + } + + // pretile the pixmap to a height of at least 100 pixels + if (sideTilePixmap.height() < 100) + { + int tiles = (int)(100 / sideTilePixmap.height()) + 1; + QPixmap preTiledPixmap(sideTilePixmap.width(), sideTilePixmap.height() * tiles); + QPainter p(&preTiledPixmap); + p.drawTiledPixmap(preTiledPixmap.rect(), sideTilePixmap); + sideTilePixmap = preTiledPixmap; + } + + return true; +} + +void PanelKMenu::paletteChanged() +{ + if (!loadSidePixmap()) + { + sidePixmap = sideTilePixmap = QPixmap(); + setMinimumSize( sizeHint() ); + } +} + +void PanelKMenu::initialize() +{ +// kdDebug(1210) << "PanelKMenu::initialize()" << endl; + updateRecent(); + + if (initialized()) + { + return; + } + + if (loadSidePixmap()) + { + // in case we've been through here before, let's disconnect + disconnect(kapp, SIGNAL(kdisplayPaletteChanged()), + this, SLOT(paletteChanged())); + connect(kapp, SIGNAL(kdisplayPaletteChanged()), + this, SLOT(paletteChanged())); + } + else + { + sidePixmap = sideTilePixmap = QPixmap(); + } + + // add services + PanelServiceMenu::initialize(); + + if (KickerSettings::showMenuTitles()) + { + int id; + id = insertItem(new PopupMenuTitle(i18n("All Applications"), font()), -1 /* id */, 0); + setItemEnabled( id, false ); + id = insertItem(new PopupMenuTitle(i18n("Actions"), font()), -1 /* id */, -1); + setItemEnabled( id, false ); + } + + // create recent menu section + createRecentMenuItems(); + + bool need_separator = false; + + // insert bookmarks + if (KickerSettings::useBookmarks() && kapp->authorizeKAction("bookmarks")) + { + // Need to create a new popup each time, it's deleted by subMenus.clear() + KPopupMenu * bookmarkParent = new KPopupMenu( this, "bookmarks" ); + if(!bookmarkOwner) + bookmarkOwner = new KBookmarkOwner; + delete bookmarkMenu; // can't reuse old one, the popup has been deleted + bookmarkMenu = new KBookmarkMenu( KonqBookmarkManager::self(), bookmarkOwner, bookmarkParent, actionCollection, true, false ); + + insertItem(KickerLib::menuIconSet("bookmark"), i18n("Bookmarks"), bookmarkParent); + + subMenus.append(bookmarkParent); + need_separator = true; + } + + // insert quickbrowser + if (KickerSettings::useBrowser()) + { + PanelQuickBrowser *browserMnu = new PanelQuickBrowser(this); + browserMnu->initialize(); + + insertItem(KickerLib::menuIconSet("kdisknav"), + i18n("Quick Browser"), + KickerLib::reduceMenu(browserMnu)); + subMenus.append(browserMnu); + need_separator = true; + } + + // insert dynamic menus + QStringList menu_ext = KickerSettings::menuExtensions(); + if (!menu_ext.isEmpty()) + { + for (QStringList::ConstIterator it=menu_ext.begin(); it!=menu_ext.end(); ++it) + { + MenuInfo info(*it); + if (!info.isValid()) + continue; + + KPanelMenu *menu = info.load(); + if (menu) + { + insertItem(KickerLib::menuIconSet(info.icon()), info.name(), menu); + dynamicSubMenus.append(menu); + need_separator = true; + } + } + } + + if (need_separator) + insertSeparator(); + + // insert client menus, if any + if (clients.count() > 0) { + QIntDictIterator<KickerClientMenu> it(clients); + while (it){ + if (it.current()->text.at(0) != '.') + insertItem( + it.current()->icon, + it.current()->text, + it.current(), + it.currentKey() + ); + ++it; + } + insertSeparator(); + } + + // run command + if (kapp->authorize("run_command")) + { + insertItem(KickerLib::menuIconSet("run"), + i18n("Run Command..."), + this, + SLOT( slotRunCommand())); + insertSeparator(); + } + + if (DM().isSwitchable() && kapp->authorize("switch_user")) + { + sessionsMenu = new QPopupMenu( this ); + insertItem(KickerLib::menuIconSet("switchuser"), i18n("Switch User"), sessionsMenu); + connect( sessionsMenu, SIGNAL(aboutToShow()), SLOT(slotPopulateSessions()) ); + connect( sessionsMenu, SIGNAL(activated(int)), SLOT(slotSessionActivated(int)) ); + } + + /* + If the user configured ksmserver to + */ + KConfig ksmserver("ksmserverrc", false, false); + ksmserver.setGroup("General"); + if (ksmserver.readEntry( "loginMode" ) == "restoreSavedSession") + { + insertItem(KickerLib::menuIconSet("filesave"), i18n("Save Session"), this, SLOT(slotSaveSession())); + } + + if (kapp->authorize("lock_screen")) + { + insertItem(KickerLib::menuIconSet("lock"), i18n("Lock Session"), this, SLOT(slotLock())); + } + + if (kapp->authorize("logout")) + { + insertItem(KickerLib::menuIconSet("exit"), i18n("Log Out..."), this, SLOT(slotLogout())); + } + +#if 0 + // WABA: tear off handles don't work together with dynamically updated + // menus. We can't update the menu while torn off, and we don't know + // when it is torn off. + if (KGlobalSettings::insertTearOffHandle()) + insertTearOffHandle(); +#endif + + setInitialized(true); +} + +int PanelKMenu::insertClientMenu(KickerClientMenu *p) +{ + int id = client_id; + clients.insert(id, p); + slotClear(); + return id; +} + +void PanelKMenu::removeClientMenu(int id) +{ + clients.remove(id); + removeItem(id); + slotClear(); +} + +extern int kicker_screen_number; + +void PanelKMenu::slotLock() +{ + QCString appname( "kdesktop" ); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", ""); +} + +void PanelKMenu::slotLogout() +{ + kapp->requestShutDown(); +} + +void PanelKMenu::slotPopulateSessions() +{ + int p = 0; + DM dm; + + sessionsMenu->clear(); + if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0) + { + if (kapp->authorize("lock_screen")) + sessionsMenu->insertItem(/*SmallIconSet("lockfork"),*/ i18n("Lock Current && Start New Session"), 100 ); + sessionsMenu->insertItem(SmallIconSet("fork"), i18n("Start New Session"), 101 ); + if (!p) { + sessionsMenu->setItemEnabled( 100, false ); + sessionsMenu->setItemEnabled( 101, false ); + } + sessionsMenu->insertSeparator(); + } + SessList sess; + if (dm.localSessions( sess )) + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + int id = sessionsMenu->insertItem( DM::sess2Str( *it ), (*it).vt ); + if (!(*it).vt) + sessionsMenu->setItemEnabled( id, false ); + if ((*it).self) + sessionsMenu->setItemChecked( id, true ); + } +} + +void PanelKMenu::slotSessionActivated( int ent ) +{ + if (ent == 100) + doNewSession( true ); + else if (ent == 101) + doNewSession( false ); + else if (!sessionsMenu->isItemChecked( ent )) + DM().lockSwitchVT( ent ); +} + +void PanelKMenu::doNewSession( bool lock ) +{ + int result = KMessageBox::warningContinueCancel( + kapp->desktop()->screen(kapp->desktop()->screenNumber(this)), + i18n("<p>You have chosen to open another desktop session.<br>" + "The current session will be hidden " + "and a new login screen will be displayed.<br>" + "An F-key is assigned to each session; " + "F%1 is usually assigned to the first session, " + "F%2 to the second session and so on. " + "You can switch between sessions by pressing " + "Ctrl, Alt and the appropriate F-key at the same time. " + "Additionally, the KDE Panel and Desktop menus have " + "actions for switching between sessions.</p>") + .arg(7).arg(8), + i18n("Warning - New Session"), + KGuiItem(i18n("&Start New Session"), "fork"), + ":confirmNewSession", + KMessageBox::PlainCaption | KMessageBox::Notify); + + if (result==KMessageBox::Cancel) + return; + + if (lock) + slotLock(); + + DM().startReserve(); +} + +void PanelKMenu::slotSaveSession() +{ + QByteArray data; + kapp->dcopClient()->send( "ksmserver", "default", + "saveCurrentSession()", data ); +} + +void PanelKMenu::slotRunCommand() +{ + QByteArray data; + QCString appname( "kdesktop" ); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + + kapp->updateRemoteUserTimestamp( appname ); + kapp->dcopClient()->send( appname, "KDesktopIface", + "popupExecuteCommand()", data ); +} + +void PanelKMenu::slotEditUserContact() +{ +} + +void PanelKMenu::setMinimumSize(const QSize & s) +{ + KPanelMenu::setMinimumSize(s.width() + sidePixmap.width(), s.height()); +} + +void PanelKMenu::setMaximumSize(const QSize & s) +{ + KPanelMenu::setMaximumSize(s.width() + sidePixmap.width(), s.height()); +} + +void PanelKMenu::setMinimumSize(int w, int h) +{ + KPanelMenu::setMinimumSize(w + sidePixmap.width(), h); +} + +void PanelKMenu::setMaximumSize(int w, int h) +{ + KPanelMenu::setMaximumSize(w + sidePixmap.width(), h); +} + +void PanelKMenu::showMenu() +{ + kdDebug( 1210 ) << "PanelKMenu::showMenu()" << endl; + PanelPopupButton *kButton = MenuManager::the()->findKButtonFor(this); + if (kButton) + { + adjustSize(); + kButton->showMenu(); + } + else + { + show(); + } +} + +QRect PanelKMenu::sideImageRect() +{ + return QStyle::visualRect( QRect( frameWidth(), frameWidth(), sidePixmap.width(), + height() - 2*frameWidth() ), this ); +} + +void PanelKMenu::resizeEvent(QResizeEvent * e) +{ +// kdDebug(1210) << "PanelKMenu::resizeEvent():" << endl; +// kdDebug(1210) << geometry().width() << ", " << geometry().height() << endl; + + PanelServiceMenu::resizeEvent(e); + + setFrameRect( QStyle::visualRect( QRect( sidePixmap.width(), 0, + width() - sidePixmap.width(), height() ), this ) ); +} + +//Workaround Qt3.3.x sizing bug, by ensuring we're always wide enough. +void PanelKMenu::resize(int width, int height) +{ + width = kMax(width, maximumSize().width()); + PanelServiceMenu::resize(width, height); +} + +QSize PanelKMenu::sizeHint() const +{ + QSize s = PanelServiceMenu::sizeHint(); +// kdDebug(1210) << "PanelKMenu::sizeHint()" << endl; +// kdDebug(1210) << s.width() << ", " << s.height() << endl; + return s; +} + +void PanelKMenu::paintEvent(QPaintEvent * e) +{ + if (sidePixmap.isNull()) { + PanelServiceMenu::paintEvent(e); + return; + } + + QPainter p(this); + p.setClipRegion(e->region()); + + style().drawPrimitive( QStyle::PE_PanelPopup, &p, + QRect( 0, 0, width(), height() ), + colorGroup(), QStyle::Style_Default, + QStyleOption( frameWidth(), 0 ) ); + + QRect r = sideImageRect(); + r.setBottom( r.bottom() - sidePixmap.height() ); + if ( r.intersects( e->rect() ) ) + { + p.drawTiledPixmap( r, sideTilePixmap ); + } + + r = sideImageRect(); + r.setTop( r.bottom() - sidePixmap.height() ); + if ( r.intersects( e->rect() ) ) + { + QRect drawRect = r.intersect( e->rect() ); + QRect pixRect = drawRect; + pixRect.moveBy( -r.left(), -r.top() ); + p.drawPixmap( drawRect.topLeft(), sidePixmap, pixRect ); + } + + drawContents( &p ); +} + +QMouseEvent PanelKMenu::translateMouseEvent( QMouseEvent* e ) +{ + QRect side = sideImageRect(); + + if ( !side.contains( e->pos() ) ) + return *e; + + QPoint newpos( e->pos() ); + QApplication::reverseLayout() ? + newpos.setX( newpos.x() - side.width() ) : + newpos.setX( newpos.x() + side.width() ); + QPoint newglobal( e->globalPos() ); + QApplication::reverseLayout() ? + newglobal.setX( newpos.x() - side.width() ) : + newglobal.setX( newpos.x() + side.width() ); + + return QMouseEvent( e->type(), newpos, newglobal, e->button(), e->state() ); +} + +void PanelKMenu::mousePressEvent(QMouseEvent * e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + PanelServiceMenu::mousePressEvent( &newEvent ); +} + +void PanelKMenu::mouseReleaseEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + PanelServiceMenu::mouseReleaseEvent( &newEvent ); +} + +void PanelKMenu::mouseMoveEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + PanelServiceMenu::mouseMoveEvent( &newEvent ); +} + +void PanelKMenu::configChanged() +{ + RecentlyLaunchedApps::the().m_bNeedToUpdate = false; + RecentlyLaunchedApps::the().configChanged(); + PanelServiceMenu::configChanged(); +} + +// create and fill "recent" section at first +void PanelKMenu::createRecentMenuItems() +{ + RecentlyLaunchedApps::the().m_nNumMenuItems = 0; + + QStringList RecentApps; + RecentlyLaunchedApps::the().getRecentApps(RecentApps); + + if (RecentApps.count() > 0) + { + bool bSeparator = KickerSettings::showMenuTitles(); + int nId = serviceMenuEndId() + 1; + int nIndex = KickerSettings::showMenuTitles() ? 1 : 0; + + for (QValueList<QString>::ConstIterator it = + RecentApps.fromLast(); /*nop*/; --it) + { + KService::Ptr s = KService::serviceByDesktopPath(*it); + if (!s) + { + RecentlyLaunchedApps::the().removeItem(*it); + } + else + { + if (bSeparator) + { + bSeparator = false; + int id = insertItem( + new PopupMenuTitle( + RecentlyLaunchedApps::the().caption(), font()), + serviceMenuEndId(), 0); + setItemEnabled( id, false ); + } + insertMenuItem(s, nId++, nIndex); + RecentlyLaunchedApps::the().m_nNumMenuItems++; + } + + if (it == RecentApps.begin()) + { + break; + } + } + + if (!KickerSettings::showMenuTitles()) + { + insertSeparator(RecentlyLaunchedApps::the().m_nNumMenuItems); + } + } +} + +void PanelKMenu::clearSubmenus() +{ + // we don't need to delete these on the way out since the libloader + // handles them for us + if (QApplication::closingDown()) + { + return; + } + + for (PopupMenuList::const_iterator it = dynamicSubMenus.constBegin(); + it != dynamicSubMenus.constEnd(); + ++it) + { + delete *it; + } + dynamicSubMenus.clear(); + + PanelServiceMenu::clearSubmenus(); +} + +void PanelKMenu::updateRecent() +{ + if (!RecentlyLaunchedApps::the().m_bNeedToUpdate) + { + return; + } + + RecentlyLaunchedApps::the().m_bNeedToUpdate = false; + + int nId = serviceMenuEndId() + 1; + + // remove previous items + if (RecentlyLaunchedApps::the().m_nNumMenuItems > 0) + { + // -1 --> menu title + int i = KickerSettings::showMenuTitles() ? -1 : 0; + for (; i < RecentlyLaunchedApps::the().m_nNumMenuItems; i++) + { + removeItem(nId + i); + entryMap_.remove(nId + i); + } + RecentlyLaunchedApps::the().m_nNumMenuItems = 0; + + if (!KickerSettings::showMenuTitles()) + { + removeItemAt(0); + } + } + + // insert new items + QStringList RecentApps; + RecentlyLaunchedApps::the().getRecentApps(RecentApps); + + if (RecentApps.count() > 0) + { + bool bNeedSeparator = KickerSettings::showMenuTitles(); + for (QValueList<QString>::ConstIterator it = RecentApps.fromLast(); + /*nop*/; --it) + { + KService::Ptr s = KService::serviceByDesktopPath(*it); + if (!s) + { + RecentlyLaunchedApps::the().removeItem(*it); + } + else + { + if (bNeedSeparator) + { + bNeedSeparator = false; + int id = insertItem(new PopupMenuTitle( + RecentlyLaunchedApps::the().caption(), + font()), nId - 1, 0); + setItemEnabled( id, false ); + } + insertMenuItem(s, nId++, KickerSettings::showMenuTitles() ? + 1 : 0); + RecentlyLaunchedApps::the().m_nNumMenuItems++; + } + + if (it == RecentApps.begin()) + break; + } + + if (!KickerSettings::showMenuTitles()) + { + insertSeparator(RecentlyLaunchedApps::the().m_nNumMenuItems); + } + } +} + +void PanelKMenu::clearRecentMenuItems() +{ + RecentlyLaunchedApps::the().clearRecentApps(); + RecentlyLaunchedApps::the().save(); + RecentlyLaunchedApps::the().m_bNeedToUpdate = true; + updateRecent(); +} + + diff --git a/kicker/kicker/ui/k_mnu.h b/kicker/kicker/ui/k_mnu.h new file mode 100644 index 000000000..f20cde06d --- /dev/null +++ b/kicker/kicker/ui/k_mnu.h @@ -0,0 +1,106 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __k_mnu_h__ +#define __k_mnu_h__ + +#include <dcopobject.h> +#include <qintdict.h> +#include <qpixmap.h> + +#include "service_mnu.h" + +class KickerClientMenu; +class KBookmarkMenu; +class KActionCollection; +class KBookmarkOwner; +class Panel; + +class PanelKMenu : public PanelServiceMenu, public DCOPObject +{ + Q_OBJECT + K_DCOP + +k_dcop: + void slotServiceStartedByStorageId(QString starter, QString desktopPath); + +public: + PanelKMenu(); + ~PanelKMenu(); + + int insertClientMenu(KickerClientMenu *p); + void removeClientMenu(int id); + + virtual QSize sizeHint() const; + virtual void setMinimumSize(const QSize &); + virtual void setMaximumSize(const QSize &); + virtual void setMinimumSize(int, int); + virtual void setMaximumSize(int, int); + virtual void showMenu(); + void clearRecentMenuItems(); + +public slots: + virtual void initialize(); + + //### KDE4: workaround for Qt bug, remove later + virtual void resize(int width, int height); + +protected slots: + void slotLock(); + void slotLogout(); + void slotPopulateSessions(); + void slotSessionActivated( int ); + void slotSaveSession(); + void slotRunCommand(); + void slotEditUserContact(); + void paletteChanged(); + virtual void configChanged(); + void updateRecent(); + +protected: + QRect sideImageRect(); + QMouseEvent translateMouseEvent(QMouseEvent* e); + void resizeEvent(QResizeEvent *); + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + bool loadSidePixmap(); + void doNewSession(bool lock); + void createRecentMenuItems(); + virtual void clearSubmenus(); + +private: + QPopupMenu *sessionsMenu; + QPixmap sidePixmap; + QPixmap sideTilePixmap; + int client_id; + bool delay_init; + QIntDict<KickerClientMenu> clients; + KBookmarkMenu *bookmarkMenu; + KActionCollection *actionCollection; + KBookmarkOwner *bookmarkOwner; + PopupMenuList dynamicSubMenus; +}; + +#endif diff --git a/kicker/kicker/ui/nonKDEButtonSettings.ui b/kicker/kicker/ui/nonKDEButtonSettings.ui new file mode 100644 index 000000000..5c44aca85 --- /dev/null +++ b/kicker/kicker/ui/nonKDEButtonSettings.ui @@ -0,0 +1,221 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>NonKDEButtonSettings</class> +<widget class="QWidget"> + <property name="name"> + <cstring>NonKDEButtonSettings</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>436</width> + <height>225</height> + </rect> + </property> + <property name="caption"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KURLRequester" row="7" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_exec</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name of the executable file to be run when this button is selected. If it is not in your $PATH then you will need to provide an absolute path.</string> + </property> + </widget> + <widget class="QLabel" row="8" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Co&mmand line arguments (optional):</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_commandLine</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter any command line options that should be passed to the command here. + +<i>Example</i>: For the command `rm -rf` enter "-rf" in this text box.</string> + </property> + </widget> + <widget class="QCheckBox" row="10" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_inTerm</cstring> + </property> + <property name="text"> + <string>Run in a &terminal window</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Select this option if the command is a command line application and you wish to be able to see its output when run.</string> + </property> + </widget> + <widget class="QLineEdit" row="9" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_commandLine</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter any command line options that should be passed to the command here. + +<i>Example</i>: For the command `rm -rf` enter "-rf" in this text box.</string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Executable:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_exec</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name of the executable file to be run when this button is selected. If it is not in your $PATH then you will need to provide an absolute path.</string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>15</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name you would like to appear for this button here.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Button title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_title</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name you would like to appear for this button here.</string> + </property> + </widget> + <spacer row="11" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="KIconButton" row="0" column="0" rowspan="3" colspan="1"> + <property name="name"> + <cstring>m_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>58</width> + <height>58</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>58</width> + <height>58</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSize"> + <number>48</number> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>&Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_description</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name you would like to appear for this button here.</string> + </property> + </widget> + <widget class="QLineEdit" row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>15</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the name you would like to appear for this button here.</string> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>8</height> + </size> + </property> + </spacer> + </grid> +</widget> +<tabstops> + <tabstop>m_icon</tabstop> + <tabstop>m_title</tabstop> + <tabstop>m_description</tabstop> + <tabstop>m_exec</tabstop> + <tabstop>m_commandLine</tabstop> + <tabstop>m_inTerm</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/kicker/kicker/ui/panelmenuiteminfo.h b/kicker/kicker/ui/panelmenuiteminfo.h new file mode 100644 index 000000000..29faca50f --- /dev/null +++ b/kicker/kicker/ui/panelmenuiteminfo.h @@ -0,0 +1,103 @@ +/***************************************************************** + +Copyright (c) 2003 Aaron J. Seigo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef PANELMENUITEMINFO_H +#define PANELMENUITEMINFO_H + +#include <qpopupmenu.h> +#include <qstring.h> + +#include <kiconloader.h> + +// a little class meant to be used to store menu items for sorting then later +// plugging into a popup menu + +class PanelMenuItemInfo +{ + public: + PanelMenuItemInfo() + : m_recvr(0), m_id(-1) {} + + PanelMenuItemInfo(const QString& iconName, const QString& visibleName, const QObject* recvr, const QCString& slot, int id = -1) + : m_icon(iconName), m_name(visibleName), m_slot_(slot), m_recvr(recvr), m_id(id) {} + + PanelMenuItemInfo(const QString& iconName, const QString& visibleName, int id = -1) + : m_icon(iconName), m_name(visibleName), m_recvr(0), m_id(id) {} + + PanelMenuItemInfo(const PanelMenuItemInfo& c) + : m_icon(c.m_icon), m_name(c.m_name), m_slot_(c.m_slot_), m_recvr(c.m_recvr), m_id(c.m_id) {} + + PanelMenuItemInfo& operator=(const PanelMenuItemInfo& c) + { + m_icon = c.m_icon; + m_name = c.m_name; + m_slot_ = c.m_slot_; + m_recvr = c.m_recvr; + m_id = c.m_id; + return *this; + } + + bool operator<(const PanelMenuItemInfo& rh) + { + return m_name.lower() < rh.m_name.lower(); + } + + bool operator<=(const PanelMenuItemInfo& rh) + { + return m_name.lower() <= rh.m_name.lower(); + } + + bool operator>(const PanelMenuItemInfo& rh) + { + return m_name.lower() > rh.m_name.lower(); + } + + int plug(QPopupMenu* menu) + { + if (!m_icon.isEmpty() && m_icon != "unknown") + { + if (m_recvr && !m_slot_.isEmpty()) + { + return menu->insertItem(SmallIconSet(m_icon), m_name, m_recvr, m_slot_, 0, m_id); + } + + return menu->insertItem(SmallIconSet(m_icon), m_name, m_id); + } + else if (m_recvr && !m_slot_.isEmpty()) + { + return menu->insertItem(m_name, m_recvr, m_slot_, 0, m_id); + } + + return menu->insertItem(m_name, m_id); + } + + private: + QString m_icon; + QString m_name; + QCString m_slot_; // HPUX namespace is polluted with m_slot + const QObject* m_recvr; + int m_id; +}; + +#endif + diff --git a/kicker/kicker/ui/popupmenutitle.cpp b/kicker/kicker/ui/popupmenutitle.cpp new file mode 100644 index 000000000..adf44b802 --- /dev/null +++ b/kicker/kicker/ui/popupmenutitle.cpp @@ -0,0 +1,33 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "popupmenutitle.h" + +PopupMenuTitle::PopupMenuTitle(const QString &name, const QFont &font) : + QCustomMenuItem(), + m_desktopName(name), + m_font(font) +{ + m_font.setBold(true); +} diff --git a/kicker/kicker/ui/popupmenutitle.h b/kicker/kicker/ui/popupmenutitle.h new file mode 100644 index 000000000..4724c88c7 --- /dev/null +++ b/kicker/kicker/ui/popupmenutitle.h @@ -0,0 +1,85 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef POPUPMENUTITLE_H +#define POPUPMENUTITLE_H + +#include <qfont.h> +#include <qstring.h> +#include <qstyle.h> +#include <qpainter.h> +#include <qmenudata.h> + +#include <kapplication.h> + +class PopupMenuTitle : public QCustomMenuItem +{ +public: + PopupMenuTitle(const QString &name, const QFont &font); + + bool fullSpan () const { return true; } + + void paint(QPainter* p, const QColorGroup& cg, + bool /* act */, bool /*enabled*/, + int x, int y, int w, int h) + { + p->save(); + QRect r(x, y, w, h); + kapp->style().drawPrimitive(QStyle::PE_HeaderSection, + p, r, cg); + + if (!m_desktopName.isEmpty()) + { + p->setPen(cg.buttonText()); + p->setFont(m_font); + p->drawText(x, y, w, h, + AlignCenter | SingleLine, + m_desktopName); + } + + p->setPen(cg.highlight()); + p->drawLine(0, 0, r.right(), 0); + p->restore(); + } + + void setFont(const QFont &font) + { + m_font = font; + m_font.setBold(true); + } + + QSize sizeHint() + { + QSize size = QFontMetrics(m_font).size(AlignHCenter, m_desktopName); + size.setHeight(size.height() + + (kapp->style().pixelMetric(QStyle::PM_DefaultFrameWidth) * 2 + 1)); + return size; + } + + private: + QString m_desktopName; + QFont m_font; +}; + +#endif diff --git a/kicker/kicker/ui/quickbrowser_mnu.cpp b/kicker/kicker/ui/quickbrowser_mnu.cpp new file mode 100644 index 000000000..583fc1deb --- /dev/null +++ b/kicker/kicker/ui/quickbrowser_mnu.cpp @@ -0,0 +1,60 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qdir.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kurl.h> + +#include "browser_mnu.h" +#include "quickbrowser_mnu.h" +#include "quickbrowser_mnu.moc" + +PanelQuickBrowser::PanelQuickBrowser(QWidget *parent, const char *name) + : KPanelMenu("", parent, name) {} + +void PanelQuickBrowser::initialize() +{ + if(initialized()) return; + setInitialized(true); + + KURL url; + + url.setPath(QDir::homeDirPath()); + if (kapp->authorizeURLAction("list", KURL(), url)) + insertItem(SmallIcon("kfm_home"), i18n("&Home Folder"), + new PanelBrowserMenu(url.path(), this)); + + url.setPath(QDir::rootDirPath()); + if (kapp->authorizeURLAction("list", KURL(), url)) + insertItem(SmallIcon("folder_red"), i18n("&Root Folder"), + new PanelBrowserMenu(url.path(), this)); + + url.setPath(QDir::rootDirPath() + "etc"); + if (kapp->authorizeURLAction("list", KURL(), url)) + insertItem(SmallIcon("folder_yellow"), i18n("System &Configuration"), + new PanelBrowserMenu(url.path(), this)); +} diff --git a/kicker/kicker/ui/quickbrowser_mnu.h b/kicker/kicker/ui/quickbrowser_mnu.h new file mode 100644 index 000000000..9d9582a8b --- /dev/null +++ b/kicker/kicker/ui/quickbrowser_mnu.h @@ -0,0 +1,43 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __quickbrowser_mnu_h__ +#define __quickbrowser_mnu_h__ + +#include <kpanelmenu.h> + +class PanelQuickBrowser : public KPanelMenu +{ + Q_OBJECT + +public: + PanelQuickBrowser(QWidget *parent=0, const char *name=0); + +public slots: + virtual void initialize(); + +protected slots: + void slotExec(int) {} +}; + +#endif diff --git a/kicker/kicker/ui/recentapps.cpp b/kicker/kicker/ui/recentapps.cpp new file mode 100644 index 000000000..54241cb29 --- /dev/null +++ b/kicker/kicker/ui/recentapps.cpp @@ -0,0 +1,172 @@ +/***************************************************************** + +Copyright (c) 2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <time.h> + +#include <qregexp.h> +#include <qstringlist.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> + +#include "kickerSettings.h" + +#include "recentapps.h" + +RecentlyLaunchedApps& RecentlyLaunchedApps::the() +{ + static RecentlyLaunchedApps obj; + return obj; +} + +RecentlyLaunchedApps::RecentlyLaunchedApps() +{ + // set defaults + m_nNumMenuItems = 0; + m_bNeedToUpdate = false; + m_bInitialised = false; + init(); +} + +void RecentlyLaunchedApps::init() +{ + if (m_bInitialised) + { + return; + } + + m_nNumMenuItems = 0; + m_appInfos.clear(); + + configChanged(); + + QStringList recentApps = KickerSettings::recentAppsStat(); + + for (QStringList::ConstIterator it = recentApps.begin(); + it != recentApps.end(); ++it ) + { + QRegExp re( "(\\d*) (\\d*) (.*)" ); + if (re.search(*it) != -1) + { + int nCount = re.cap(1).toInt(); + long lTime = re.cap(2).toLong(); + QString szPath = re.cap(3); + m_appInfos.append(RecentlyLaunchedAppInfo( + szPath, nCount, time_t(lTime))); + } + } + + qHeapSort(m_appInfos); + + m_bInitialised = true; +} + +void RecentlyLaunchedApps::configChanged() +{ + qHeapSort(m_appInfos); +} + +void RecentlyLaunchedApps::save() +{ + QStringList recentApps; + + for (QValueList<RecentlyLaunchedAppInfo>::const_iterator it = + m_appInfos.constBegin(); it != m_appInfos.constEnd(); ++it) + { + recentApps.append(QString("%1 %2 %3").arg((*it).getLaunchCount()) + .arg((*it).getLastLaunchTime()) + .arg((*it).getDesktopPath())); + } + + KickerSettings::setRecentAppsStat(recentApps); + KickerSettings::writeConfig(); +} + +void RecentlyLaunchedApps::appLaunched(const QString& strApp) +{ + // Inform other applications (like the quickstarter applet) + // that an application was started + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << launchDCOPSignalSource() << strApp; + KApplication::kApplication()->dcopClient()->emitDCOPSignal("appLauncher", + "serviceStartedByStorageId(QString,QString)", params); + + for (QValueList<RecentlyLaunchedAppInfo>::iterator it = m_appInfos.begin(); + it != m_appInfos.end(); ++it) + { + if ((*it).getDesktopPath() == strApp) + { + (*it).increaseLaunchCount(); + (*it).setLastLaunchTime(time(0)); + qHeapSort(m_appInfos); + return; + } + } + + m_appInfos.append(RecentlyLaunchedAppInfo(strApp, 1, time(0))); + qHeapSort(m_appInfos); +} + +void RecentlyLaunchedApps::getRecentApps(QStringList& recentApps) +{ + recentApps.clear(); + + int maximumNum = KickerSettings::numVisibleEntries(); + int i = 0; + for (QValueList<RecentlyLaunchedAppInfo>::const_iterator it = + m_appInfos.constBegin(); + it != m_appInfos.constEnd() && i < maximumNum; + ++it, ++i) + { + recentApps.append((*it).getDesktopPath()); + } +} + +void RecentlyLaunchedApps::removeItem( const QString& strName ) +{ + for (QValueList<RecentlyLaunchedAppInfo>::iterator it = m_appInfos.begin(); + it != m_appInfos.end(); ++it) + { + if ((*it).getDesktopPath() == strName) + { + m_appInfos.erase(it); + return; + } + } +} + +void RecentlyLaunchedApps::clearRecentApps() +{ + m_appInfos.clear(); +} + +QString RecentlyLaunchedApps::caption() const +{ + return KickerSettings::recentVsOften() ? + i18n("Recently Used Applications") : + i18n("Most Used Applications"); +} diff --git a/kicker/kicker/ui/recentapps.h b/kicker/kicker/ui/recentapps.h new file mode 100644 index 000000000..0582cc166 --- /dev/null +++ b/kicker/kicker/ui/recentapps.h @@ -0,0 +1,99 @@ +/***************************************************************** + +Copyright (c) 2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __recentapps_h__ +#define __recentapps_h__ + +#include <qvaluelist.h> + +class RecentlyLaunchedApps; + +class RecentlyLaunchedAppInfo +{ +public: + RecentlyLaunchedAppInfo() + { + m_launchCount = 0; + m_lastLaunchTime = 0; + } + + RecentlyLaunchedAppInfo(const QString& desktopPath, int nLaunchCount, time_t lastLaunchTime) + { + m_desktopPath = desktopPath; + m_launchCount = nLaunchCount; + m_lastLaunchTime = lastLaunchTime; + } + + RecentlyLaunchedAppInfo(const RecentlyLaunchedAppInfo& clone) + { + m_desktopPath = clone.m_desktopPath; + m_launchCount = clone.m_launchCount; + m_lastLaunchTime = clone.m_lastLaunchTime; + } + + bool operator<(const RecentlyLaunchedAppInfo& rhs) + { + // Sort items in descending order according to either last launch time or launch count. + return KickerSettings::recentVsOften() ? + m_lastLaunchTime > rhs.m_lastLaunchTime: + m_launchCount > rhs.m_launchCount; + } + + QString getDesktopPath() const { return m_desktopPath; } + int getLaunchCount() const { return m_launchCount; }; + time_t getLastLaunchTime() const { return m_lastLaunchTime; }; + void increaseLaunchCount() { m_launchCount++; }; + void setLaunchCount(int nLaunchCount) { m_launchCount = nLaunchCount; }; + void setLastLaunchTime(time_t lastLaunch) { m_lastLaunchTime = lastLaunch; }; + +private: + QString m_desktopPath; + int m_launchCount; + time_t m_lastLaunchTime; +}; + +class RecentlyLaunchedApps +{ +public: + static RecentlyLaunchedApps& the(); + void init(); + void configChanged(); + void save(); + void clearRecentApps(); + void appLaunched(const QString & strApp); + void getRecentApps(QStringList & RecentApps); + void removeItem(const QString &strName); + QString caption() const; + + int m_nNumMenuItems; + bool m_bNeedToUpdate; + +private: + QString launchDCOPSignalSource() { return "kmenu"; } + RecentlyLaunchedApps(); + + QValueList<RecentlyLaunchedAppInfo> m_appInfos; + bool m_bInitialised; +}; + +#endif diff --git a/kicker/kicker/ui/removeapplet_mnu.cpp b/kicker/kicker/ui/removeapplet_mnu.cpp new file mode 100644 index 000000000..fce885f39 --- /dev/null +++ b/kicker/kicker/ui/removeapplet_mnu.cpp @@ -0,0 +1,99 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kglobal.h> + +#include "pluginmanager.h" +#include "containerarea.h" +#include "container_applet.h" + +#include "panelmenuiteminfo.h" +#include "removeapplet_mnu.h" +#include "removeapplet_mnu.moc" + +PanelRemoveAppletMenu::PanelRemoveAppletMenu(ContainerArea* cArea, + QWidget *parent, + const char *name) + : QPopupMenu(parent, name), m_containerArea(cArea) +{ + connect(this, SIGNAL(activated(int)), SLOT(slotExec(int))); + connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); +} + +void PanelRemoveAppletMenu::slotAboutToShow() +{ + int id = 0; + + clear(); + m_containers = m_containerArea->containers("Applet") + + m_containerArea->containers("Special Button"); + + QValueList<PanelMenuItemInfo> items; + + for (BaseContainer::List::const_iterator it = m_containers.constBegin(); + it != m_containers.constEnd();) + { + BaseContainer* container = *it; + if (container->isImmutable()) + { + ++it; + m_containers.remove(container); + continue; + } + + items.append(PanelMenuItemInfo(container->icon(), + container->visibleName().replace("&", "&&"), + id)); + ++id; + ++it; + } + + qHeapSort(items); + + for (QValueList<PanelMenuItemInfo>::iterator it = items.begin(); + it != items.end(); + ++it) + { + (*it).plug(this); + } + + if (m_containers.count() > 1) + { + insertSeparator(); + insertItem(i18n("All"), this, SLOT(slotRemoveAll()), 0, id); + } +} + +void PanelRemoveAppletMenu::slotExec(int id) +{ + if (m_containers.at(id) != m_containers.end()) + { + m_containerArea->removeContainer(*m_containers.at(id)); + } +} + +void PanelRemoveAppletMenu::slotRemoveAll() +{ + m_containerArea->removeContainers(m_containers); +} diff --git a/kicker/kicker/ui/removeapplet_mnu.h b/kicker/kicker/ui/removeapplet_mnu.h new file mode 100644 index 000000000..455a93afd --- /dev/null +++ b/kicker/kicker/ui/removeapplet_mnu.h @@ -0,0 +1,52 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __removeapplet_mnu_h__ +#define __removeapplet_mnu_h__ + +#include <qptrlist.h> +#include <qpopupmenu.h> + +#include "appletinfo.h" +#include "container_base.h" + +class ContainerArea; + +class PanelRemoveAppletMenu : public QPopupMenu +{ + Q_OBJECT + +public: + PanelRemoveAppletMenu(ContainerArea* cArea, QWidget* parent = 0, const char* name = 0); + +protected slots: + void slotExec( int id ); + void slotAboutToShow(); + void slotRemoveAll(); + +private: + BaseContainer::List m_containers; + ContainerArea* m_containerArea; +}; + +#endif diff --git a/kicker/kicker/ui/removebutton_mnu.cpp b/kicker/kicker/ui/removebutton_mnu.cpp new file mode 100644 index 000000000..33dc48e14 --- /dev/null +++ b/kicker/kicker/ui/removebutton_mnu.cpp @@ -0,0 +1,111 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qregexp.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kglobal.h> +#include <kdebug.h> + +#include "panelbutton.h" +#include "pluginmanager.h" +#include "containerarea.h" +#include "container_button.h" + +#include "panelmenuiteminfo.h" +#include "removebutton_mnu.h" +#include "removebutton_mnu.moc" + +PanelRemoveButtonMenu::PanelRemoveButtonMenu( ContainerArea* cArea, + QWidget *parent, const char *name ) + : QPopupMenu( parent, name ), containerArea( cArea ) +{ + connect(this, SIGNAL(activated(int)), SLOT(slotExec(int))); + connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); +} + +void PanelRemoveButtonMenu::addToContainers(const QString& type) +{ + BaseContainer::List list = containerArea->containers(type); + for (BaseContainer::Iterator it = list.begin(); + it != list.end(); + ++it) + { + if ((*it)->isImmutable()) + { + continue; + } + containers.append(*it); + } +} + +void PanelRemoveButtonMenu::slotAboutToShow() +{ + clear(); + containers.clear(); + + addToContainers("URLButton"); + addToContainers("ServiceButton"); + addToContainers("ServiceMenuButton"); + addToContainers("ExecButton"); + + int id = 0; + QValueList<PanelMenuItemInfo> items; + for (BaseContainer::Iterator it = containers.begin(); it != containers.end(); ++it) + { + items.append(PanelMenuItemInfo((*it)->icon(), (*it)->visibleName(), id)); + id++; + } + + qHeapSort(items); + + for (QValueList<PanelMenuItemInfo>::iterator it = items.begin(); + it != items.end(); + ++it) + { + (*it).plug(this); + } + + if (containers.count() > 1) + { + insertSeparator(); + insertItem(i18n("All"), this, SLOT(slotRemoveAll()), 0, id); + } +} + +void PanelRemoveButtonMenu::slotExec( int id ) +{ + if (containers.at(id) != containers.end()) + { + containerArea->removeContainer(*containers.at(id)); + } +} + +PanelRemoveButtonMenu::~PanelRemoveButtonMenu() +{ +} + +void PanelRemoveButtonMenu::slotRemoveAll() +{ + containerArea->removeContainers(containers); +} diff --git a/kicker/kicker/ui/removebutton_mnu.h b/kicker/kicker/ui/removebutton_mnu.h new file mode 100644 index 000000000..20d29c171 --- /dev/null +++ b/kicker/kicker/ui/removebutton_mnu.h @@ -0,0 +1,55 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __removebutton_mnu_h__ +#define __removebutton_mnu_h__ + +#include <qptrlist.h> +#include <qpopupmenu.h> + +#include "appletinfo.h" +#include "container_base.h" + +class ContainerArea; + +class PanelRemoveButtonMenu : public QPopupMenu +{ + Q_OBJECT + +public: + PanelRemoveButtonMenu( ContainerArea *cArea, QWidget *parent=0, const char *name=0 ); + ~PanelRemoveButtonMenu(); + +protected slots: + void slotExec( int id ); + void slotAboutToShow(); + void slotRemoveAll(); + +private: + void addToContainers(const QString& type); + + BaseContainer::List containers; + ContainerArea* containerArea; +}; + +#endif diff --git a/kicker/kicker/ui/removecontainer_mnu.cpp b/kicker/kicker/ui/removecontainer_mnu.cpp new file mode 100644 index 000000000..ddce1f2df --- /dev/null +++ b/kicker/kicker/ui/removecontainer_mnu.cpp @@ -0,0 +1,61 @@ +/***************************************************************** + +Copyreght (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kglobal.h> + +#include "removecontainer_mnu.h" +#include "removecontainer_mnu.moc" + +#include "removeapplet_mnu.h" +#include "removebutton_mnu.h" +#include "removeextension_mnu.h" + +#include "kicker.h" +#include "extensionmanager.h" +#include "containerarea.h" + +RemoveContainerMenu::RemoveContainerMenu( ContainerArea* cArea, + QWidget *parent, const char *name) + : QPopupMenu( parent, name ), containerArea( cArea ) +{ + appletId = insertItem(i18n("&Applet"), + new PanelRemoveAppletMenu(containerArea, this)); + buttonId = insertItem(i18n("Appli&cation"), + new PanelRemoveButtonMenu( containerArea, this ) ); + adjustSize(); + connect( this, SIGNAL( aboutToShow() ), SLOT( slotAboutToShow() ) ); +} + +RemoveContainerMenu::~RemoveContainerMenu() +{ +} + +void RemoveContainerMenu::slotAboutToShow() +{ + setItemEnabled(appletId, containerArea->containerCount("Applet") > 0 || + containerArea->containerCount("Special Button") > 0); + setItemEnabled(buttonId, (containerArea->containerCount("ServiceMenuButton") + + containerArea->containerCount("ServiceButton")) > 0); +} + diff --git a/kicker/kicker/ui/removecontainer_mnu.h b/kicker/kicker/ui/removecontainer_mnu.h new file mode 100644 index 000000000..9d7142671 --- /dev/null +++ b/kicker/kicker/ui/removecontainer_mnu.h @@ -0,0 +1,47 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __removecontainer_mnu_h__ +#define __removecontainer_mnu_h__ + +#include <qpopupmenu.h> + +class ContainerArea; + +class RemoveContainerMenu : public QPopupMenu +{ + Q_OBJECT + +public: + RemoveContainerMenu(ContainerArea* cArea, QWidget *parent=0, const char *name=0); + ~RemoveContainerMenu(); + +protected slots: + void slotAboutToShow(); + +private: + int appletId, buttonId; + ContainerArea *containerArea; +}; + +#endif diff --git a/kicker/kicker/ui/removeextension_mnu.cpp b/kicker/kicker/ui/removeextension_mnu.cpp new file mode 100644 index 000000000..7f7d09075 --- /dev/null +++ b/kicker/kicker/ui/removeextension_mnu.cpp @@ -0,0 +1,108 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <klocale.h> +#include <kglobal.h> + +#include "kicker.h" +#include "extensionmanager.h" +#include "pluginmanager.h" + +#include "panelmenuiteminfo.h" +#include "removeextension_mnu.h" +#include "removeextension_mnu.moc" + +static const int REMOVEALLID = 1000; + +PanelRemoveExtensionMenu::PanelRemoveExtensionMenu( QWidget *parent, const char *name ) + : QPopupMenu( parent, name ) +{ + connect(this, SIGNAL(activated(int)), SLOT(slotExec(int))); + connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); +} + +PanelRemoveExtensionMenu::PanelRemoveExtensionMenu() +{ +} + +void PanelRemoveExtensionMenu::slotAboutToShow() +{ + int id = 0; + + clear(); + m_containers = ExtensionManager::the()->containers(); + QValueList<PanelMenuItemInfo> items; + + ExtensionList::iterator itEnd = m_containers.end(); + for (ExtensionList::iterator it = m_containers.begin(); it != itEnd; ++it) + { + const AppletInfo info = (*it)->info(); + QString name = info.name().replace("&", "&&"); + switch ((*it)->position()) + { + case KPanelExtension::Top: + name = i18n("%1 (Top)").arg(name); + break; + case KPanelExtension::Right: + name = i18n("%1 (Right)").arg(name); + break; + case KPanelExtension::Bottom: + name = i18n("%1 (Bottom)").arg(name); + break; + case KPanelExtension::Left: + name = i18n("%1 (Left)").arg(name); + break; + case KPanelExtension::Floating: + name = i18n("%1 (Floating)").arg(name); + break; + } + items.append(PanelMenuItemInfo(QString::null, name, id)); + ++id; + } + + qHeapSort(items); + QValueList<PanelMenuItemInfo>::iterator itEnd2 = items.end(); + for (QValueList<PanelMenuItemInfo>::iterator it = items.begin(); it != itEnd2; ++it) + { + (*it).plug(this); + } + + if (m_containers.count() > 1) + { + insertSeparator(); + insertItem(i18n("All"), REMOVEALLID); + } +} + +void PanelRemoveExtensionMenu::slotExec( int id ) +{ + if (id == REMOVEALLID) + { + ExtensionManager::the()->removeAllContainers(); + } + else if (m_containers.at(id) != m_containers.end()) + { + ExtensionManager::the()->removeContainer(*m_containers.at(id)); + } +} + diff --git a/kicker/kicker/ui/removeextension_mnu.h b/kicker/kicker/ui/removeextension_mnu.h new file mode 100644 index 000000000..bc0e08b00 --- /dev/null +++ b/kicker/kicker/ui/removeextension_mnu.h @@ -0,0 +1,48 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __removeextension_mnu_h__ +#define __removeextension_mnu_h__ + +#include <qptrlist.h> +#include <qpopupmenu.h> + +#include "container_extension.h" + +class PanelRemoveExtensionMenu : public QPopupMenu +{ + Q_OBJECT + +public: + PanelRemoveExtensionMenu( QWidget *parent=0, const char *name=0 ); + PanelRemoveExtensionMenu(); + +protected slots: + void slotExec( int id ); + void slotAboutToShow(); + +private: + ExtensionList m_containers; +}; + +#endif diff --git a/kicker/kicker/ui/service_mnu.cpp b/kicker/kicker/ui/service_mnu.cpp new file mode 100644 index 000000000..a59c14ce8 --- /dev/null +++ b/kicker/kicker/ui/service_mnu.cpp @@ -0,0 +1,823 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <typeinfo> +#include <qcursor.h> +#include <qbitmap.h> +#include <qpixmap.h> +#include <qimage.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmimetype.h> +#include <kprocess.h> +#include <krun.h> +#include <kservicegroup.h> +#include <ksycoca.h> +#include <ksycocaentry.h> +#include <kservice.h> +#include <kurldrag.h> +#include <kio/job.h> + +#include "global.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "menumanager.h" +#include "popupmenutitle.h" +#include "panelbutton.h" +#include "recentapps.h" +#include "service_mnu.h" +#include "service_mnu.moc" + +PanelServiceMenu::PanelServiceMenu(const QString & label, const QString & relPath, QWidget * parent, + const char * name, bool addmenumode, const QString & insertInlineHeader) + : KPanelMenu(label, parent, name), + relPath_(relPath), + insertInlineHeader_( insertInlineHeader ), + clearOnClose_(false), + addmenumode_(addmenumode), + popupMenu_(0) +{ + excludeNoDisplay_=true; + + connect(KSycoca::self(), SIGNAL(databaseChanged()), + SLOT(slotClearOnClose())); + connect(this, SIGNAL(aboutToHide()), this, SLOT(slotClose())); +} + +PanelServiceMenu::~PanelServiceMenu() +{ + clearSubmenus(); +} + + +void PanelServiceMenu::setExcludeNoDisplay( bool flag ) +{ + excludeNoDisplay_=flag; +} + +void PanelServiceMenu::showMenu() +{ + activateParent(QString::null); +} + +// the initialization is split in initialize() and +// doInitialize() so that a subclass does not have to +// redo all the service parsing (see e.g. kicker/menuext/prefmenu) + +void PanelServiceMenu::initialize() +{ + if (initialized()) return; + + setInitialized(true); + entryMap_.clear(); + clear(); + + clearSubmenus(); + doInitialize(); +} + +void PanelServiceMenu::fillMenu(KServiceGroup::Ptr& _root, + KServiceGroup::List& _list, + const QString& /* _relPath */, + int& id) +{ + QStringList suppressGenericNames = _root->suppressGenericNames(); + + KServiceGroup::List::ConstIterator it = _list.begin(); + bool separatorNeeded = false; + for (; it != _list.end(); ++it) + { + KSycocaEntry * e = *it; + + if (e->isType(KST_KServiceGroup)) + { + + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); + QString groupCaption = g->caption(); + + // Avoid adding empty groups. + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(g->relPath()); + + int nbChildCount = subMenuRoot->childCount(); + if (nbChildCount == 0 && !g->showEmptyMenu()) + { + continue; + } + + QString inlineHeaderName = g->showInlineHeader() ? groupCaption : ""; + // Item names may contain ampersands. To avoid them being converted + // to accelerators, replace them with two ampersands. + groupCaption.replace("&", "&&"); + + if ( nbChildCount == 1 && g->allowInline() && g->inlineAlias()) + { + KServiceGroup::Ptr element = KServiceGroup::group(g->relPath()); + if ( element ) + { + //just one element + KServiceGroup::List listElement = element->entries(true, excludeNoDisplay_, true, KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly); + KSycocaEntry * e1 = *( listElement.begin() ); + if ( e1->isType( KST_KService ) ) + { + if (separatorNeeded) + { + insertSeparator(); + separatorNeeded = false; + } + + KService::Ptr s(static_cast<KService *>(e1)); + insertMenuItem(s, id++, -1, &suppressGenericNames); + continue; + } + } + } + + if (g->allowInline() && ((nbChildCount <= g->inlineValue() ) || (g->inlineValue() == 0))) + { + //inline all entries + KServiceGroup::Ptr rootElement = KServiceGroup::group(g->relPath()); + + if (!rootElement || !rootElement->isValid()) + { + break; + } + + KServiceGroup::List listElement = rootElement->entries(true, excludeNoDisplay_, true, KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly); + + if ( !g->inlineAlias() && !inlineHeaderName.isEmpty() ) + { + int mid = insertItem(new PopupMenuTitle(inlineHeaderName, font()), id + 1, id); + id++; + setItemEnabled( mid, false ); + } + + fillMenu( rootElement, listElement, g->relPath(), id ); + continue; + } + + // Ignore dotfiles. + if ((g->name().at(0) == '.')) + { + continue; + } + + PanelServiceMenu * m = + newSubMenu(g->name(), g->relPath(), this, g->name().utf8(), inlineHeaderName); + m->setCaption(groupCaption); + + QIconSet iconset = KickerLib::menuIconSet(g->icon()); + + if (separatorNeeded) + { + insertSeparator(); + separatorNeeded = false; + } + + int newId = insertItem(iconset, groupCaption, m, id++); + entryMap_.insert(newId, static_cast<KSycocaEntry*>(g)); + // We have to delete the sub menu our selves! (See Qt docs.) + subMenus.append(m); + } + else if (e->isType(KST_KService)) + { + if (separatorNeeded) + { + insertSeparator(); + separatorNeeded = false; + } + + KService::Ptr s(static_cast<KService *>(e)); + insertMenuItem(s, id++, -1, &suppressGenericNames); + } + else if (e->isType(KST_KServiceSeparator)) + { + separatorNeeded = true; + } + } +#if 0 + // WABA: tear off handles don't work together with dynamically updated + // menus. We can't update the menu while torn off, and we don't know + // when it is torn off. + if ( count() > 0 && !relPath_.isEmpty() ) + if (KGlobalSettings::insertTearOffHandle()) + insertTearOffHandle(); +#endif +} + +void PanelServiceMenu::clearSubmenus() +{ + for (PopupMenuList::const_iterator it = subMenus.constBegin(); + it != subMenus.constEnd(); + ++it) + { + delete *it; + } + subMenus.clear(); +} + +void PanelServiceMenu::doInitialize() +{ + + // Set the startposition outside the panel, so there is no drag initiated + // when we use drag and click to select items. A drag is only initiated when + // you click to open the menu, and then press and drag an item. + startPos_ = QPoint(-1,-1); + + // We ask KSycoca to give us all services (sorted). + KServiceGroup::Ptr root = KServiceGroup::group(relPath_); + + if (!root || !root->isValid()) + return; + + KServiceGroup::List list = root->entries(true, excludeNoDisplay_, true, KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly); + + if (list.isEmpty()) { + setItemEnabled(insertItem(i18n("No Entries")), false); + return; + } + + int id = serviceMenuStartId(); + + if (addmenumode_) { + int mid = insertItem(KickerLib::menuIconSet("ok"), i18n("Add This Menu"), id++); + entryMap_.insert(mid, static_cast<KSycocaEntry*>(root)); + + if (relPath_ == "") + { + insertItem(KickerLib::menuIconSet("exec"), i18n("Add Non-KDE Application"), + this, SLOT(addNonKDEApp())); + } + + if (list.count() > 0) { + insertSeparator(); + id++; + } + } + if ( !insertInlineHeader_.isEmpty() ) + { + int mid = insertItem(new PopupMenuTitle(insertInlineHeader_, font()), -1, 0); + setItemEnabled( mid, false ); + } + fillMenu( root, list, relPath_, id ); +} + +void PanelServiceMenu::configChanged() +{ + deinitialize(); +} + +void PanelServiceMenu::insertMenuItem(KService::Ptr & s, int nId, + int nIndex/*= -1*/, + const QStringList *suppressGenericNames /* = 0 */, + const QString & aliasname) +{ + QString serviceName = (aliasname.isEmpty() ? s->name() : aliasname).simplifyWhiteSpace(); + QString comment = s->genericName().simplifyWhiteSpace(); + + if (!comment.isEmpty()) + { + if (KickerSettings::menuEntryFormat() == KickerSettings::NameAndDescription) + { + if ((!suppressGenericNames || + !suppressGenericNames->contains(s->untranslatedGenericName())) && + serviceName.find(comment, 0, true) == -1) + { + if (comment.find(serviceName, 0, true) == -1) + { + serviceName = i18n("Entries in K-menu: %1 app name, %2 description", "%1 - %2").arg(serviceName, comment); + } + else + { + serviceName = comment; + } + } + } + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName) + { + serviceName = i18n("Entries in K-menu: %1 description, %2 app name", "%1 (%2)").arg(comment, serviceName); + } + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly) + { + serviceName = comment; + } + } + + // restrict menu entries to a sane length + if ( serviceName.length() > 60 ) { + serviceName.truncate( 57 ); + serviceName += "..."; + } + + // check for NoDisplay + if (s->noDisplay()) + return; + + // ignore dotfiles. + if ((serviceName.at(0) == '.')) + return; + + // item names may contain ampersands. To avoid them being converted + // to accelerators, replace them with two ampersands. + serviceName.replace("&", "&&"); + + int newId = insertItem(KickerLib::menuIconSet(s->icon()), serviceName, nId, nIndex); + entryMap_.insert(newId, static_cast<KSycocaEntry*>(s)); +} + +void PanelServiceMenu::activateParent(const QString &child) +{ + PanelServiceMenu *parentMenu = dynamic_cast<PanelServiceMenu*>(parent()); + if (parentMenu) + { + parentMenu->activateParent(relPath_); + } + else + { + PanelPopupButton *kButton = MenuManager::the()->findKButtonFor(this); + if (kButton) + { + adjustSize(); + kButton->showMenu(); + } + else + { + show(); + } + } + + if (!child.isEmpty()) + { + EntryMap::Iterator mapIt; + for ( mapIt = entryMap_.begin(); mapIt != entryMap_.end(); ++mapIt ) + { + KServiceGroup *g = dynamic_cast<KServiceGroup *>(static_cast<KSycocaEntry*>(mapIt.data())); + + // if the dynamic_cast fails, we are looking at a KService entry + if (g && (g->relPath() == child)) + { + activateItemAt(indexOf(mapIt.key())); + return; + } + } + } +} + +bool PanelServiceMenu::highlightMenuItem( const QString &menuItemId ) +{ + initialize(); + + // Check menu itself + EntryMap::Iterator mapIt; + for ( mapIt = entryMap_.begin(); mapIt != entryMap_.end(); ++mapIt ) + { + // Skip recent files menu + if (mapIt.key() >= serviceMenuEndId()) + { + continue; + } + KService *s = dynamic_cast<KService *>( + static_cast<KSycocaEntry*>(mapIt.data())); + if (s && (s->menuId() == menuItemId)) + { + activateParent(QString::null); + int index = indexOf(mapIt.key()); + setActiveItem(index); + + // Warp mouse pointer to location of active item + QRect r = itemGeometry(index); + QCursor::setPos(mapToGlobal(QPoint(r.x()+ r.width() - 15, + r.y() + r.height() - 5))); + return true; + } + } + + for(PopupMenuList::iterator it = subMenus.begin(); + it != subMenus.end(); + ++it) + { + PanelServiceMenu *serviceMenu = dynamic_cast<PanelServiceMenu*>(*it); + if (serviceMenu && serviceMenu->highlightMenuItem(menuItemId)) + return true; + } + return false; +} + +void PanelServiceMenu::slotExec(int id) +{ + if (!entryMap_.contains(id)) + { + return; + } + + KSycocaEntry * e = entryMap_[id]; + + kapp->propagateSessionManager(); + + KService::Ptr service = static_cast<KService *>(e); + KApplication::startServiceByDesktopPath(service->desktopEntryPath(), + QStringList(), 0, 0, 0, "", true); + + updateRecentlyUsedApps(service); + startPos_ = QPoint(-1,-1); +} + +void PanelServiceMenu::mousePressEvent(QMouseEvent * ev) +{ + startPos_ = ev->pos(); + KPanelMenu::mousePressEvent(ev); +} + +void PanelServiceMenu::mouseReleaseEvent(QMouseEvent * ev) +{ + if (ev->button() == RightButton && !Kicker::the()->isKioskImmutable()) + { + int id = idAt( ev->pos() ); + + if (id < serviceMenuStartId()) + { + return; + } + + if (!entryMap_.contains(id)) + { + kdDebug(1210) << "Cannot find service with menu id " << id << endl; + return; + } + + contextKSycocaEntry_ = entryMap_[id]; + + delete popupMenu_; + popupMenu_ = new KPopupMenu(this); + connect(popupMenu_, SIGNAL(activated(int)), SLOT(slotContextMenu(int))); + bool hasEntries = false; + + switch (contextKSycocaEntry_->sycocaType()) + { + case KST_KService: + if (kapp->authorize("editable_desktop_icons")) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("desktop"), + i18n("Add Item to Desktop"), AddItemToDesktop); + } + if (kapp->authorizeKAction("kicker_rmb") && !Kicker::the()->isImmutable()) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("kicker"), + i18n("Add Item to Main Panel"), AddItemToPanel); + } + if (kapp->authorizeKAction("menuedit")) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("kmenuedit"), + i18n("Edit Item"), EditItem); + } + if (kapp->authorize("run_command")) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("run"), + i18n("Put Into Run Dialog"), PutIntoRunDialog); + } + break; + + case KST_KServiceGroup: + if (kapp->authorize("editable_desktop_icons")) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("desktop"), + i18n("Add Menu to Desktop"), AddMenuToDesktop); + } + if (kapp->authorizeKAction("kicker_rmb") && !Kicker::the()->isImmutable()) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("kicker"), + i18n("Add Menu to Main Panel"), AddMenuToPanel); + } + if (kapp->authorizeKAction("menuedit")) + { + hasEntries = true; + popupMenu_->insertItem(SmallIconSet("kmenuedit"), + i18n("Edit Menu"), EditMenu); + } + break; + + default: + break; + } + + if (hasEntries) + { + popupMenu_->popup(this->mapToGlobal(ev->pos())); + return; + } + } + + delete popupMenu_; + popupMenu_ = 0; + + KPanelMenu::mouseReleaseEvent(ev); +} + +extern int kicker_screen_number; + +void PanelServiceMenu::slotContextMenu(int selected) +{ + KProcess *proc; + KService::Ptr service; + KServiceGroup::Ptr g; + QByteArray ba; + QDataStream ds(ba, IO_WriteOnly); + + KURL src,dest; + KIO::CopyJob *job; + KDesktopFile *df; + + switch (selected) { + case AddItemToDesktop: + service = static_cast<KService *>(contextKSycocaEntry_); + + src.setPath( KGlobal::dirs()->findResource( "apps", service->desktopEntryPath() ) ); + dest.setPath( KGlobalSettings::desktopPath() ); + dest.setFileName( src.fileName() ); + + job = KIO::copyAs( src, dest ); + job->setDefaultPermissions( true ); + break; + + case AddItemToPanel: { + QCString appname = "kicker"; + if ( kicker_screen_number ) + appname.sprintf("kicker-screen-%d", kicker_screen_number); + service = static_cast<KService *>(contextKSycocaEntry_); + kapp->dcopClient()->send(appname, "Panel", "addServiceButton(QString)", service->desktopEntryPath()); + break; + } + + case EditItem: + proc = new KProcess(this); + *proc << KStandardDirs::findExe(QString::fromLatin1("kmenuedit")); + *proc << "/"+relPath_ << static_cast<KService *>(contextKSycocaEntry_)->menuId(); + proc->start(); + break; + + case PutIntoRunDialog: { + close(); + QCString appname = "kdesktop"; + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + service = static_cast<KService *>(contextKSycocaEntry_); + kapp->updateRemoteUserTimestamp( appname ); + kapp->dcopClient()->send(appname, "default", "popupExecuteCommand(QString)", service->exec()); + break; + } + + case AddMenuToDesktop: + g = static_cast<KServiceGroup *>(contextKSycocaEntry_); + dest.setPath( KGlobalSettings::desktopPath() ); + dest.setFileName( g->caption() ); + + df = new KDesktopFile( dest.path() ); + df->writeEntry( "Icon", g->icon() ); + df->writePathEntry( "URL", "programs:/"+g->name() ); + df->writeEntry( "Name", g->caption() ); + df->writeEntry( "Type", "Link" ); + df->sync(); + delete df; + + break; + + case AddMenuToPanel: { + QCString appname = "kicker"; + if ( kicker_screen_number ) + appname.sprintf("kicker-screen-%d", kicker_screen_number); + + g = static_cast<KServiceGroup *>(contextKSycocaEntry_); + ds << "foo" << g->relPath(); + kapp->dcopClient()->send("kicker", "Panel", "addServiceMenuButton(QString,QString)", ba); + break; + } + + case EditMenu: + proc = new KProcess(this); + *proc << KStandardDirs::findExe(QString::fromLatin1("kmenuedit")); + *proc << "/"+static_cast<KServiceGroup *>(contextKSycocaEntry_)->relPath(); + proc->start(); + break; + + default: + break; + } +} + +void PanelServiceMenu::mouseMoveEvent(QMouseEvent * ev) +{ + KPanelMenu::mouseMoveEvent(ev); + + if (Kicker::the()->isKioskImmutable()) + return; + + if ( (ev->state() & LeftButton ) != LeftButton ) + return; + + QPoint p = ev->pos() - startPos_; + if (p.manhattanLength() <= QApplication::startDragDistance() ) + return; + + int id = idAt(startPos_); + + // Don't drag items we didn't create. + if (id < serviceMenuStartId()) + return; + + if (!entryMap_.contains(id)) { + kdDebug(1210) << "Cannot find service with menu id " << id << endl; + return; + } + + KSycocaEntry * e = entryMap_[id]; + + QPixmap icon; + KURL url; + + switch (e->sycocaType()) { + + case KST_KService: + { + icon = static_cast<KService *>(e)->pixmap(KIcon::Small); + QString filePath = static_cast<KService *>(e)->desktopEntryPath(); + if (filePath[0] != '/') + { + filePath = locate("apps", filePath); + } + url.setPath(filePath); + break; + } + + case KST_KServiceGroup: + { + icon = KGlobal::iconLoader() + ->loadIcon(static_cast<KServiceGroup *>(e)->icon(), KIcon::Small); + url = "programs:/" + static_cast<KServiceGroup *>(e)->relPath(); + break; + } + + default: + { + return; + break; + } + } + + // If the path to the desktop file is relative, try to get the full + // path from KStdDirs. + + KURLDrag *d = new KURLDrag(KURL::List(url), this); + connect(d, SIGNAL(destroyed()), this, SLOT(slotDragObjectDestroyed())); + d->setPixmap(icon); + d->dragCopy(); + + // Set the startposition outside the panel, so there is no drag initiated + // when we use drag and click to select items. A drag is only initiated when + // you click to open the menu, and then press and drag an item. + startPos_ = QPoint(-1,-1); +} + +void PanelServiceMenu::dragEnterEvent(QDragEnterEvent *event) +{ + // Set the DragObject's target to this widget. This is needed because the + // widget doesn't accept drops, but we want to determine if the drag object + // is dropped on it. This avoids closing on accidental drags. If this + // widget accepts drops in the future, these lines can be removed. + if (event->source() == this) + { + KURLDrag::setTarget(this); + } + event->ignore(); +} + +void PanelServiceMenu::dragLeaveEvent(QDragLeaveEvent *) +{ + // see PanelServiceMenu::dragEnterEvent why this is nescessary + if (!frameGeometry().contains(QCursor::pos())) + { + KURLDrag::setTarget(0); + } +} + +void PanelServiceMenu::slotDragObjectDestroyed() +{ + if (KURLDrag::target() != this) + { + // we need to re-enter the event loop before calling close() here + // this gets called _before_ the drag object is destroyed, so we are + // still in its event loop. closing the menu before that event loop is + // exited may result in getting hung up in it which in turn prevents + // the execution of any code after the original exec() statement + // though the panels themselves continue on otherwise normally + // (we just have some sort of nested event loop) + QTimer::singleShot(0, this, SLOT(close())); + } +} + +PanelServiceMenu *PanelServiceMenu::newSubMenu(const QString & label, const QString & relPath, + QWidget * parent, const char * name, const QString& _inlineHeader) +{ + return new PanelServiceMenu(label, relPath, parent, name, false,_inlineHeader); +} + +void PanelServiceMenu::slotClearOnClose() +{ + if (!initialized()) return; + + if (!isVisible()){ + clearOnClose_ = false; + slotClear(); + } else { + clearOnClose_ = true; + } +} + +void PanelServiceMenu::slotClose() +{ + if (clearOnClose_) + { + clearOnClose_ = false; + slotClear(); + } + + delete popupMenu_; + popupMenu_ = 0; +} + +void PanelServiceMenu::slotClear() +{ + if (isVisible()) + { + // QPopupMenu's aboutToHide() is emitted before the popup is really hidden, + // and also before a click in the menu is handled, so do the clearing + // only after that has been handled + QTimer::singleShot(100, this, SLOT(slotClear())); + return; + } + + entryMap_.clear(); + KPanelMenu::slotClear(); + + for (PopupMenuList::iterator it = subMenus.begin(); + it != subMenus.end(); + ++it) + { + delete *it; + } + subMenus.clear(); +} + +void PanelServiceMenu::selectFirstItem() +{ + setActiveItem(indexOf(serviceMenuStartId())); +} + +// updates "recent" section of KMenu +void PanelServiceMenu::updateRecentlyUsedApps(KService::Ptr &service) +{ + QString strItem(service->desktopEntryPath()); + + // don't add an item from root kmenu level + if (!strItem.contains('/')) + { + return; + } + + // add it into recent apps list + RecentlyLaunchedApps::the().appLaunched(strItem); + RecentlyLaunchedApps::the().save(); + RecentlyLaunchedApps::the().m_bNeedToUpdate = true; +} + diff --git a/kicker/kicker/ui/service_mnu.h b/kicker/kicker/ui/service_mnu.h new file mode 100644 index 000000000..9e28acd3f --- /dev/null +++ b/kicker/kicker/ui/service_mnu.h @@ -0,0 +1,129 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef SERVICE_MENU_H +#define SERVICE_MENU_H + +#include <qmap.h> +#include <qvaluevector.h> + +#include <ksycocaentry.h> +#include <kservice.h> +#include <kpanelmenu.h> +#include <kservicegroup.h> +/** + * PanelServiceMenu is filled with KDE services and service groups. The sycoca + * database is queried and the hierarchical structure built by creating child + * menus of type PanelServiceMenu, so the creation is recursive. + * + * The entries are sorted alphabetically and groups come before services. + * + * @author Rik Hemsley <rik@kde.org> + */ + +typedef QMap<int, KSycocaEntry::Ptr> EntryMap; +typedef QValueVector<QPopupMenu*> PopupMenuList; + +class KDE_EXPORT PanelServiceMenu : public KPanelMenu +{ + Q_OBJECT + +public: + PanelServiceMenu(const QString & label, const QString & relPath, + QWidget* parent = 0, const char* name = 0, + bool addmenumode = false, + const QString &insertInlineHeader = QString::null); + + virtual ~PanelServiceMenu(); + + QString relPath() { return relPath_; } + + void setExcludeNoDisplay( bool flag ); + + virtual void showMenu(); + bool highlightMenuItem( const QString &menuId ); + void selectFirstItem(); + +private: + void fillMenu( KServiceGroup::Ptr &_root, KServiceGroup::List &_list, + const QString &_relPath, int & id ); + +protected slots: + virtual void initialize(); + virtual void slotExec(int id); + virtual void slotClearOnClose(); + virtual void slotClear(); + virtual void configChanged(); + virtual void slotClose(); + void slotDragObjectDestroyed(); + + // for use in Add Applicaton To Panel + virtual void addNonKDEApp() {} + +protected: + void insertMenuItem(KService::Ptr & s, int nId, int nIndex = -1, + const QStringList *suppressGenericNames=0, + const QString &aliasname = QString::null); + virtual PanelServiceMenu * newSubMenu(const QString & label, + const QString & relPath, + QWidget * parent, const char * name, + const QString & _inlineHeader = + QString::null); + + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + virtual void updateRecentlyUsedApps(KService::Ptr &s); + void activateParent(const QString &child); + int serviceMenuStartId() { return 4242; } + int serviceMenuEndId() { return 5242; } + virtual void clearSubmenus(); + void doInitialize(); + + QString relPath_; + + EntryMap entryMap_; + + bool loaded_; + bool excludeNoDisplay_; + QString insertInlineHeader_; + QPopupMenu * opPopup_; + bool clearOnClose_; + bool addmenumode_; + QPoint startPos_; + PopupMenuList subMenus; + +private slots: + void slotContextMenu(int); + +private: + enum ContextMenuEntry { AddItemToPanel, EditItem, AddMenuToPanel, EditMenu, + AddItemToDesktop, AddMenuToDesktop, PutIntoRunDialog }; + KPopupMenu* popupMenu_; + KSycocaEntry* contextKSycocaEntry_; + void readConfig(); + }; + +#endif // SERVICE_MENU_H diff --git a/kicker/libkicker/Makefile.am b/kicker/libkicker/Makefile.am new file mode 100644 index 000000000..5ec65be46 --- /dev/null +++ b/kicker/libkicker/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = $(all_includes) + +lib_LTLIBRARIES = libkickermain.la + +libkickermain_la_SOURCES = appletinfo.cpp global.cpp kickertip.cpp \ + menuinfo.cpp panelbutton.cpp panner.cpp \ + kickerSettings.kcfgc kshadowsettings.cpp \ + kshadowengine.cpp paneldrag.cpp \ + simplebutton.cpp + +libkickermain_la_METASOURCES = AUTO + +libkickermain_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined +libkickermain_la_LIBADD = $(LIB_KIO) + +kde_kcfg_DATA = kickerSettings.kcfg + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/libkicker.pot diff --git a/kicker/libkicker/appletinfo.cpp b/kicker/libkicker/appletinfo.cpp new file mode 100644 index 000000000..cfb626fac --- /dev/null +++ b/kicker/libkicker/appletinfo.cpp @@ -0,0 +1,112 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qfileinfo.h> +#include <kdesktopfile.h> +#include <kapplication.h> + +#include "appletinfo.h" + +AppletInfo::AppletInfo( const QString& deskFile, const QString& configFile, const AppletInfo::AppletType type) + : m_type (type), + m_unique(true), + m_hidden(false) +{ + QFileInfo fi(deskFile); + m_desktopFile = fi.fileName(); + + const char* resource = "applets"; + switch (type) + { + case Extension: + resource = "extensions"; + break; + case BuiltinButton: + resource = "builtinbuttons"; + break; + case SpecialButton: + resource = "specialbuttons"; + break; + case Undefined: + case Applet: + default: + break; + } + + KDesktopFile df(m_desktopFile, true, resource); + + // set the appletssimple attributes + setName(df.readName()); + setComment(df.readComment()); + setIcon(df.readIcon()); + + // library + setLibrary(df.readEntry("X-KDE-Library")); + + // is it a unique applet? + setIsUnique(df.readBoolEntry("X-KDE-UniqueApplet", false)); + + // should it be shown in the gui? + m_hidden = df.readBoolEntry("Hidden", false); + + if (configFile.isEmpty()) + { + // generate a config file base name from the library name + m_configFile = m_lib.lower(); + + if (m_unique) + { + m_configFile.append("rc"); + } + else + { + m_configFile.append("_") + .append(kapp->randomString(20).lower()) + .append("_rc"); + } + } + else + { + m_configFile = configFile; + } +} + +bool AppletInfo::operator!=( const AppletInfo& rhs) const +{ + return configFile() != rhs.configFile(); +} + +bool AppletInfo::operator<( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) < 0 ); +} + +bool AppletInfo::operator> ( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) > 0 ); +} + +bool AppletInfo::operator<= ( const AppletInfo& rhs ) const +{ + return ( QString::localeAwareCompare( name(), rhs.name() ) <= 0 ); +} diff --git a/kicker/libkicker/appletinfo.h b/kicker/libkicker/appletinfo.h new file mode 100644 index 000000000..b9ab187ba --- /dev/null +++ b/kicker/libkicker/appletinfo.h @@ -0,0 +1,92 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __appletinfo_h__ +#define __appletinfo_h__ + +#include <qmap.h> +#include <qptrlist.h> +#include <qstring.h> +#include <qvaluevector.h> + +#include <kdemacros.h> + +class KDE_EXPORT AppletInfo +{ + public: + typedef QValueVector<AppletInfo> List; + typedef QMap<QObject*, AppletInfo*> Dict; + + enum AppletType { Undefined = 0, + Applet = 1, + BuiltinButton = 2, + SpecialButton = 4, + Extension = 8, + Button = BuiltinButton | SpecialButton }; + + AppletInfo(const QString& desktopFile = QString::null, + const QString& configFile = QString::null, + const AppletType type = Undefined); + + QString name() const { return m_name; } + QString comment() const { return m_comment; } + QString icon() const { return m_icon; } + + AppletType type() const { return m_type; } + + QString library() const { return m_lib; } + QString desktopFile() const { return m_desktopFile; } + QString configFile() const { return m_configFile; } + + bool isUniqueApplet() const { return m_unique; } + bool isHidden() const { return m_hidden; } + + void setConfigFile(QString cf) { m_configFile = cf; } + + bool operator<(const AppletInfo& rhs) const; + bool operator>(const AppletInfo& rhs) const; + bool operator<=(const AppletInfo& rhs) const; + bool operator!=(const AppletInfo& rhs) const; + + void setType(AppletType type) { m_type = type; } + + protected: + void setName(QString name) { m_name = name; } + void setComment(QString comment) { m_comment = comment; } + void setIcon(QString icon) { m_icon = icon; } + void setLibrary(QString lib) { m_lib = lib; } + void setIsUnique(bool u) { m_unique = u; } + + private: + QString m_name; + QString m_comment; + QString m_icon; + QString m_lib; + QString m_desktopFile; + QString m_configFile; + AppletType m_type; + bool m_unique; + bool m_hidden; +}; + +#endif diff --git a/kicker/libkicker/global.cpp b/kicker/libkicker/global.cpp new file mode 100644 index 000000000..1f393616d --- /dev/null +++ b/kicker/libkicker/global.cpp @@ -0,0 +1,477 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qbitmap.h> +#include <qfile.h> +#include <qpopupmenu.h> +#include <qregexp.h> +#include <qpainter.h> + +#include <kiconeffect.h> +#include <kiconloader.h> +#include <kio/netaccess.h> +#include <kstandarddirs.h> +#include <kservice.h> + +#include "global.h" +#include "kickerSettings.h" + +namespace KickerLib +{ + +KPanelExtension::Position directionToPosition(KPanelApplet::Direction d ) +{ + switch (d) + { + case KPanelApplet::Down: + return KPanelExtension::Top; + break; + + case KPanelApplet::Left: + return KPanelExtension::Right; + break; + + case KPanelApplet::Right: + return KPanelExtension::Left; + break; + + case KPanelApplet::Up: + default: + return KPanelExtension::Bottom; + break; + } +} + +KPanelExtension::Position directionToPopupPosition(KPanelApplet::Direction d) +{ + switch (d) + { + case KPanelApplet::Up: + return KPanelExtension::Top; + break; + + case KPanelApplet::Down: + return KPanelExtension::Bottom; + break; + + case KPanelApplet::Left: + return KPanelExtension::Left; + break; + + case KPanelApplet::Right: + default: + return KPanelExtension::Right; + break; + } +} + +KPanelApplet::Direction positionToDirection(KPanelExtension::Position p) +{ + switch (p) + { + case KPanelExtension::Top: + return KPanelApplet::Down; + break; + + case KPanelExtension::Right: + return KPanelApplet::Left; + break; + + case KPanelExtension::Left: + return KPanelApplet::Right; + break; + + case KPanelExtension::Bottom: + default: + return KPanelApplet::Up; + break; + } +} + +KPanelApplet::Direction arrowToDirection(Qt::ArrowType p) +{ + switch (p) + { + case Qt::DownArrow: + return KPanelApplet::Down; + break; + + case Qt::LeftArrow: + return KPanelApplet::Left; + break; + + case Qt::RightArrow: + return KPanelApplet::Right; + break; + + case Qt::UpArrow: + default: + return KPanelApplet::Up; + break; + } +} + +int sizeValue(KPanelExtension::Size s) +{ + switch (s) + { + case KPanelExtension::SizeTiny: + return 24; + break; + + case KPanelExtension::SizeSmall: + return 30; + break; + + case KPanelExtension::SizeNormal: + return 46; + break; + + case KPanelExtension::SizeLarge: + default: + return 58; + break; + } +} + +int maxButtonDim() +{ + return (2 * KickerSettings::iconMargin()) + KIcon::SizeLarge; +} + +QString newDesktopFile(const KURL& url) +{ + QString base = url.fileName(); + if (base.endsWith(".desktop")) + base.truncate(base.length()-8); + QRegExp r("(.*)(?=-\\d+)"); + if (r.search(base) > -1) + base = r.cap(1); + + QString file = base + ".desktop"; + + for(int n = 1; ++n; ) + { + QString path = locate("appdata", file); + if (path.isEmpty()) + break; + + file = QString("%2-%1.desktop").arg(n).arg(base); + } + file = locateLocal("appdata", file); + return file; +} + +QString copyDesktopFile(const KURL& url) +{ + QString file = newDesktopFile(url); + KURL dest; + dest.setPath(file); + KIO::NetAccess::upload(url.path(), dest, 0); + return file; +} + +QPopupMenu* reduceMenu(QPopupMenu *menu) +{ + if (menu->count() != 1) + { + return menu; + } + + QMenuItem *item = menu->findItem(menu->idAt(0)); + + if (item->popup()) + { + return reduceMenu(item->popup()); + } + + return menu; +} + +QPoint popupPosition(KPanelApplet::Direction d, + const QWidget* popup, + const QWidget* source, + const QPoint& offset) +{ + QRect r; + if (source->isTopLevel()) + { + r = source->geometry(); + } + else + { + r = QRect(source->mapToGlobal(QPoint(0, 0)), + source->mapToGlobal(QPoint(source->width(), source->height()))); + + switch (d) + { + case KPanelApplet::Left: + case KPanelApplet::Right: + r.setLeft( source->topLevelWidget()->x() ); + r.setWidth( source->topLevelWidget()->width() ); + break; + case KPanelApplet::Up: + case KPanelApplet::Down: + r.setTop( source->topLevelWidget()->y() ); + r.setHeight( source->topLevelWidget()->height() ); + break; + } + } + + switch (d) + { + case KPanelApplet::Left: + case KPanelApplet::Right: + { + QDesktopWidget* desktop = QApplication::desktop(); + QRect screen = desktop->screenGeometry(desktop->screenNumber(const_cast<QWidget*>(source))); + int x = (d == KPanelApplet::Left) ? r.left() - popup->width() : + r.right() + 1; + int y = r.top() + offset.y(); + + // try to keep this on screen + if (y + popup->height() > screen.bottom()) + { + y = r.bottom() - popup->height() + offset.y(); + + if (y < screen.top()) + { + y = screen.bottom() - popup->height(); + + if (y < screen.top()) + { + y = screen.top(); + } + } + } + + return QPoint(x, y); + } + case KPanelApplet::Up: + case KPanelApplet::Down: + default: + { + int x = 0; + int y = (d == KPanelApplet::Up) ? r.top() - popup->height() : + r.bottom() + 1; + + if (QApplication::reverseLayout()) + { + x = r.right() - popup->width() + 1; + + if (offset.x() > 0) + { + x -= r.width() - offset.x(); + } + + // try to keep this on the screen + if (x - popup->width() < 0) + { + x = r.left(); + } + + return QPoint(x, y); + } + else + { + QDesktopWidget* desktop = QApplication::desktop(); + QRect screen = desktop->screenGeometry(desktop->screenNumber(const_cast<QWidget*>(source))); + x = r.left() + offset.x(); + + // try to keep this on the screen + if (x + popup->width() > screen.right()) + { + x = r.right() - popup->width() + 1 + offset.x(); + + if (x < screen.left()) + { + x = screen.left(); + } + } + } + + return QPoint(x, y); + } + } +} + +void colorize(QImage& image) +{ + KConfig *config = KGlobal::config(); + config->setGroup("WM"); + QColor color = QApplication::palette().active().highlight(); + QColor activeTitle = config->readColorEntry("activeBackground", &color); + QColor inactiveTitle = config->readColorEntry("inactiveBackground", &color); + + // figure out which color is most suitable for recoloring to + int h1, s1, v1, h2, s2, v2, h3, s3, v3; + activeTitle.hsv(&h1, &s1, &v1); + inactiveTitle.hsv(&h2, &s2, &v2); + QApplication::palette().active().background().hsv(&h3, &s3, &v3); + + if ( (kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < kAbs(h2-h3)+kAbs(s2-s3)+kAbs(v2-v3)) && + ((kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < 32) || (s1 < 32)) && (s2 > s1)) + color = inactiveTitle; + else + color = activeTitle; + + // limit max/min brightness + int r, g, b; + color.rgb(&r, &g, &b); + int gray = qGray(r, g, b); + if (gray > 180) { + r = (r - (gray - 180) < 0 ? 0 : r - (gray - 180)); + g = (g - (gray - 180) < 0 ? 0 : g - (gray - 180)); + b = (b - (gray - 180) < 0 ? 0 : b - (gray - 180)); + } else if (gray < 76) { + r = (r + (76 - gray) > 255 ? 255 : r + (76 - gray)); + g = (g + (76 - gray) > 255 ? 255 : g + (76 - gray)); + b = (b + (76 - gray) > 255 ? 255 : b + (76 - gray)); + } + color.setRgb(r, g, b); + KIconEffect::colorize(image, color, 1.0); +} + +QColor blendColors(const QColor& c1, const QColor& c2) +{ + int r1, g1, b1; + int r2, g2, b2; + + c1.rgb(&r1, &g1, &b1); + c2.rgb(&r2, &g2, &b2); + + r1 += (int) (.5 * (r2 - r1)); + g1 += (int) (.5 * (g2 - g1)); + b1 += (int) (.5 * (b2 - b1)); + + return QColor(r1, g1, b1); +} + +QColor shadowColor(const QColor& c) +{ + int r = c.red(); + int g = c.green(); + int b = c.blue(); + + if ( r < 128 ) + r = 255; + else + r = 0; + + if ( g < 128 ) + g = 255; + else + g = 0; + + if ( b < 128 ) + b = 255; + else + b = 0; + + return QColor( r, g, b ); +} + +QIconSet menuIconSet(const QString& icon) +{ + QIconSet iconset; + int iconSize = KickerSettings::menuEntryHeight(); + + if (iconSize < 0) + { + return iconset; + } + + if (icon != "unknown") + { + if (iconSize > 0) + { + iconset = KGlobal::iconLoader()->loadIconSet(icon, + KIcon::NoGroup, + iconSize, true); + } + else if (iconSize == 0) + { + QPixmap normal = KGlobal::iconLoader()->loadIcon(icon, + KIcon::Small, + 0, + KIcon::DefaultState, + 0, + true); + + QPixmap active = KGlobal::iconLoader()->loadIcon(icon, + KIcon::Small, + 0, + KIcon::ActiveState, + 0, + true); + + // make sure they are not larger than 20x20 + if (normal.width() > 20 || normal.height() > 20) + { + normal.convertFromImage(normal.convertToImage().smoothScale(20,20)); + } + + if (active.width() > 20 || active.height() > 20) + { + active.convertFromImage(active.convertToImage().smoothScale(20,20)); + } + + iconset.setPixmap(normal, QIconSet::Small, QIconSet::Normal); + iconset.setPixmap(active, QIconSet::Small, QIconSet::Active); + } + } + + if (iconset.isNull()) + { + QPixmap pix(iconSize, iconSize); + QBitmap map(iconSize, iconSize, true); + pix.setMask(map); + iconset = QIconSet(pix, pix); + } + + return iconset; +} + +void drawBlendedRect(QPainter *p, const QRect &r, const QColor &color, int alpha) +{ + static QPixmap pix; + static QColor last_color = Qt::black; + static int last_alpha = 0; + + if (pix.isNull() || last_color != color || last_alpha != alpha) + { + QImage img(16, 16, 32); + img.setAlphaBuffer(false); + img.fill(((uint)(alpha & 0xFF) << 24) | (color.rgb() & 0xFFFFFF)); + img.setAlphaBuffer(true); + pix.convertFromImage(img); + last_color = color; + last_alpha = alpha; + } + + p->drawTiledPixmap(r, pix); +} + +} // namespace + diff --git a/kicker/libkicker/global.h b/kicker/libkicker/global.h new file mode 100644 index 000000000..2b9449584 --- /dev/null +++ b/kicker/libkicker/global.h @@ -0,0 +1,112 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __pglobal_h__ +#define __pglobal_h__ + +#include <qiconset.h> +#include <qmap.h> + +#include <kpanelapplet.h> +#include <kpanelextension.h> +#include <kurl.h> + +namespace KickerLib +{ + +/* + * Functions to convert between various enums + */ +KDE_EXPORT KPanelExtension::Position directionToPosition(KPanelApplet::Direction d); +KDE_EXPORT KPanelExtension::Position directionToPopupPosition(KPanelApplet::Direction d); +KDE_EXPORT KPanelApplet::Direction positionToDirection(KPanelExtension::Position p); +KDE_EXPORT KPanelApplet::Direction arrowToDirection(Qt::ArrowType p); +KDE_EXPORT int sizeValue(KPanelExtension::Size s); + +/** + * Pixel sizes for but sizes and margins + */ +KDE_EXPORT int maxButtonDim(); + +/** + * Tint the image to reflect the current color scheme + * Used, for instance, by KMenu side bar + */ +KDE_EXPORT void colorize(QImage& image); + +/** + * Blend a color rectangle on a painter + */ +KDE_EXPORT void drawBlendedRect(QPainter *p, const QRect &r, const QColor &color = Qt::black, int alpha = 0x40); + +/** + * Blend two colours together to get a colour halfway in between + */ +KDE_EXPORT QColor blendColors(const QColor& c1, const QColor& c2); + +/** + * Create or copy .desktop files for use in kicker safely and easily + */ +KDE_EXPORT QString copyDesktopFile(const KURL&url); +KDE_EXPORT QString newDesktopFile(const KURL&url); + + +/** + * Reduces a popup menu + * + * When a popup menu contains only 1 sub-menu, it makes no sense to + * show this popup-menu but we better show the sub-menu directly. + * + * This function checks whether that is the case and returns either the + * original menu or the sub-menu when appropriate. + */ +KDE_EXPORT QPopupMenu *reduceMenu(QPopupMenu *); + + +/** + * Calculate the appropriate position for a popup menu based on the + * direction, the size of the menu, the widget geometry, and a optional + * point in the local coordinates of the widget. + */ +KDE_EXPORT QPoint popupPosition(KPanelApplet::Direction d, + const QWidget* popup, + const QWidget* source, + const QPoint& offset = QPoint(0, 0)); + +/** + * Calculate an acceptable inverse of the given color wich will be used + * as the shadow color. + */ +KDE_EXPORT QColor shadowColor(const QColor& c); + +/** + * Get an appropriate for a menu in Plasma. As the user may set this size + * globally, it is important to always use this method. + * @param icon the name of icon requested + * @return the icon set for the requested icon + */ +KDE_EXPORT QIconSet menuIconSet(const QString& icon); + +} + +#endif // __pglobal_h__ diff --git a/kicker/libkicker/kickerSettings.kcfg b/kicker/libkicker/kickerSettings.kcfg new file mode 100644 index 000000000..42f02bcad --- /dev/null +++ b/kicker/libkicker/kickerSettings.kcfg @@ -0,0 +1,342 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + +<include>kapplication.h</include> +<include>klocale.h</include> +<kcfgfile arg="true" /> + +<group name="General"> + +<entry name="Locked" type="Bool" > + <label>When this option is enabled, the panels may not be moved and items cannot be removed or added</label> + <default>false</default> + </entry> + +<entry name="ConserveSpace" type="Bool" > + <label>Enable conserve space</label> + <default>true</default> + </entry> + +<entry name="Transparent" type="Bool" > + <label>Enable transparency</label> + <whatsthis>When this option is enabled, the panel will become pseudo-transparent</whatsthis> + <default>false</default> + </entry> + +<entry name="MenubarPanelTransparent" type="Bool" > + <label>Enable transparency for menubar panel</label> + <whatsthis>When this option is enabled, the panel containing the menubar will become pseudo-transparent as well</whatsthis> + <default>false</default> + </entry> + +<entry name="UseBackgroundTheme" type="Bool" > + <label>Enable background image</label> + <whatsthis>When this option is enabled, the panel will display a tiled image as its background</whatsthis> + <default>true</default> + </entry> + +<entry name="ColorizeBackground" type="Bool" > + <label>Enable colourized background.</label> + <default>false</default> + </entry> + +<entry name="RotateBackground" type="Bool" > + <label>Rotate background</label> + <whatsthis>When this option is enabled, when the panel is placed on the side or top edges of the screen, the background image will be rotated to match the panel's orientation</whatsthis> + <default>true</default> + </entry> + +<entry name="BackgroundTheme" type="Path" > + <label>Background image</label> + <whatsthis>Here you can choose an image to be displayed on the panel. Press the 'browse' button to choose a theme using the file dialog. This option is only effective if 'Enable background image' is selected</whatsthis> + <default>wallpapers/default.png</default> + </entry> + +<entry name="TintValue" type="Int" > + <label>Controls the saturation level of the tint color used with transparent panels</label> + <default>33</default> + <min>0</min> + <max>100</max> + </entry> + +<entry name="TintColor" type="Color" > + <label>The tint color used to colorize transparent panels</label> + <default code="true">(QApplication::palette().active().mid())</default> + <whatsthis>This option sets the color to use when tinting transparent panels</whatsthis> + </entry> + +<entry name="UnhideLocation" type="Int"> + <label>Raise when the pointer touches the screen here</label> + <default>0</default> + </entry> + +<entry name="FadeOutAppletHandles" type="Bool"> + <label>Fade out applet handles</label> + <default>true</default> + <whatsthis>Select this option to make applet handles only visible on mouse hover. Applet handles let you move, remove and configure applets.</whatsthis> + </entry> + +<entry name="HideAppletHandles" type="Bool"> + <label>Hide applet handles</label> + <default>false</default> + <whatsthis>Select this option to always hide the applet handles. Beware this could disable moving, removing or configuring some applets.</whatsthis> + </entry> + +<entry name="ShowToolTips" type="Bool" > + <label>Show informational tooltips</label> + <default>true</default> + </entry> + +<entry name="UntrustedApplets" type="StringList"> + <label>A list of applets that have been loaded at runtime. In the case of a crash these applets will not be loaded at the next Kicker start, in case they caused the crash</label> + </entry> + +<entry name="UntrustedExtensions" type="StringList"> + <label>A list of extensions that have been loaded at runtime. In the case of a crash these extensions will not be loaded at the next Kicker start, in case they caused the crash</label> + </entry> + +</group> + +<group name="menus"> + + <entry name="MenuEntryFormat" type="Enum" > + <choices> + <choice name="NameOnly"> + <label>Show simple menu entries</label> + </choice> + <choice name="NameAndDescription"> + <label>Show names first on detailed entries</label> + </choice> + <choice name="DescriptionOnly"> + <label>Show only description for menu entries</label> + </choice> + <choice name="DescriptionAndName"> + <label>Show detailed menu entries</label> + </choice> + </choices> + <default>DescriptionAndName</default> + <label>Formation of the menu entry text</label> + </entry> + +<entry name="ShowMenuTitles" type="Bool" > + <label>Show section titles in Kmenu</label> + <default>true</default> + </entry> + +<entry name="MenuEntryHeight" type="Int" > + <label>Height of menu entries in pixels</label> + <default>0</default> + </entry> + +<entry name="ShowHiddenFiles" type="Bool" > + <label>Show hidden files in Quick Browser</label> + <default>false</default> + </entry> + +<entry name="MaxEntries2" type="UInt" > + <label>Maximum number of entries</label> + <default>30</default> + <min>1</min> + </entry> + +<entry name="UseBookmarks" type="Bool" > + <label>Show bookmarks in KMenu</label> + <default>false</default> + </entry> + +<entry name="UseBrowser" type="Bool" > + <label>Use the Quick Browser</label> + <default>false</default> + </entry> + +<entry name="MenuExtensions" key="Extensions" type="StringList" > + <label>Optional Menus</label> + <default>prefmenu.desktop,systemmenu.desktop</default> + </entry> + +<entry name="RecentAppsStat" type="StringList" > + <label>Recently used applications</label> + </entry> + +<entry name="NumVisibleEntries" type="UInt" > + <label>Number of visible entries</label> + <default>5</default> + <max>100</max> + </entry> + +<entry name="RecentVsOften" type="Bool" > + <label>Show most recently used applications rather than most frequently used</label> + <default>false</default> + </entry> + +</group> + +<group name="button_tiles"> + +<entry name="EnableKMenuTiles" type="Bool"> + <label>Enable a tile background image for the KMenu button</label> + <default>false</default> + </entry> + +<entry name="EnableDesktopButtonTiles" type="Bool"> + <label>Enable a tile background image for the Desktop button</label> + <default>false</default> + </entry> + +<entry name="EnableURLTiles" type="Bool" > + <label>Enable a tile background image for Application, URL and special buttons</label> + <default>false</default> + </entry> + +<entry name="EnableBrowserTiles" type="Bool" > + <label>Enable a tile background image for the Quick Browser button</label> + <default>false</default> + </entry> + +<entry name="EnableWindowListTiles" type="Bool" > + <label>Enable a tile background image for the Window List button</label> + <default>false</default> + </entry> + +<entry name="KMenuTile" type="Path" > + <label>Image tile for Kmenu button background</label> + </entry> + +<entry name="KMenuTileColor" type="Color" > + <label>Color to use for Kmenu button background</label> + <default code="true">QColor()</default> + </entry> + +<entry name="DesktopButtonTile" type="Path" > + <label>Image tile for Desktop button background</label> + </entry> + +<entry name="DesktopButtonTileColor" type="Color" > + <label>Color to use for Kmenu button background</label> + <default code="true">QColor()</default> + </entry> + +<entry name="URLTile" type="Path" > + <label>Image tile for Application, URL and special button backgrounds</label> + </entry> + +<entry name="URLTileColor" type="Color" > + <label>Color to use for Application, URL and special button backgrounds</label> + <default code="true">QColor()</default> + </entry> + +<entry name="BrowserTile" type="Path" > + <label>Image tile for Browser button background</label> + </entry> + +<entry name="BrowserTileColor" type="Color" > + <label>Color to use for Browser button background</label> + <default code="true">QColor()</default> + </entry> + +<entry name="WindowListTile" type="Path" > + <label>Image tile for Window List button background</label> + </entry> + +<entry name="WindowListTileColor" type="Color" > + <label>Color to use for Window List button background</label> + <default code="true">QColor()</default> + </entry> + +</group> + +<group name="KMenu" > + +<entry name="UseSidePixmap" type="Bool" > + <label>Use side image in Kmenu</label> + <default>true</default> + </entry> + +<entry name="SidePixmapName" key="SideName" type="String" > + <label>The name of the file to use as the side image in the K Menu</label> + <default>kside.png</default> + </entry> + +<entry name="SideTileName" key="SideTileName" type="String" > + <label>The name of the file used as a tile to fill the height of K Menu that SidePixmapName does not cover</label> + <default>kside_tile.png</default> + </entry> + +<entry name="ShowKMenuText" key="ShowText" type="Bool" > + <label>Show text on the K Menu button</label> + <default>false</default> + </entry> + +<entry name="KMenuText" key="Text" type="String" > + <label>Text to be shown on K Menu Button</label> + <default code="true">i18n("Applications")</default> + </entry> + +</group> + +<group name="buttons" > + +<entry name="ShowMouseOverEffects" key="EnableIconZoom" type="Bool" > + <label>Enable icon mouse over effects</label> + <default>true</default> + </entry> + +<entry name="MouseOversShowIcon" type="Bool" > + <label>Show icons in mouse over effects</label> + <default>true</default> + </entry> + +<entry name="MouseOversShowText" type="Bool" > + <label>Show text in mouse over effects</label> + <default>true</default> + </entry> + +<entry name="MouseOversSpeed" type="Int" > + <label>Controls how fast the tooltips fade in, measured in thousandths of a second</label> + <default>500</default> + <min>0</min> + </entry> + + <entry name="MouseOversShowDelay" type="UInt" > + <label>Mouse over effects are shown after the defined time (in milliseconds)</label> + <default>500</default> + </entry> + + <entry name="MouseOversHideDelay" type="UInt" > + <label>Mouse over effects are hidden after the defined time (in milliseconds)</label> + <default>200</default> + </entry> + +<entry name="EnableTileBackground" type="Bool" > + <label>Enable background tiles</label> + <default>false</default> + </entry> + +<entry name="IconMargin" key="IconMargin" type="Int" > + <label>The margin between panel icons and the panel border</label> + <default>3</default> + </entry> + +<entry name="RemoveButtonsWhenBroken" type="Bool" > + <label>Buttons that represent KServices (applications, primarily) watch for the removal of the service and delete themselves when this happens. This setting turns this off.</label> + <default>true</default> + </entry> + +<entry name="ButtonFont" key="Font" type="Font" > + <label>Font for the buttons with text.</label> + <default code="true">KGlobalSettings::generalFont()</default> + </entry> + +<entry name="ButtonTextColor" key="TextColor" type="Color" > + <label>Text color for the buttons.</label> + <default code="true">KGlobalSettings::textColor()</default> + </entry> + +</group> + +</kcfg> + + diff --git a/kicker/libkicker/kickerSettings.kcfgc b/kicker/libkicker/kickerSettings.kcfgc new file mode 100644 index 000000000..59c271928 --- /dev/null +++ b/kicker/libkicker/kickerSettings.kcfgc @@ -0,0 +1,8 @@ +File=kickerSettings.kcfg +Singleton=true +ClassName=KickerSettings +Mutators=true +Visibility=KDE_EXPORT +IncludeFiles=qapplication.h +GlobalEnums=true +MemberVariables=dpointer diff --git a/kicker/libkicker/kickertip.cpp b/kicker/libkicker/kickertip.cpp new file mode 100644 index 000000000..403641443 --- /dev/null +++ b/kicker/libkicker/kickertip.cpp @@ -0,0 +1,557 @@ +/***************************************************************** + +Copyright (c) 2004 Zack Rusin <zrusin@kde.org> + Sami Kyostil <skyostil@kempele.fi> + Aaron J. Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qpainter.h> +#include <qsimplerichtext.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <kdialog.h> + +#include "global.h" + +#include "kickertip.h" +#include "kickerSettings.h" + +// putting this #include higher results in compile errors +#include <netwm.h> + +static const int DEFAULT_FRAMES_PER_SECOND = 30; + +KickerTip* KickerTip::m_self = 0; +int KickerTip::m_tippingEnabled = 1; + +void KickerTip::Client::updateKickerTip() const +{ + if (KickerTip::the()->isTippingFor(dynamic_cast<const QWidget*>(this)) && + KickerTip::the()->isVisible()) + { + KickerTip::the()->display(); + } +} + +KickerTip* KickerTip::the() +{ + if (!m_self) + { + m_self = new KickerTip(0); + } + + return m_self; +} + +KickerTip::KickerTip(QWidget * parent) + : QWidget(parent, "animtt",WX11BypassWM), + m_richText(0), + m_mimeFactory(0), + m_dissolveSize(0), + m_dissolveDelta(-1), + m_direction(KPanelApplet::Up), + m_dirty(false), + m_toolTipsEnabled(KickerSettings::showToolTips()), + m_tippingFor(0) +{ + setFocusPolicy(NoFocus); + setBackgroundMode(NoBackground); + resize(0, 0); + hide(); + connect(&m_frameTimer, SIGNAL(timeout()), SLOT(internalUpdate())); +} + +KickerTip::~KickerTip() +{ + delete m_richText; + delete m_mimeFactory; +} + +void KickerTip::display() +{ + if (!tippingEnabled()) + { + return; + } + + { + // prevent tips from showing when the active window is fullscreened + NETRootInfo ri(qt_xdisplay(), NET::ActiveWindow); + NETWinInfo wi(qt_xdisplay(), ri.activeWindow(), ri.rootWindow(), NET::WMState); + if (wi.state() & NET::FullScreen) + { + return; + } + } + + QWidget *widget = const_cast<QWidget*>(m_tippingFor); + KickerTip::Client *client = dynamic_cast<KickerTip::Client*>(widget); + + if (!client) + { + return; + } + + // delete the mimefactory and create a new one so any old pixmaps used in the + // richtext area are freed but the mimefactory is ready to be added to in + // the call to updateKickerTip + delete m_mimeFactory; + m_mimeFactory = new QMimeSourceFactory(); + + // Declare interchange object and define defaults. + Data data; + data.maskEffect = Dissolve; + data.duration = 2000; + data.direction = KPanelApplet::Up; + data.mimeFactory = m_mimeFactory; + + // Tickle the information out of the bastard. + client->updateKickerTip(data); + + // Hide the tip if there is nothing to show + if (data.message.isEmpty() && data.subtext.isEmpty() && data.icon.isNull()) + { + hide(); + return; + } + + delete m_richText; + m_richText = new QSimpleRichText("<qt><h3>" + data.message + "</h3><p>" + + data.subtext + "</p></qt>", font(), QString::null, 0, + m_mimeFactory); + m_richText->setWidth(640); + m_direction = data.direction; + + if (KickerSettings::mouseOversShowIcon()) + { + m_icon = data.icon; + } + else if (KickerSettings::mouseOversShowText()) + { + m_icon = QPixmap(); + } + else + { + // don't bother since we have NOTHING to show + return; + } + + m_maskEffect = isVisible() ? Plain : data.maskEffect; + m_dissolveSize = 24; + m_dissolveDelta = -1; + + displayInternal(); + + m_frameTimer.start(1000 / DEFAULT_FRAMES_PER_SECOND); + + // close the message window after given mS + if (data.duration > 0) + { + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(hide())); + m_timer.start(data.duration, true); + } + else + { + m_timer.stop(); + } + + move(KickerLib::popupPosition(m_direction, this, m_tippingFor)); + show(); +} + +void KickerTip::paintEvent(QPaintEvent * e) +{ + if (m_dirty) + { + displayInternal(); + m_dirty = false; + } + + QPainter p(this); + p.drawPixmap(e->rect().topLeft(), m_pixmap, e->rect()); +} + +void KickerTip::mousePressEvent(QMouseEvent * /*e*/) +{ + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + hide(); +} + +static void drawRoundRect(QPainter &p, const QRect &r) +{ + static int line[8] = { 1, 3, 4, 5, 6, 7, 7, 8 }; + static int border[8] = { 1, 2, 1, 1, 1, 1, 1, 1 }; + int xl, xr, y1, y2; + QPen pen = p.pen(); + bool drawBorder = pen.style() != QPen::NoPen; + + if (r.width() < 16 || r.height() < 16) + { + p.drawRect(r); + return; + } + + p.fillRect(r.x(), r.y() + 8, r.width(), r.height() - 16, p.brush()); + p.fillRect(r.x() + 8, r.y(), r.width() - 16, r.height(), p.brush()); + + p.setPen(p.brush().color()); + + for (int i = 0; i < 8; i++) + { + xl = i; + xr = r.width() - i - 1; + y1 = 7; + y2 = 7 - (line[i] - 1); + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + y1 = r.height() - y1 - 1; + y2 = r.height() - y2 - 1; + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + } + + if (drawBorder) + { + p.setPen(pen); + + if (r.height() > 16) + { + p.drawLine(r.x(), r.y() + 8, r.x(), r.y() + r.height() - 9); + p.drawLine(r.x() + r.width() - 1, r.y() + 8, r.x() + r.width() - 1, r.y() + r.height() - 9); + } + if (r.width() > 16) + { + p.drawLine(r.x() + 8, r.y(), r.x() + r.width() - 9, r.y()); + p.drawLine(r.x() + 8, r.y() + r.height() - 1, r.x() + r.width() - 9, r.y() + r.height() - 1); + } + + for (int i = 0; i < 8; i++) + { + xl = i; + xr = r.width() - i - 1; + y2 = 7 - (line[i] - 1); + y1 = y2 + (border[i] - 1); + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + y1 = r.height() - y1 - 1; + y2 = r.height() - y2 - 1; + + p.drawLine(xl, y1, xl, y2); + p.drawLine(xr, y1, xr, y2); + + } + } +} + +void KickerTip::plainMask() +{ + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::NoPen); + //maskPainter.drawRoundRect(m_mask.rect(), 1600 / m_mask.rect().width(), 1600 / m_mask.rect().height()); + drawRoundRect(maskPainter, m_mask.rect()); + setMask(m_mask); + m_frameTimer.stop(); +} + +void KickerTip::dissolveMask() +{ + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::NoPen); + //maskPainter.drawRoundRect(m_mask.rect(), 1600 / m_mask.rect().width(), 1600 / m_mask.rect().height()); + drawRoundRect(maskPainter, m_mask.rect()); + + m_dissolveSize += m_dissolveDelta; + + if (m_dissolveSize > 0) + { + maskPainter.setRasterOp(Qt::EraseROP); + + int x, y, s; + const int size = 16; + + for (y = 0; y < height() + size; y += size) + { + x = width(); + s = 4 * m_dissolveSize * x / 128; + for (; x > -size; x -= size, s -= 2) + { + if (s < 0) + { + break; + } + maskPainter.drawEllipse(x - s / 2, y - s / 2, s, s); + } + } + } + else if (m_dissolveSize < 0) + { + m_frameTimer.stop(); + m_dissolveDelta = 1; + } + + setMask(m_mask); +} + +void KickerTip::displayInternal() +{ + // we need to check for m_tippingFor here as well as m_richText + // since if one is really persistant and moves the mouse around very fast + // you can trigger a situation where m_tippingFor gets reset to 0 but + // before display() is called! + if (!m_tippingFor || !m_richText) + { + return; + } + + // determine text rectangle + QRect textRect(0, 0, 0, 0); + if (KickerSettings::mouseOversShowText()) + { + textRect.setWidth(m_richText->widthUsed()); + textRect.setHeight(m_richText->height()); + } + + int margin = KDialog::marginHint(); + int height = QMAX(m_icon.height(), textRect.height()) + 2 * margin; + int textX = m_icon.isNull() ? margin : 2 + m_icon.width() + 2 * margin; + int width = textX + textRect.width() + margin; + int textY = (height - textRect.height()) / 2; + + // resize pixmap, mask and widget + bool firstTime = m_dissolveSize == 24; + if (firstTime) + { + m_mask.resize(width, height); + m_pixmap.resize(width, height); + resize(width, height); + if (isVisible()) + { + // we've already been shown before, but we may grow larger. + // in the case of Up or Right displaying tips, this growth can + // result in the tip occluding the panel and causing it to redraw + // once we return back to display() causing horrid flicker + move(KickerLib::popupPosition(m_direction, this, m_tippingFor)); + } + } + + // create and set transparency mask + switch(m_maskEffect) + { + case Plain: + plainMask(); + break; + + case Dissolve: + dissolveMask(); + break; + } + + // draw background + QPainter bufferPainter(&m_pixmap); + bufferPainter.setPen(colorGroup().foreground()); + bufferPainter.setBrush(colorGroup().background()); + //bufferPainter.drawRoundRect(0, 0, width, height, 1600 / width, 1600 / height); + drawRoundRect(bufferPainter, QRect(0, 0, width, height)); + + // draw icon if present + if (!m_icon.isNull()) + { + bufferPainter.drawPixmap(margin, + margin, + m_icon, 0, 0, + m_icon.width(), m_icon.height()); + } + + if (KickerSettings::mouseOversShowText()) + { + // draw text shadow + QColorGroup cg = colorGroup(); + cg.setColor(QColorGroup::Text, cg.background().dark(115)); + int shadowOffset = QApplication::reverseLayout() ? -1 : 1; + m_richText->draw(&bufferPainter, textX + shadowOffset, textY + 1, QRect(), cg); + + // draw text + cg = colorGroup(); + m_richText->draw(&bufferPainter, textX, textY, rect(), cg); + } +} + +void KickerTip::tipFor(const QWidget* w) +{ + if (m_tippingFor) + { + disconnect(m_tippingFor, SIGNAL(destroyed(QObject*)), + this, SLOT(tipperDestroyed(QObject*))); + } + + m_tippingFor = w; + + if (m_tippingFor) + { + connect(m_tippingFor, SIGNAL(destroyed(QObject*)), + this, SLOT(tipperDestroyed(QObject*))); + } +} + +void KickerTip::untipFor(const QWidget* w) +{ + if (isTippingFor(w)) + hide(); +} + +bool KickerTip::isTippingFor(const QWidget* w) const +{ + return m_tippingFor == w; +} + +void KickerTip::tipperDestroyed(QObject* o) +{ + // we can't do a dynamic cast because we are in the process of dieing + // so static it is. + untipFor(static_cast<QWidget*>(o)); +} + +void KickerTip::internalUpdate() +{ + m_dirty = true; + repaint(false); +} + +void KickerTip::enableTipping(bool tip) +{ + if (tip) + { + m_tippingEnabled++; + } + else + { + m_tippingEnabled--; + } + + if (m_tippingEnabled < 1 && m_self) + { + m_self->hide(); + } +} + +bool KickerTip::tippingEnabled() +{ + return m_tippingEnabled > 0; +} + +void KickerTip::hide() +{ + tipFor(0); + m_timer.stop(); + m_frameTimer.stop(); + QWidget::hide(); +} + +bool KickerTip::eventFilter(QObject *object, QEvent *event) +{ + if (!tippingEnabled()) + { + return false; + } + + if (!object->isWidgetType()) + { + return false; + } + + QWidget *widget = static_cast<QWidget*>(object); + + switch (event->type()) + { + case QEvent::Enter: + if (!KickerSettings::showMouseOverEffects()) + { + return false; + } + + if (!mouseGrabber() && + !qApp->activePopupWidget() && + !isTippingFor(widget)) + { + m_toolTipsEnabled = QToolTip::isGloballyEnabled(); + QToolTip::setGloballyEnabled(false); + + tipFor(widget); + m_timer.stop(); + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(display())); + + // delay to avoid false starts + // e.g. when the user quickly zooms their mouse over + // a button then out of kicker + if (isVisible()) + { + m_timer.start(150, true); + } + else + { + m_timer.start(KickerSettings::mouseOversShowDelay(), true); + } + } + break; + case QEvent::Leave: + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + + m_timer.stop(); + + if (isTippingFor(widget) && isVisible()) + { + disconnect(&m_timer, SIGNAL(timeout()), 0, 0); + connect(&m_timer, SIGNAL(timeout()), SLOT(hide())); + m_timer.start(KickerSettings::mouseOversHideDelay(), true); + } + + tipFor(0); + break; + case QEvent::MouseButtonPress: + QToolTip::setGloballyEnabled(m_toolTipsEnabled); + hide(); + default: + break; + } + + return false; +} + +#include <kickertip.moc> + diff --git a/kicker/libkicker/kickertip.h b/kicker/libkicker/kickertip.h new file mode 100644 index 000000000..7211012fb --- /dev/null +++ b/kicker/libkicker/kickertip.h @@ -0,0 +1,121 @@ +/***************************************************************** + +Copyright (c) 2004 Zack Rusin <zrusin@kde.org> + Sami Kyostil <skyostil@kempele.fi> + Aaron J. Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef KICKER_TIP_H +#define KICKER_TIP_H + +#include <qbitmap.h> +#include <qpixmap.h> +#include <qtimer.h> +#include <qwidget.h> + +#include <kpanelapplet.h> + +class QMimeSourceFactory; +class QPaintEvent; +class QSimpleRichText; +class QTimer; + +class KDE_EXPORT KickerTip : public QWidget +{ + Q_OBJECT + +public: + enum MaskEffect { Plain, Dissolve }; + + struct Data + { + QString message; + QString subtext; + QPixmap icon; + KickerTip::MaskEffect maskEffect; + int duration; + KPanelApplet::Direction direction; + + // do NOT delete this in the client! + QMimeSourceFactory* mimeFactory; + }; + + class KDE_EXPORT Client + { + public: + virtual void updateKickerTip(KickerTip::Data&) = 0; + void updateKickerTip() const; + }; + + static KickerTip* the(); + static void enableTipping(bool tip); + static bool tippingEnabled(); + + void untipFor(const QWidget* w); + bool eventFilter(QObject *o, QEvent *e); + +protected: + KickerTip(QWidget * parent); + ~KickerTip(); + + void paintEvent(QPaintEvent * e); + void mousePressEvent(QMouseEvent * e); + + void plainMask(); + void dissolveMask(); + + void displayInternal(); + void hide(); + + void tipFor(const QWidget* w); + bool isTippingFor(const QWidget* w) const; + +protected slots: + void tipperDestroyed(QObject* o); + void internalUpdate(); + void display(); + +private: + QBitmap m_mask; + QPixmap m_pixmap; + QPixmap m_icon; + MaskEffect m_maskEffect; + QSimpleRichText* m_richText; + QMimeSourceFactory* m_mimeFactory; + + int m_dissolveSize; + int m_dissolveDelta; + KPanelApplet::Direction m_direction; + + QTimer m_timer; + QTimer m_frameTimer; + bool m_dirty; + bool m_toolTipsEnabled; + + const QWidget* m_tippingFor; + + static KickerTip* m_self; + static int m_tippingEnabled; + + friend class KickerTip::Client; +}; + +#endif diff --git a/kicker/libkicker/kshadowengine.cpp b/kicker/libkicker/kshadowengine.cpp new file mode 100644 index 000000000..32008883e --- /dev/null +++ b/kicker/libkicker/kshadowengine.cpp @@ -0,0 +1,251 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net> + * + * Many thanks to: + * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow + * algorithm (currently used) + * - Tim Jansen <tim@tjansen.de> for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <qcolor.h> +#include <qpainter.h> +#include <qbitmap.h> +#include <qpixmap.h> + +#include "kshadowsettings.h" +#include "kshadowengine.h" + +KShadowEngine::KShadowEngine() : + m_shadowSettings( new KShadowSettings ) +{ +} + +KShadowEngine::~KShadowEngine() +{ + delete m_shadowSettings; +} + +KShadowEngine::KShadowEngine(KShadowSettings *fx) : + m_shadowSettings(0L) +{ + setShadowSettings(fx); +} + + +void KShadowEngine::setShadowSettings(KShadowSettings *fx) +{ + delete m_shadowSettings; + + m_shadowSettings = fx; +} + +KShadowSettings *KShadowEngine::shadowSettings() +{ + return m_shadowSettings; +} + +QImage KShadowEngine::makeShadow(const QPixmap& textPixmap, const QColor &bgColor) +{ + QImage result; + + // create a new image for for the shaddow + int w = textPixmap.width(); + int h = textPixmap.height(); + + // avoid calling these methods for every pixel + int bgRed = bgColor.red(); + int bgGreen = bgColor.green(); + int bgBlue = bgColor.blue(); + + int thick = m_shadowSettings->thickness() >> 1; + + double alphaShadow; + + /* + * This is the source pixmap + */ + QImage img = textPixmap.convertToImage().convertDepth(32); + + /* + * Resize the image if necessary + */ + if ((result.width() != w) || (result.height() != h)) + { + result.create(w, h, 32); + } + + result.fill(0); // all black + result.setAlphaBuffer(true); + + for (int i = thick; i < w - thick; i++) + { + for (int j = thick; j < h - thick; j++) + { + switch (m_shadowSettings->algorithm()) + { + case KShadowSettings::DoubleLinearDecay: + alphaShadow = doubleLinearDecay(img, i, j); + break; + case KShadowSettings::RadialDecay: + alphaShadow = radialDecay(img, i, j); + break; + case KShadowSettings::NoDecay: + alphaShadow = noDecay(img, i, j); + break; + case KShadowSettings::DefaultDecay: + default: + alphaShadow = defaultDecay(img, i, j); + } + + alphaShadow = (alphaShadow > m_shadowSettings->maxOpacity()) ? m_shadowSettings->maxOpacity() : alphaShadow; + + // update the shadow's i,j pixel. + result.setPixel(i,j, qRgba(bgRed, bgGreen , bgBlue, (int) alphaShadow)); + } + } + return result; +} + +// Multiplication factor for pixels directly above, under, or next to the text +#define AXIS_FACTOR 2.0 +// Multiplication factor for pixels diagonal to the text +#define DIAGONAL_FACTOR 1.0 + +double KShadowEngine::defaultDecay(QImage& source, int i, int j) +{ + if ((i < 1) || (j < 1) || (i > source.width() - 2) || (j > source.height() - 2)) + return 0; + + double alphaShadow; + alphaShadow =(qGray(source.pixel(i-1,j-1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i-1,j )) * AXIS_FACTOR + + qGray(source.pixel(i-1,j+1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i ,j-1)) * AXIS_FACTOR + + 0 + + qGray(source.pixel(i ,j+1)) * AXIS_FACTOR + + qGray(source.pixel(i+1,j-1)) * DIAGONAL_FACTOR + + qGray(source.pixel(i+1,j )) * AXIS_FACTOR + + qGray(source.pixel(i+1,j+1)) * DIAGONAL_FACTOR) / m_shadowSettings->multiplicationFactor(); + + return alphaShadow; +} + +double KShadowEngine::doubleLinearDecay(QImage& source, int i, int j) +{ + //printf("img: %p, %d %d\n", (char *) &source, i, j); + return defaultDecay( source, i, j ); // for now +} + +double KShadowEngine::radialDecay(QImage& source, int i, int j) +{ + //printf("img: %p, %d %d\n", (char *) &source, i, j); + return defaultDecay( source, i, j ); // for now +} + +double KShadowEngine::noDecay(QImage& source, int i, int j) +{ + // create a new image for for the shaddow + int w = source.width(); + int h = source.height(); + int sx, sy; + //int thick = m_shadowSettings->thickness() >> 1; + + double alphaShadow = 0; + double opacity = 0; + for (int k = 1; k <= m_shadowSettings->thickness(); k++) { + /* Generate a shadow THICKNESS pixels thicker + * on either side than the text image. Ensure + * that i +/- k and j +/- k are within the + * bounds of the text pixmap. + */ + opacity = 0; + for (int l = -k; l <= k; l++) { + if (i < k) + sx = 0; + else if (i >= w - k) + sx = w - 1; + else + sx = i + l; + + for (int m = -k; m <= k; m++) { + if (j < k) + sy = 0; + else if (j >= h - k) + sy = h - 1; + else + sy = j + m; + + opacity += qGray(source.pixel(sx, sy)); + } + } + alphaShadow += opacity / m_shadowSettings->multiplicationFactor(); + } + return alphaShadow; +} + +KTextShadowEngine::KTextShadowEngine() : KShadowEngine() +{ + KShadowSettings *shadset = new KShadowSettings(); + + shadset->setOffsetX(0); + shadset->setOffsetY(0); + shadset->setThickness(1); + shadset->setMaxOpacity(96); + + setShadowSettings(shadset); +} + +// taken from mtaskbar, by Sebastian Wolff +void KTextShadowEngine::drawText(QPainter &p, const QRect &tr, int tf, const QString &str, const QSize &size) +{ + // get the color of the shadow: white for dark text, black for bright text + QPen textPen = p.pen(); + QColor shadCol = textPen.color(); + + if (shadCol.red() + + shadCol.green() + + shadCol.blue() <= 3*256/2-1) + { + shadCol = QColor(255,255,255); + } + else + { + shadCol = QColor(0,0,0); + } + + // get a transparent pixmap + QPainter pixPainter; + QPixmap textPixmap(size); + + textPixmap.fill(QColor(0,0,0)); + textPixmap.setMask(textPixmap.createHeuristicMask(true)); + + // draw text + pixPainter.begin(&textPixmap); + pixPainter.setPen(Qt::white); + pixPainter.setFont(p.font()); // get the font from the root painter + pixPainter.drawText(tr, tf, str); + pixPainter.end(); + + // draw shadow + QImage img = makeShadow(textPixmap, shadCol); + + // return + p.drawImage(0, 0, img); + p.drawText(tr, tf, str); +} + diff --git a/kicker/libkicker/kshadowengine.h b/kicker/libkicker/kshadowengine.h new file mode 100644 index 000000000..0fc4877fa --- /dev/null +++ b/kicker/libkicker/kshadowengine.h @@ -0,0 +1,123 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net> + * + * Many thanks to: + * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow + * algorithm (currently used) + * - Tim Jansen <tim@tjansen.de> for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FX_SHADOW +#define __FX_SHADOW + +#include <qpixmap.h> +#include <qimage.h> +#include <qcolor.h> + +#include <kdemacros.h> + +class KShadowSettings; + +/** + * This class implements the shadow algorithm(s). It uses a FxData + * object for its parameters. Note that the shadow algorithm is using the + * luminosity of the original pixmap for the shadow one. + * @see KShadowSettings + * @author laur.ivan@corvil.com + * @since 3.2 + */ +class KDE_EXPORT KShadowEngine +{ +public: + /// Creates a new shadow engine. + KShadowEngine(); + + ~KShadowEngine(); + + /** + * Creates a new shadow engine. + * @param fx the shadow settings object with the configuration. The Shadow + * Engine will own this object and also delete it. Must + * be heap-allocated + */ + KShadowEngine(KShadowSettings *fx); + + /** + * Set the KShadowSettings object. + * @param fx the shadow settings object with the configuration. The Shadow + * Engine will own this object and also delete it. Must + * be heap-allocated. + */ + void setShadowSettings(KShadowSettings *fx); + + /** + * Get the current KShadowSettings. + * @param the current shadow settings + */ + KShadowSettings *shadowSettings(); + + /** + * Make shadow! + * + * textPixmap is the original pixmap where a (white) text is drawn. + * bgColor is the color used for the shadow. + * @param textPixmap the pixmap of the text + * @param bgColor the background color + * @return the resulting image + */ + QImage makeShadow(const QPixmap& textPixmap, const QColor &bgColor); + +private: + // No static objects in libs, and no static deleters in kdefx... + //static KShadowSettings s_defaultShadowSettings; + + KShadowSettings *m_shadowSettings; + + /* + * a simple algorithm with 3 pixels thickness + */ + double defaultDecay(QImage& source, int x, int y); + + /* + * a slower algorithm where the influence of a pixel + * is qGray(px)/(abs(dx) + abs(dy) +1). + */ + double doubleLinearDecay(QImage& source, int x, int y); + + /* + * a very slow algorithm where the influence of a pixel + * is qGray(px)/(sqrt(sqr(dx) + sqr(dy)) +1). + */ + double radialDecay(QImage& source, int x, int y); + + /* + * a nice/fast algorithm proposed by Bernardo Hung + */ + double noDecay(QImage& source, int x, int y); + + void *d; +}; + +class KDE_EXPORT KTextShadowEngine : public KShadowEngine +{ +public: + KTextShadowEngine(); + + void drawText(QPainter &p, const QRect &tr, int tf, const QString &str, const QSize &size); +}; + +#endif diff --git a/kicker/libkicker/kshadowsettings.cpp b/kicker/libkicker/kshadowsettings.cpp new file mode 100644 index 000000000..9c935d30f --- /dev/null +++ b/kicker/libkicker/kshadowsettings.cpp @@ -0,0 +1,182 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net> + * + * Many thanks to: + * - Tim Jansen <tim@tjansen.de> for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <qstring.h> +#include <qstringlist.h> +#include "kshadowsettings.h" + +KShadowSettings::KShadowSettings() +{ + // init the components with some default values + setDefaults(); +} + +// load/save methods +void KShadowSettings::fromString(const QString &val) +{ + setOffsetX(val.section(',', OFFSET_X, OFFSET_X).toInt()); + setOffsetY(val.section(',', OFFSET_Y, OFFSET_Y).toInt()); + setMultiplicationFactor(val.section(',', MULTIPLICATION_FACTOR, MULTIPLICATION_FACTOR).toDouble()); + setMaxOpacity(val.section(',', MAX_OPACITY, MAX_OPACITY).toDouble()); + setThickness(val.section(',', THICKNESS, THICKNESS).toInt()); + setAlgorithm((Algorithm) val.section(',', ALGORITHM, ALGORITHM).toInt()); + setSelectionType((SelectionType)val.section(',', SELECTION_TYPE, SELECTION_TYPE).toInt()); +} + +QString KShadowSettings::toString() const +{ + QString result; + result.sprintf("%d,%d,%f,%f,%d,%d,%d", + offsetX(), + offsetY(), + multiplicationFactor(), + maxOpacity(), + thickness(), + (int)algorithm(), + (int)selectionType()); + return result; +} + +//*********************************** +// get methods +//*********************************** + +/** + * Returns the decay algorithm to be used (see the alg. enumeration in the .h) + */ +KShadowSettings::Algorithm KShadowSettings::algorithm() const +{ + return _algorithm; +} + +/** + * Returns a multiplication facor used to average the resulted data + */ +double KShadowSettings::multiplicationFactor() const +{ + return _multiplicationFactor; +} + +/** + * Returns the max opacity allowed (0 = transparent, 255 = opaque) + */ +double KShadowSettings::maxOpacity() const +{ + return _maxOpacity; +} + +/** + * Returns the Y offset (0 is centered on text) + */ +int KShadowSettings::offsetX() const +{ + return _offsetX; +} + +/** + * Returns the Y offset (0 is centered on text) + */ +int KShadowSettings::offsetY() const +{ + return _offsetY; +} + +/** + * Returns the thickness. Used by the KShadow algorithm + */ +int KShadowSettings::thickness() const +{ + return _thickness; +} + +/** + * Returns the selection type + */ +KShadowSettings::SelectionType KShadowSettings::selectionType() const +{ + return _selectionType; +} + +// set methods +/** + * set the default parameters + */ +void KShadowSettings::setDefaults() +{ + fromString(DEFAULT_SHADOW_CONFIGURATION); +} + + +/** + * Set the algorithm + */ +void KShadowSettings::setAlgorithm(Algorithm val) +{ + _algorithm = val; +} + +/** + * Set the multiplication factor + */ +void KShadowSettings::setMultiplicationFactor(double val) +{ + _multiplicationFactor = val; +} + +/** + * Set the max. opacity + */ +void KShadowSettings::setMaxOpacity(double val) +{ + _maxOpacity = val; +} + +/** + * Set the X offset of the shadow + */ +void KShadowSettings::setOffsetX(int val) +{ + _offsetX = val; +} + +/** + * Set the Y offset of the shadow + */ +void KShadowSettings::setOffsetY(int val) +{ + _offsetY = val; +} + +/** + * Set the shadow thickness + */ +void KShadowSettings::setThickness(int val) +{ + _thickness = val; +} + +/** + * Set the selection type + */ +void KShadowSettings::setSelectionType(SelectionType val) +{ + _selectionType = val; +} diff --git a/kicker/libkicker/kshadowsettings.h b/kicker/libkicker/kshadowsettings.h new file mode 100644 index 000000000..9a91f1c15 --- /dev/null +++ b/kicker/libkicker/kshadowsettings.h @@ -0,0 +1,236 @@ +/* This file is proposed to be part of the KDE libraries. + * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net> + * + * Many thanks to: + * - Tim Jansen <tim@tjansen.de> for the API updates and fixes. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FX_DATA +#define __FX_DATA + +#include <kdemacros.h> + +#define SHADOW_CONFIG_ENTRY QString("ShadowParameters") +#define SHADOW_TEXT_COLOR QString("ShadowTextColor") +#define SHADOW_TEXT_BACKGROUND QString("ShadowTextBackground") + +// fallback configuration string +#define DEFAULT_SHADOW_CONFIGURATION QString("0,0,4.0,120.0,2,1,1,0,0,0") + +/** + * This class is the implementation of a structure for the + * various parameters required by the shadow class. + * + * One may afford this implementation since the shadow class is + * designed to be used as singleton for an application. + * @see KShadowEngine + * @author laur.ivan@corvil.com + * @since 3.2 + */ +class KDE_EXPORT KShadowSettings +{ + public: + /** + * Specifies the order of the options. + * @see fromString + */ + enum ConfigurationOrder + { + OFFSET_X = 0, + OFFSET_Y = OFFSET_X + 1, + MULTIPLICATION_FACTOR = OFFSET_Y + 1, + MAX_OPACITY = MULTIPLICATION_FACTOR + 1, + THICKNESS = MAX_OPACITY + 1, + ALGORITHM = THICKNESS + 1, + SELECTION_TYPE = ALGORITHM + 1 + }; + + public: + /** + * The algorithm used. + */ + enum Algorithm + { + DefaultDecay = 1, ///< the default AXIS/DIAGONAL_FACTOR based alg + DoubleLinearDecay, ///< decay factor is 1/dx+dy + RadialDecay, ///< decay factor is 1/sqrt(dx*dx + dy*dy) + NoDecay ///< decay factor is 1 always + }; + + /** + * The selected method used. + */ + enum SelectionType + { + InverseVideoOnSelection = 0, ///< when selected, the halo is on I/Video + SelectionColorsOnSelection ///< the halo is made w/ selected colors + }; + + /** + * The default constructor. + * Creates an object with default settings for all the variabless. + */ + KShadowSettings(); + + // load/save methods + /** + * Loads the configuration from a string. + * @param the string to load from (comma-separated values) + * @see ConfigurationOrder + */ + virtual void fromString(const QString &s); + /** + * Saves the configuration to a string. + * @return the configuration (comma-separated values) + * @see ConfigurationOrder + */ + virtual QString toString() const; + + // get methods + /** + * Returns the x offset of the shadow. + * @return the x offset + */ + int offsetX() const; + + /** + * Returns the y offset of the shadow. + * @return the y offset + */ + int offsetY() const; + + /** + * Returns the multiplication factor. + * @return the multiplication factor + */ + double multiplicationFactor() const; + + /** + * Returns the maximum opacity of the shadow. + * @return the maximum opacity + */ + double maxOpacity() const; + + /** + * Returns the thickness. + * @return the thickness + */ + int thickness() const; + + /** + * Returns the used algorithm. + * @return the algorithm used + */ + Algorithm algorithm() const; + + /** + * Returns the selection type used. + * @return the selection type + */ + SelectionType selectionType() const; + + // set methods + /** + * Sets default values. + */ + virtual void setDefaults(); + + /** + * Sets the used algorithm. + * @param a the algorithm used + */ + virtual void setAlgorithm(Algorithm a); + + /** + * Sets the multiplication factor. + * @param mf the multiplication factor + */ + virtual void setMultiplicationFactor(double mf); + + /** + * Sets the maximum opacity of the shadow. + * @param mo the maximum opacity + */ + virtual void setMaxOpacity(double mo); + + /** + * Sets the x offset of the shadow. + * @param x the x offset + */ + virtual void setOffsetX(int x); + + /** + * Sets the y offset of the shadow. + * @param y the y offset + */ + virtual void setOffsetY(int y); + + /** + * Sets the thickness. + * @param t the thickness + */ + virtual void setThickness(int t); + + /** + * Sets the selection type used. + * @param s the selection type + */ + virtual void setSelectionType(SelectionType s); + + private: + + /* + * The employed algorithm (see fxshadow.h) + */ + Algorithm _algorithm; + + /** + * This is the multiplication factor for the resulted shadow + */ + double _multiplicationFactor; + + /** + * The maximum permitted opacity for the shadow + */ + double _maxOpacity; + + /* + * offsetX and offsetY are the x/y offsets of the shadow with + * the mention that 0,0 is a centered shadow. + */ + int _offsetX; + int _offsetY; + + /* + * The shadow thickness: + * shadow is this many pixels thicker than the text. + */ + int _thickness; + + /* + * If the value is InverseVideoOnSelection, then the fg/bg + * colours are swapped when the element is selected. + * Otherwise, the selected fg/bg colors are used for text + * as well + */ + SelectionType _selectionType; + + void *d; +}; + + +#endif diff --git a/kicker/libkicker/menuinfo.cpp b/kicker/libkicker/menuinfo.cpp new file mode 100644 index 000000000..740d44d95 --- /dev/null +++ b/kicker/libkicker/menuinfo.cpp @@ -0,0 +1,68 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "menuinfo.h" + +#include <qfile.h> +#include <qwidget.h> + +#include <kapplication.h> +#include <ksimpleconfig.h> +#include <klibloader.h> +#include <kstandarddirs.h> +#include <kpanelmenu.h> +#include <kparts/componentfactory.h> + +MenuInfo::MenuInfo(const QString& desktopFile) +{ + KSimpleConfig df(locate("data", QString::fromLatin1("kicker/menuext/%1").arg(desktopFile))); + df.setGroup("Desktop Entry"); + + QStringList list = df.readListEntry("X-KDE-AuthorizeAction"); + if (kapp && !list.isEmpty()) + { + for(QStringList::ConstIterator it = list.begin(); + it != list.end(); + ++it) + { + if (!kapp->authorize((*it).stripWhiteSpace())) + return; + } + } + + name_ = df.readEntry("Name"); + comment_ = df.readEntry("Comment"); + icon_ = df.readEntry("Icon"); + library_ = df.readEntry("X-KDE-Library"); + desktopfile_ = desktopFile; +} + +KPanelMenu* MenuInfo::load(QWidget *parent, const char *name) +{ + if (library_.isEmpty()) + return 0; + + return KParts::ComponentFactory::createInstanceFromLibrary<KPanelMenu>( + QFile::encodeName( library_ ), + parent, name ); +} diff --git a/kicker/libkicker/menuinfo.h b/kicker/libkicker/menuinfo.h new file mode 100644 index 000000000..0d324538e --- /dev/null +++ b/kicker/libkicker/menuinfo.h @@ -0,0 +1,52 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _menuinfo_h_ +#define _menuinfo_h_ + +#include <qstring.h> + +#include <kdemacros.h> + +class KPanelMenu; +class QWidget; + +class KDE_EXPORT MenuInfo +{ +public: + MenuInfo(const QString& desktopFile); + + QString name() const { return name_; } + QString comment() const { return comment_; } + QString icon() const { return icon_; } + QString library() const { return library_; } + QString desktopFile() const { return desktopfile_; } + bool isValid() const { return !name_.isEmpty(); } + + KPanelMenu* load(QWidget *parent = 0, const char *name = 0); + +private: + QString name_, comment_, icon_, library_, desktopfile_; +}; + +#endif diff --git a/kicker/libkicker/panelbutton.cpp b/kicker/libkicker/panelbutton.cpp new file mode 100644 index 000000000..f53d4b38f --- /dev/null +++ b/kicker/libkicker/panelbutton.cpp @@ -0,0 +1,985 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qfile.h> +#include <qfontmetrics.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qstyle.h> +#include <qstylesheet.h> +#include <qtooltip.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kcursor.h> +#include <kdialog.h> +#include <kdirwatch.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <kicontheme.h> +#include <kipc.h> +#include <kstandarddirs.h> +#include <klocale.h> + +#include "global.h" + +#include "kshadowengine.h" +#include "kshadowsettings.h" + +#include "kickerSettings.h" +#include "panelbutton.h" +#include "panelbutton.moc" + +// init static variable +KShadowEngine* PanelButton::s_textShadowEngine = 0L; + +PanelButton::PanelButton( QWidget* parent, const char* name ) + : QButton(parent, name), + m_valid(true), + m_isLeftMouseButtonDown(false), + m_drawArrow(false), + m_highlight(false), + m_changeCursorOverItem(true), + m_hasAcceptedDrag(false), + m_arrowDirection(KPanelExtension::Bottom), + m_popupDirection(KPanelApplet::Up), + m_orientation(Horizontal), + m_size((KIcon::StdSizes)-1), + m_fontPercent(0.40) +{ + setBackgroundOrigin(AncestorOrigin); + setWFlags(WNoAutoErase); + KGlobal::locale()->insertCatalogue("libkicker"); + calculateIconSize(); + setAcceptDrops(true); + + m_textColor = KGlobalSettings::textColor(); + + updateSettings(KApplication::SETTINGS_MOUSE); + + kapp->addKipcEventMask(KIPC::SettingsChanged | KIPC::IconChanged); + + installEventFilter(KickerTip::the()); + + connect(kapp, SIGNAL(settingsChanged(int)), SLOT(updateSettings(int))); + connect(kapp, SIGNAL(iconChanged(int)), SLOT(updateIcon(int))); +} + +void PanelButton::configure() +{ + QString name = tileName(); + if( name.isEmpty() ) + return; + + if (!KickerSettings::enableTileBackground()) + { + setTile(QString::null); + return; + } + + KConfigGroup tilesGroup( KGlobal::config(), "button_tiles" ); + if( !tilesGroup.readBoolEntry( "Enable" + name + "Tiles", true ) ) { + setTile( QString::null ); + return; + } + + QString tile = tilesGroup.readEntry( name + "Tile" ); + QColor color = QColor(); + + if (tile == "Colorize") + { + color = tilesGroup.readColorEntry( name + "TileColor" ); + tile = QString::null; + } + + setTile( tile, color ); +} + +void PanelButton::setTile(const QString& tile, const QColor& color) +{ + if (tile == m_tile && m_tileColor == color) + { + return; + } + + m_tile = tile; + m_tileColor = color; + loadTiles(); + update(); +} + +void PanelButton::setDrawArrow(bool drawArrow) +{ + if (m_drawArrow == drawArrow) + { + return; + } + + m_drawArrow = drawArrow; + update(); +} + +QImage PanelButton::loadTile(const QString& tile, + const QSize& size, + const QString& state) +{ + QString name = tile; + + if (size.height() < 42) + { + name += "_tiny_"; + } + else if (size.height() < 54) + { + name += "_normal_"; + } + else + { + name += "_large_"; + } + + name += state + ".png"; + + QImage tileImg(KGlobal::dirs()->findResource("tiles", name)); + + // scale if size does not match exactly + if (!tileImg.isNull() && tileImg.size() != size) + { + tileImg = tileImg.smoothScale(size); + } + + return tileImg; +} + +void PanelButton::setEnabled(bool enable) +{ + QButton::setEnabled(enable); + loadIcons(); + update(); +} + +void PanelButton::setPopupDirection(KPanelApplet::Direction d) +{ + m_popupDirection = d; + setArrowDirection(KickerLib::directionToPopupPosition(d)); +} + +void PanelButton::setOrientation(Orientation o) +{ + m_orientation = o; +} + +void PanelButton::updateIcon(int group) +{ + if (group != KIcon::Panel) + { + return; + } + + loadIcons(); + update(); +} + +void PanelButton::updateSettings(int category) +{ + if (category != KApplication::SETTINGS_MOUSE) + { + return; + } + + m_changeCursorOverItem = KGlobalSettings::changeCursorOverIcon(); + + if (m_changeCursorOverItem) + { + setCursor(KCursor::handCursor()); + } + else + { + unsetCursor(); + } +} + +void PanelButton::checkForDeletion(const QString& path) +{ + if (path == m_backingFile) + { + setEnabled(false); + QTimer::singleShot(1000, this, SLOT(scheduleForRemoval())); + } +} + +bool PanelButton::checkForBackingFile() +{ + return QFile::exists(m_backingFile); +} + +void PanelButton::scheduleForRemoval() +{ + static int timelapse = 1000; + if (checkForBackingFile()) + { + setEnabled(true); + timelapse = 1000; + emit hideme(false); + return; + } + else if (KickerSettings::removeButtonsWhenBroken()) + { + if (timelapse > 255*1000) // we'v given it ~8.5 minutes by this point + { + emit removeme(); + return; + } + + if (timelapse > 3000 && isVisible()) + { + emit hideme(true); + } + + timelapse *= 2; + QTimer::singleShot(timelapse, this, SLOT(scheduleForRemoval())); + } +} + +// return the dimension that the button wants to be for a given panel dimension (panelDim) +int PanelButton::preferredDimension(int panelDim) const +{ + // determine the upper limit on the size. Normally, this is panelDim, + // but if conserveSpace() is true, we restrict size to comfortably fit the icon + if (KickerSettings::conserveSpace()) + { + int newSize = preferredIconSize(panelDim); + if (newSize > 0) + { + return QMIN(panelDim, newSize + (KDialog::spacingHint() * 2)); + } + } + + return panelDim; +} + +int PanelButton::widthForHeight(int height) const +{ + int rc = preferredDimension(height); + + // we only paint the text when horizontal, so make sure we're horizontal + // before adding the text in here + if (orientation() == Horizontal && !m_buttonText.isEmpty()) + { + QFont f(font()); + f.setPixelSize(KMIN(height, KMAX(int(float(height) * m_fontPercent), 16))); + QFontMetrics fm(f); + + rc += fm.width(m_buttonText) + KMIN(25, KMAX(5, fm.width('m') / 2)); + } + + return rc; +} + +int PanelButton::heightForWidth(int width) const +{ + return preferredDimension(width); +} + +const QPixmap& PanelButton::labelIcon() const +{ + return m_highlight ? m_iconh : m_icon; +} + +const QPixmap& PanelButton::zoomIcon() const +{ + return m_iconz; +} + +bool PanelButton::isValid() const +{ + return m_valid; +} + +void PanelButton::setTitle(const QString& t) +{ + m_title = t; +} + +void PanelButton::setIcon(const QString& icon) +{ + if (icon == m_iconName) + { + return; + } + + m_iconName = icon; + loadIcons(); + update(); + emit iconChanged(); +} + +QString PanelButton::icon() const +{ + return m_iconName; +} + +bool PanelButton::hasText() const +{ + return !m_buttonText.isEmpty(); +} + +void PanelButton::setButtonText(const QString& text) +{ + m_buttonText = text; + update(); +} + +QString PanelButton::buttonText() const +{ + return m_buttonText; +} + +void PanelButton::setTextColor(const QColor& c) +{ + m_textColor = c; +} + +QColor PanelButton::textColor() const +{ + return m_textColor; +} + +void PanelButton::setFontPercent(double p) +{ + m_fontPercent = p; +} + +double PanelButton::fontPercent() const +{ + return m_fontPercent; +} + +KPanelExtension::Orientation PanelButton::orientation() const +{ + return m_orientation; +} + +KPanelApplet::Direction PanelButton::popupDirection() const +{ + return m_popupDirection; +} + +QPoint PanelButton::center() const +{ + return mapToGlobal(rect().center()); +} + +QString PanelButton::title() const +{ + return m_title; +} + +void PanelButton::triggerDrag() +{ + setDown(false); + + startDrag(); +} + +void PanelButton::startDrag() +{ + emit dragme(m_icon); +} + +void PanelButton::enterEvent(QEvent* e) +{ + if (!m_highlight) + { + m_highlight = true; + repaint(false); + } + + QButton::enterEvent(e); +} + +void PanelButton::leaveEvent(QEvent* e) +{ + if (m_highlight) + { + m_highlight = false; + repaint(false); + } + + QButton::leaveEvent(e); +} + +void PanelButton::dragEnterEvent(QDragEnterEvent* e) +{ + if (e->isAccepted()) + { + m_hasAcceptedDrag = true; + } + + update(); + QButton::dragEnterEvent( e ); +} + +void PanelButton::dragLeaveEvent(QDragLeaveEvent* e) +{ + m_hasAcceptedDrag = false; + update(); + QButton::dragLeaveEvent( e ); +} + +void PanelButton::dropEvent(QDropEvent* e) +{ + m_hasAcceptedDrag = false; + update(); + QButton::dropEvent( e ); +} + +void PanelButton::mouseMoveEvent(QMouseEvent *e) +{ + if (!m_isLeftMouseButtonDown || (e->state() & LeftButton) == 0) + { + return; + } + + QPoint p(e->pos() - m_lastLeftMouseButtonPress); + if (p.manhattanLength() <= 16) + { + // KGlobalSettings::dndEventDelay() is not enough! + return; + } + + m_isLeftMouseButtonDown = false; + triggerDrag(); +} + +void PanelButton::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == LeftButton) + { + m_lastLeftMouseButtonPress = e->pos(); + m_isLeftMouseButtonDown = true; + } + QButton::mousePressEvent(e); +} + +void PanelButton::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() == LeftButton) + { + m_isLeftMouseButtonDown = false; + } + QButton::mouseReleaseEvent(e); +} + +void PanelButton::resizeEvent(QResizeEvent*) +{ + loadTiles(); + + if (calculateIconSize()) + { + loadIcons(); + } +} + +void PanelButton::drawButton(QPainter *p) +{ + const QPixmap& tile = (isDown() || isOn()) ? m_down : m_up; + + if (m_tileColor.isValid()) + { + p->fillRect(rect(), m_tileColor); + style().drawPrimitive(QStyle::PE_Panel, p, rect(), colorGroup()); + } + else if (paletteBackgroundPixmap()) + { + // Draw the background. This is always needed, even when using tiles, + // because they don't have to cover the entire button. + QPoint offset = backgroundOffset(); + int ox = offset.x(); + int oy = offset.y(); + p->drawTiledPixmap( 0, 0, width(), height(),*paletteBackgroundPixmap(), ox, oy); + } + + if (!tile.isNull()) + { + // Draw the tile. + p->drawPixmap(0, 0, tile); + } + else if (isDown() || isOn()) + { + // Draw shapes to indicate the down state. + style().drawPrimitive(QStyle::PE_Panel, p, rect(), colorGroup(), QStyle::Style_Sunken); + } + + drawButtonLabel(p); + + if (hasFocus() || m_hasAcceptedDrag) + { + int x1, y1, x2, y2; + rect().coords(&x1, &y1, &x2, &y2); + QRect r(x1+2, y1+2, x2-x1-3, y2-y1-3); + style().drawPrimitive(QStyle::PE_FocusRect, p, r, colorGroup(), + QStyle::Style_Default, colorGroup().button()); + } +} + +void PanelButton::drawButtonLabel(QPainter *p) +{ + QPixmap icon = labelIcon(); + bool active = isDown() || isOn(); + + if (active) + { + icon = icon.convertToImage().smoothScale(icon.width() - 2, + icon.height() - 2); + } + + if (!m_buttonText.isEmpty() && orientation() == Horizontal) + { + int h = height(); + int w = width(); + int y = (h - icon.height())/2; + p->save(); + QFont f = font(); + + double fontPercent = m_fontPercent; + if (active) + { + fontPercent *= .8; + } + f.setPixelSize(KMIN(h, KMAX(int(float(h) * m_fontPercent), 16))); + QFontMetrics fm(f); + p->setFont(f); + + /* Draw shadowed text */ + bool reverse = QApplication::reverseLayout(); + QPainter::TextDirection rtl = reverse ? QPainter::RTL : QPainter::LTR; + + if (!reverse && !icon.isNull()) + { + /* Draw icon */ + p->drawPixmap(3, y, icon); + } + + int tX = reverse ? 3 : icon.width() + KMIN(25, KMAX(5, fm.width('m') / 2)); + int tY = fm.ascent() + ((h - fm.height()) / 2); + + QColor shadCol = KickerLib::shadowColor(m_textColor); + + // get a transparent pixmap + QPainter pixPainter; + QPixmap textPixmap(w, h); + + textPixmap.fill(QColor(0,0,0)); + textPixmap.setMask(textPixmap.createHeuristicMask(true)); + + // draw text + pixPainter.begin(&textPixmap); + pixPainter.setPen(m_textColor); + pixPainter.setFont(p->font()); // get the font from the root painter + pixPainter.drawText(tX, tY, m_buttonText, -1, rtl); + pixPainter.end(); + + if (!s_textShadowEngine) + { + KShadowSettings* shadset = new KShadowSettings(); + shadset->setOffsetX(0); + shadset->setOffsetY(0); + shadset->setThickness(1); + shadset->setMaxOpacity(96); + s_textShadowEngine = new KShadowEngine(shadset); + } + + // draw shadow + QImage img = s_textShadowEngine->makeShadow(textPixmap, shadCol); + p->drawImage(0, 0, img); + p->save(); + p->setPen(m_textColor); + p->drawText(tX, tY, m_buttonText, -1, rtl); + p->restore(); + + if (reverse && !icon.isNull()) + { + p->drawPixmap(w - icon.width() - 3, y, icon); + } + + p->restore(); + } + else if (!icon.isNull()) + { + int y = (height() - icon.height()) / 2; + int x = (width() - icon.width()) / 2; + p->drawPixmap(x, y, icon); + } + + if (m_drawArrow && (m_highlight || active)) + { + QStyle::PrimitiveElement e = QStyle::PE_ArrowUp; + int arrowSize = style().pixelMetric(QStyle::PM_MenuButtonIndicator); + QRect r((width() - arrowSize)/2, 0, arrowSize, arrowSize); + + switch (m_arrowDirection) + { + case KPanelExtension::Top: + e = QStyle::PE_ArrowUp; + break; + case KPanelExtension::Bottom: + e = QStyle::PE_ArrowDown; + r.moveBy(0, height() - arrowSize); + break; + case KPanelExtension::Right: + e = QStyle::PE_ArrowRight; + r = QRect(width() - arrowSize, (height() - arrowSize)/2, arrowSize, arrowSize); + break; + case KPanelExtension::Left: + e = QStyle::PE_ArrowLeft; + r = QRect(0, (height() - arrowSize)/2, arrowSize, arrowSize); + break; + case KPanelExtension::Floating: + if (orientation() == Horizontal) + { + e = QStyle::PE_ArrowDown; + r.moveBy(0, height() - arrowSize); + } + else if (QApplication::reverseLayout()) + { + e = QStyle::PE_ArrowLeft; + r = QRect(0, (height() - arrowSize)/2, arrowSize, arrowSize); + } + else + { + e = QStyle::PE_ArrowRight; + r = QRect(width() - arrowSize, (height() - arrowSize)/2, arrowSize, arrowSize); + } + break; + } + + int flags = QStyle::Style_Enabled; + if (active) + { + flags |= QStyle::Style_Down; + } + style().drawPrimitive(e, p, r, colorGroup(), flags); + } +} + +// return the icon size that would be used if the panel were proposed_size +// if proposed_size==-1, use the current panel size instead +int PanelButton::preferredIconSize(int proposed_size) const +{ + // (re)calculates the icon sizes and report true if they have changed. + // Get sizes from icontheme. We assume they are sorted. + KIconTheme *ith = KGlobal::iconLoader()->theme(); + + if (!ith) + { + return -1; // unknown icon size + } + + QValueList<int> sizes = ith->querySizes(KIcon::Panel); + + int sz = ith->defaultSize(KIcon::Panel); + + if (proposed_size < 0) + { + proposed_size = (orientation() == Horizontal) ? height() : width(); + } + + // determine the upper limit on the size. Normally, this is panelSize, + // but if conserve space is requested, the max button size is used instead. + int upperLimit = proposed_size; + if (proposed_size > KickerLib::maxButtonDim() && + KickerSettings::conserveSpace()) + { + upperLimit = KickerLib::maxButtonDim(); + } + + //kdDebug()<<endl<<endl<<flush; + QValueListConstIterator<int> i = sizes.constBegin(); + while (i != sizes.constEnd()) + { + if ((*i) + (2 * KickerSettings::iconMargin()) > upperLimit) + { + break; + } + sz = *i; // get the largest size under the limit + ++i; + } + + //kdDebug()<<"Using icon sizes: "<<sz<<" "<<zoom_sz<<endl<<flush; + return sz; +} + +void PanelButton::backedByFile(const QString& localFilePath) +{ + m_backingFile = localFilePath; + + if (m_backingFile.isEmpty()) + { + return; + } + + // avoid multiple connections + disconnect(KDirWatch::self(), SIGNAL(deleted(const QString&)), + this, SLOT(checkForDeletion(const QString&))); + + if (!KDirWatch::self()->contains(m_backingFile)) + { + KDirWatch::self()->addFile(m_backingFile); + } + + connect(KDirWatch::self(), SIGNAL(deleted(const QString&)), + this, SLOT(checkForDeletion(const QString&))); + +} + +void PanelButton::setArrowDirection(KPanelExtension::Position dir) +{ + if (m_arrowDirection != dir) + { + m_arrowDirection = dir; + update(); + } +} + +void PanelButton::loadTiles() +{ + if (m_tileColor.isValid()) + { + setBackgroundOrigin(WidgetOrigin); + m_up = m_down = QPixmap(); + } + else if (m_tile.isNull()) + { + setBackgroundOrigin(AncestorOrigin); + m_up = m_down = QPixmap(); + } + else + { + setBackgroundOrigin(WidgetOrigin); + // If only the tiles were named a bit smarter we wouldn't have + // to pass the up or down argument. + m_up = QPixmap(loadTile(m_tile, size(), "up")); + m_down = QPixmap(loadTile(m_tile, size(), "down")); + } +} + +void PanelButton::loadIcons() +{ + KIconLoader * ldr = KGlobal::iconLoader(); + QString nm = m_iconName; + KIcon::States defaultState = isEnabled() ? KIcon::DefaultState : + KIcon::DisabledState; + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState, 0L, true); + + if (m_icon.isNull()) + { + nm = defaultIcon(); + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState); + } + + if (!isEnabled()) + { + m_iconh = m_icon; + } + else + { + m_iconh = ldr->loadIcon(nm, KIcon::Panel, m_size, + KIcon::ActiveState, 0L, true); + } + + m_iconz = ldr->loadIcon(nm, KIcon::Panel, KIcon::SizeHuge, + defaultState, 0L, true ); +} + +// (re)calculates the icon sizes and report true if they have changed. +// (false if we don't know, because theme couldn't be loaded?) +bool PanelButton::calculateIconSize() +{ + int size = preferredIconSize(); + + if (size < 0) + { + // size unknown + return false; + } + + if (m_size != size) + { + // Size has changed, update + m_size = size; + return true; + } + + return false; +} + +void PanelButton::updateKickerTip(KickerTip::Data& data) +{ + data.message = QStyleSheet::escape(title()); + data.subtext = QStyleSheet::escape(QToolTip::textFor(this)); + data.icon = zoomIcon(); + data.direction = popupDirection(); +} + +// +// PanelPopupButton class +// + +PanelPopupButton::PanelPopupButton(QWidget *parent, const char *name) + : PanelButton(parent, name), + m_popup(0), + m_pressedDuringPopup(false), + m_initialized(false) +{ + connect(this, SIGNAL(pressed()), SLOT(slotExecMenu())); +} + +void PanelPopupButton::setPopup(QPopupMenu *popup) +{ + if (m_popup) + { + m_popup->removeEventFilter(this); + disconnect(m_popup, SIGNAL(aboutToHide()), this, SLOT(menuAboutToHide())); + } + + m_popup = popup; + setDrawArrow(m_popup != 0); + + if (m_popup) + { + m_popup->installEventFilter(this); + connect(m_popup, SIGNAL(aboutToHide()), this, SLOT(menuAboutToHide())); + } +} + +QPopupMenu *PanelPopupButton::popup() const +{ + return m_popup; +} + +bool PanelPopupButton::eventFilter(QObject *, QEvent *e) +{ + if (e->type() == QEvent::MouseMove) + { + QMouseEvent *me = static_cast<QMouseEvent *>(e); + if (rect().contains(mapFromGlobal(me->globalPos())) && + ((me->state() & ControlButton) != 0 || + (me->state() & ShiftButton) != 0)) + { + PanelButton::mouseMoveEvent(me); + return true; + } + } + else if (e->type() == QEvent::MouseButtonPress || + e->type() == QEvent::MouseButtonDblClick) + { + QMouseEvent *me = static_cast<QMouseEvent *>(e); + if (rect().contains(mapFromGlobal(me->globalPos()))) + { + m_pressedDuringPopup = true; + return true; + } + } + else if (e->type() == QEvent::MouseButtonRelease) + { + QMouseEvent *me = static_cast<QMouseEvent *>(e); + if (rect().contains(mapFromGlobal(me->globalPos()))) + { + if (m_pressedDuringPopup && m_popup) + { + m_popup->hide(); + } + return true; + } + } + return false; +} + +void PanelPopupButton::showMenu() +{ + if (isDown()) + { + if (m_popup) + { + m_popup->hide(); + } + + setDown(false); + return; + } + + setDown(true); + update(); + slotExecMenu(); +} + +void PanelPopupButton::slotExecMenu() +{ + if (!m_popup) + { + return; + } + + m_pressedDuringPopup = false; + KickerTip::enableTipping(false); + kapp->syncX(); + kapp->processEvents(); + + if (!m_initialized) + { + initPopup(); + } + + m_popup->adjustSize(); + m_popup->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); +} + +void PanelPopupButton::menuAboutToHide() +{ + if (!m_popup) + { + return; + } + + setDown(false); + KickerTip::enableTipping(true); +} + +void PanelPopupButton::triggerDrag() +{ + if (m_popup) + { + m_popup->hide(); + } + + PanelButton::triggerDrag(); +} + +void PanelPopupButton::setInitialized(bool initialized) +{ + m_initialized = initialized; +} + diff --git a/kicker/libkicker/panelbutton.h b/kicker/libkicker/panelbutton.h new file mode 100644 index 000000000..f71865c77 --- /dev/null +++ b/kicker/libkicker/panelbutton.h @@ -0,0 +1,471 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __panelbutton_h__ +#define __panelbutton_h__ + +#include <algorithm> + +#include <qbutton.h> + +#include <kpanelapplet.h> +#include <kpanelextension.h> +#include <kurldrag.h> + +#include "kickertip.h" + +class QPopupMenu; +class KConfigGroup; +class KShadowEngine; + +/** + * PanelButton is the base class for all buttons to be + * placed in Kicker's panels. It inherits QButton, and + * KickerTip::Client. + */ +class KDE_EXPORT PanelButton: public QButton, public KickerTip::Client +{ + Q_OBJECT + +public: + /** + * Create a panel button + * @param parent the parent widget + * @param name the widget's name + */ + PanelButton( QWidget* parent, const char* name ); + + /** + * Configures this button according to the user's preferences for + * button tiles/colors/etc. This must be called by the container + * embedding the button after consturction and thereafter whenever + * the configuration changes to ensure it remains properly styled. + * Note that it is not used for configuration specific to the subclass. + */ + void configure(); + + /** + * Prompts the button to save it's configuration. Subclass specific + * settings should be saved in this method to the KConfigGroup passed in. + */ + virtual void saveConfig(KConfigGroup&) const {} + + /** + * Reimplement this to display a properties dialog for your button. + */ + virtual void properties() {} + + /** + * Reimplement this to give Kicker a hint for the width of the button + * given a certain height. + */ + virtual int widthForHeight(int height) const; + + /** + * Reimplement this to give Kicker a hint for the height of the button + * given a certain width. + */ + virtual int heightForWidth(int width) const; + + /** + * @return the button's current icon + */ + virtual const QPixmap& labelIcon() const; + + /** + * @return the button's zoom icon + */ + virtual const QPixmap& zoomIcon() const; + + /** + * @return true if this button is valid. + */ + bool isValid() const; + + /** + * Changes the title for the panel button. + * @param t the button's title + */ + void setTitle(const QString& t); + + /** + * @return the title of the button. + */ + QString title() const; + + /** + * Changes the name of the panel button's tile, with + * optional color. + * @param tile the button's tile name + * @param color the button's tile color + */ + void setTile(const QString& tile, const QColor& color = QColor()); + + /** + * Set to true to draw an arrow on the button. + */ + void setDrawArrow(bool drawArrow); + + /** + * Used to set the icon for this panel button. + * @param icon the path to the button's icon + */ + void setIcon(const QString& icon); + + /** + * @return the button's icon + */ + QString icon() const; + + /** + * @return whether this button has a text label or not + */ + bool hasText() const; + + /** + * Change the button's text label + * @param text text for button's label + */ + void setButtonText(const QString& text); + + /** + * @return button's text label + */ + QString buttonText() const; + + /** + * Change the button's text label color + * @param c the new text label color + */ + void setTextColor(const QColor& c); + + /** + * @return the button's text label color + */ + QColor textColor() const; + + /** + * Change the button's text scale + * @param p font scale (in percent) + */ + void setFontPercent(double p); + + /** + * @return the button's text scale (in percent) + */ + double fontPercent() const; + + /** + * @return the orientation of the button + */ + Orientation orientation() const; + + /** + * @return the button's popup direction (read from parent KPanelApplet) + */ + KPanelApplet::Direction popupDirection() const; + + /** + * @return global position of the center of the button + */ + QPoint center() const; + + /** + * Used to load the graphical tile of the button + * @param name path/name of button's tile + * @param size size of the tile + * @param state used if button has multiple states (null by default) + */ + static QImage loadTile(const QString& name, const QSize&, + const QString& state = QString::null); + + /** + * Update the contents of the button's KickerTip + * @param data new KickerTip data + */ + void updateKickerTip(KickerTip::Data& data); + +signals: + /** + * Emitted when the button's icon is changed. + */ + void iconChanged(); + + /** + * Emitted to notify parent containers to save config + */ + void requestSave(); + + /** + * Emitted when the button needs to be removed from it's container + * @see KickerSettings::removeButtonsWhenBroken() + */ + void removeme(); + + /** + * Emitted when the button may need to be removed, but that removal depends + * on as-yet-uncertain future events and therefore ought to be hidden from + * view, though not deleted quite yet. + * @see KickerSettings::removeButtonsWhenBroken() + */ + void hideme(bool hide); + + /** + * Emitted when button initiates a drag + */ + void dragme(const QPixmap); + + /** + * Overloads dragme to support panel button's with a list of KURL's ([url/servicemenu/browser]button) + */ + void dragme(const KURL::List, const QPixmap); + +public slots: + /** + * Set to true to enable the button. + */ + void setEnabled(bool enable); + + /** + * Sets the orientation of the button (ie. which direction the icon will rotate). + */ + void setOrientation(Orientation o); + + /** + * Sets the direction to pop up the contents of the button. + */ + void setPopupDirection(KPanelApplet::Direction d); + +protected: + /** + * Subclasses must implement this to define the name of the button which is + * used to identify this button for saving and loading. It must be unique + * to the subclass, should not be i18n'd and is never made user visible. + * KDE4: remove this and use the classname directly instead. + */ + virtual QString tileName() = 0; + + /** + * @return the default icon for the button + */ + virtual QString defaultIcon() const { return "unknown"; }; + + /** + * Called right before drag occurs. + */ + virtual void triggerDrag(); + + /** + * Emits a signal to drag the button. Reimplement this if, for example, + * if you need the button to call dragme(KURL::List, const QPixmap) + * instead of dragme(const QPixmap) + */ + virtual void startDrag(); + + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + virtual void dropEvent(QDropEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void resizeEvent(QResizeEvent*); + virtual void drawButton(QPainter *); + virtual void drawButtonLabel(QPainter *); + + /** + * @return the preferred icon size. + */ + virtual int preferredIconSize(int proposed_size = -1) const; + + /** + * @return the preferred dimensions for the button + */ + virtual int preferredDimension(int panelDim) const; + + /** + * if the button represents a local file, it tells PanelButton + * what file that is and it starts to watch it. if the file is + * deleted, it is disabled and then checked for one second later + * to see if has returned (e.g. a reinstall occurred) by calling + * checkForBackingFile(). if that returns false, then the button + * is removed from kicker. + * TODO: implement a heuristic that checks back in intervals for + * the reappearance of the file and returns the button to the panel + */ + virtual bool checkForBackingFile(); + + /** + * Set the file backing this button (See @ref checkForBackingFile()), + * you shouldn't need to use this, currently it's only used in [url/service]button + */ + void backedByFile(const QString& localFilePath); + + /** + * Sets the button's arrow direction. + * @param dir the arrow direction + */ + void setArrowDirection(KPanelExtension::Position dir); + + /** + * Loads the tiles for the button + */ + void loadTiles(); + + /** + * Loads the icons for the button + */ + void loadIcons(); + + /** + * (Re)Calculate icon sizes and return true if they have changed. + */ + bool calculateIconSize(); + + bool m_valid; + QPixmap m_icon; + +protected slots: + /** + * Called from KApplication when global icon settings have changed. + * @param group the new group + */ + void updateIcon(int group); + + /** + * Called from KApplication when global settings have changed. + * @param category the settings category, see KApplication::SettingsCategory + */ + void updateSettings(int category); + + /** + * Used for backedByFile, to check if the file backing this button + * has been deleted. + * @param path path to backing file + */ + void checkForDeletion(const QString& path); + + /** + * Called to prepare the button for removal from the Kicker + */ + void scheduleForRemoval(); + +private: + QPoint m_lastLeftMouseButtonPress; + bool m_isLeftMouseButtonDown; + bool m_drawArrow; + bool m_highlight; + bool m_changeCursorOverItem; + bool m_hasAcceptedDrag; + QColor m_textColor; + QColor m_tileColor; + QString m_buttonText; + QString m_tile; + QString m_title; + QString m_iconName; + QString m_backingFile; + QPixmap m_up; + QPixmap m_down; + QPixmap m_iconh; // hover + QPixmap m_iconz; // mouse over + KPanelExtension::Position m_arrowDirection; + KPanelApplet::Direction m_popupDirection; + Orientation m_orientation; + int m_size; + double m_fontPercent; + static KShadowEngine* s_textShadowEngine; + + class PanelPopupPrivate; + PanelPopupPrivate* d; +}; + +/** + * Base class for panelbuttons which popup a menu + */ +class KDE_EXPORT PanelPopupButton : public PanelButton +{ + Q_OBJECT + +public: + /** + * Create a panel button that pops up a menu. + * @param parent the parent widget + * @param name the widget's name + */ + PanelPopupButton(QWidget *parent=0, const char *name=0); + + /** + * Sets the button's popup menu. + * @param popup the menu to pop up + */ + void setPopup(QPopupMenu *popup); + + /** + * @return the button's popup menu + */ + QPopupMenu *popup() const; + + bool eventFilter(QObject *, QEvent *); + virtual void showMenu(); + +protected: + /** + * Called each time the button is clicked and the popup + * is displayed. Reimplement for dynamic popup menus. + */ + virtual void initPopup() {}; + + /** + * Called before drag occurs. Reimplement to do any + * necessary setup before the button is dragged. + */ + virtual void triggerDrag(); + + /** + * Marks the menu as initialized. + */ + void setInitialized(bool initialized); + +protected slots: + /** + * Connected to the button's pressed() signal, this is + * the code that actually displays the menu. Reimplement if + * you need to take care of any tasks before the popup is + * displayed (eg. KickerTip) + */ + virtual void slotExecMenu(); + +private slots: + void menuAboutToHide(); + +private: + QPopupMenu *m_popup; + bool m_pressedDuringPopup; + bool m_initialized; + + class PanelPopupButtonPrivate; + PanelPopupButtonPrivate* d; +}; + +#endif // __panelbutton_h__ diff --git a/kicker/libkicker/paneldrag.cpp b/kicker/libkicker/paneldrag.cpp new file mode 100644 index 000000000..871ac1d96 --- /dev/null +++ b/kicker/libkicker/paneldrag.cpp @@ -0,0 +1,180 @@ +/***************************************************************** +Copyright (c) 2004 Aaron J. Seigo <aseigo@kde.org> + 2004 Stephen Depooter <sbdep@woot.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <sys/types.h> +#include <unistd.h> + +#include <qbuffer.h> + +#include "paneldrag.h" + +#define PANELDRAG_BUFSIZE sizeof(BaseContainer*) + sizeof(pid_t) + +PanelDrag::PanelDrag(BaseContainer* container, QWidget* dragSource) + : QDragObject(dragSource, 0) +{ + pid_t source_pid = getpid(); + + a.resize(PANELDRAG_BUFSIZE); + memcpy(a.data(), &container, sizeof(BaseContainer*)); + memcpy(a.data() + sizeof(BaseContainer*), &source_pid, sizeof(pid_t)); +} + +PanelDrag::~PanelDrag() +{ +} + +bool PanelDrag::decode(const QMimeSource* e, BaseContainer** container) +{ + QByteArray a = e->encodedData("application/basecontainerptr"); + + if (a.size() != PANELDRAG_BUFSIZE) + { + return false; + } + + pid_t target_pid = getpid(); + pid_t source_pid; + memcpy(&source_pid, a.data() + sizeof(QObject*), sizeof(pid_t)); + + if (source_pid == target_pid) + { + memcpy(container, a.data(), sizeof(QObject*)); + return true; + } + + return false; +} + +bool PanelDrag::canDecode(const QMimeSource *e) +{ + if (!e->provides("application/basecontainerptr")) + { + return false; + } + + QByteArray a = e->encodedData("application/basecontainerptr"); + if (a.size() != PANELDRAG_BUFSIZE) + { + return false; + } + +/* pid_t target_pid = getpid(); + pid_t source_pid; + memcpy(&source_pid, a.data() + sizeof(void*), sizeof(pid_t)); + + if (source_pid != target_pid) + { + return true; + } */ + + return true; +} + +QByteArray PanelDrag::encodedData(const char * mimeType) const +{ + if (QString("application/basecontainerptr") == mimeType && + a.size() == PANELDRAG_BUFSIZE) + { + return a; + } + + return QByteArray(); +} + +const char * PanelDrag::format(int i) const +{ + if (i == 0) + { + return "application/basecontainerptr"; + } + + return 0; +} + + +AppletInfoDrag::AppletInfoDrag(const AppletInfo& info, QWidget *dragSource) + : QDragObject(dragSource, 0) +{ + QBuffer buff(a); + buff.open(IO_WriteOnly); + QDataStream s(&buff); + s << info.desktopFile() << info.configFile() << info.type(); +} + +AppletInfoDrag::~AppletInfoDrag() +{ +} + +const char * AppletInfoDrag::format(int i) const +{ + if (i == 0) + { + return "application/appletinfo"; + } + + return 0; +} + +QByteArray AppletInfoDrag::encodedData(const char* mimeType) const +{ + if (QString("application/appletinfo") == mimeType) + { + return a; + } + + return QByteArray(); +} + +bool AppletInfoDrag::canDecode(const QMimeSource * e) +{ + if (!e->provides("application/appletinfo")) + { + return false; + } + + return true; +} + +bool AppletInfoDrag::decode(const QMimeSource* e, AppletInfo& container) +{ + QByteArray a = e->encodedData("application/appletinfo"); + + if (a.isEmpty()) + { + return false; + } + + QBuffer buff(a); + buff.open(IO_ReadOnly); + QDataStream s(&buff); + + QString desktopFile; + QString configFile; + int type; + s >> desktopFile >> configFile >> type; + AppletInfo info(desktopFile, configFile, (AppletInfo::AppletType)type); + container = info; + return true; +} + diff --git a/kicker/libkicker/paneldrag.h b/kicker/libkicker/paneldrag.h new file mode 100644 index 000000000..ba85ad375 --- /dev/null +++ b/kicker/libkicker/paneldrag.h @@ -0,0 +1,68 @@ +/***************************************************************** +Copyright (c) 2004 Aaron J. Seigo <aseigo@kde.org> + 2004 Stephen Depooter <sbdep@woot.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _paneldrag_h_ +#define _paneldrag_h_ + +#include <qdragobject.h> + +#include <kdemacros.h> + +#include "appletinfo.h" + +class BaseContainer; + +class KDE_EXPORT PanelDrag : public QDragObject +{ + public: + PanelDrag(BaseContainer* container, QWidget *dragSource); + ~PanelDrag(); + + virtual const char * format(int i = 0) const; + virtual QByteArray encodedData(const char *) const; + + static bool canDecode(const QMimeSource * e); + static bool decode(const QMimeSource* e, BaseContainer** container); + + private: + QByteArray a; +}; + +class KDE_EXPORT AppletInfoDrag : public QDragObject +{ + public: + AppletInfoDrag(const AppletInfo& container, QWidget *dragSource); + ~AppletInfoDrag(); + + virtual const char * format(int i = 0) const; + virtual QByteArray encodedData(const char *) const; + + static bool canDecode(const QMimeSource * e); + static bool decode(const QMimeSource* e, AppletInfo& container); + + private: + QByteArray a; +}; + +#endif + diff --git a/kicker/libkicker/panner.cpp b/kicker/libkicker/panner.cpp new file mode 100644 index 000000000..43dd67a41 --- /dev/null +++ b/kicker/libkicker/panner.cpp @@ -0,0 +1,396 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlayout.h> +#include <qtooltip.h> +#include <qtimer.h> +#include <qpainter.h> +#include <qstyle.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> + +#include "simplebutton.h" +#include "panner.h" +#include "panner.moc" + +Panner::Panner( QWidget* parent, const char* name ) + : QWidget( parent, name ), + _luSB(0), + _rdSB(0), + _cwidth(0), _cheight(0), + _cx(0), _cy(0) +{ + KGlobal::locale()->insertCatalogue("libkicker"); + setBackgroundOrigin( AncestorOrigin ); + + _updateScrollButtonsTimer = new QTimer(this); + connect(_updateScrollButtonsTimer, SIGNAL(timeout()), this, SLOT(reallyUpdateScrollButtons())); + + _clipper = new QWidget(this); + _clipper->setBackgroundOrigin(AncestorOrigin); + _clipper->installEventFilter( this ); + _viewport = new QWidget(_clipper); + _viewport->setBackgroundOrigin(AncestorOrigin); + + // layout + _layout = new QBoxLayout(this, QBoxLayout::LeftToRight); + _layout->addWidget(_clipper, 1); + setOrientation(Horizontal); +} + +Panner::~Panner() +{ +} + +void Panner::createScrollButtons() +{ + if (_luSB) + { + return; + } + + // left/up scroll button + _luSB = new SimpleArrowButton(this); + _luSB->installEventFilter(this); + //_luSB->setAutoRepeat(true); + _luSB->setMinimumSize(12, 12); + _luSB->hide(); + _layout->addWidget(_luSB); + connect(_luSB, SIGNAL(pressed()), SLOT(startScrollLeftUp())); + connect(_luSB, SIGNAL(released()), SLOT(stopScroll())); + + // right/down scroll button + _rdSB = new SimpleArrowButton(this); + _rdSB->installEventFilter(this); + //_rdSB->setAutoRepeat(true); + _rdSB->setMinimumSize(12, 12); + _rdSB->hide(); + _layout->addWidget(_rdSB); + connect(_rdSB, SIGNAL(pressed()), SLOT(startScrollRightDown())); + connect(_rdSB, SIGNAL(released()), SLOT(stopScroll())); + + // set up the buttons + setupButtons(); +} + +void Panner::setupButtons() +{ + if (orientation() == Horizontal) + { + if (_luSB) + { + _luSB->setArrowType(Qt::LeftArrow); + _rdSB->setArrowType(Qt::RightArrow); + _luSB->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + _rdSB->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + QToolTip::add(_luSB, i18n("Scroll left")); + QToolTip::add(_rdSB, i18n("Scroll right")); + setMinimumSize(24, 0); + } + _layout->setDirection(QBoxLayout::LeftToRight); + } + else + { + if (_luSB) + { + _luSB->setArrowType(Qt::UpArrow); + _rdSB->setArrowType(Qt::DownArrow); + _luSB->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + _rdSB->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + QToolTip::add(_luSB, i18n("Scroll up")); + QToolTip::add(_rdSB, i18n("Scroll down")); + setMinimumSize(0, 24); + } + _layout->setDirection(QBoxLayout::TopToBottom); + } + + if (isVisible()) + { + // we need to manually redo the layout if we are visible + // otherwise let the toolkit decide when to do this + _layout->activate(); + } +} + +void Panner::setOrientation(Orientation o) +{ + _orient = o; + setupButtons(); + reallyUpdateScrollButtons(); +} + +void Panner::resizeEvent( QResizeEvent* ) +{ + //QScrollView::resizeEvent( e ); + //updateScrollButtons(); +} + +void Panner::scrollRightDown() +{ + if(orientation() == Horizontal) // scroll right + scrollBy( _step, 0 ); + else // scroll down + scrollBy( 0, _step ); + if (_step < 64) + _step++; +} + +void Panner::scrollLeftUp() +{ + if(orientation() == Horizontal) // scroll left + scrollBy( -_step, 0 ); + else // scroll up + scrollBy( 0, -_step ); + if (_step < 64) + _step++; +} + +void Panner::startScrollRightDown() +{ + _scrollTimer = new QTimer(this); + connect(_scrollTimer, SIGNAL(timeout()), SLOT(scrollRightDown())); + _scrollTimer->start(50); + _step = 8; + scrollRightDown(); +} + +void Panner::startScrollLeftUp() +{ + _scrollTimer = new QTimer(this); + connect(_scrollTimer, SIGNAL(timeout()), SLOT(scrollLeftUp())); + _scrollTimer->start(50); + _step = 8; + scrollLeftUp(); +} + +void Panner::stopScroll() +{ + delete _scrollTimer; + _scrollTimer = 0; +} + +void Panner::reallyUpdateScrollButtons() +{ + int delta = 0; + + _updateScrollButtonsTimer->stop(); + + if (orientation() == Horizontal) + { + delta = contentsWidth() - width(); + } + else + { + delta = contentsHeight() - height(); + } + + if (delta >= 1) + { + createScrollButtons(); + + // since the buttons may be visible but of the wrong size + // we need to do this every single time + _luSB->show(); + _rdSB->show(); + } + else if (_luSB && _luSB->isVisibleTo(this)) + { + _luSB->hide(); + _rdSB->hide(); + } +} + +void Panner::updateScrollButtons() +{ + _updateScrollButtonsTimer->start(200, true); +} + +void Panner::setContentsPos(int x, int y) +{ + if (x < 0) + x = 0; + else if (x > (contentsWidth() - visibleWidth())) + x = contentsWidth() - visibleWidth(); + + if (y < 0) + y = 0; + else if (y > (contentsHeight() - visibleHeight())) + y = contentsHeight() - visibleHeight(); + + if (x == contentsX() && y == contentsY()) + return; + + _viewport->move(-x, -y); + emit contentsMoving(x, y); +} + +void Panner::scrollBy(int dx, int dy) +{ + setContentsPos(contentsX() + dx, contentsY() + dy); +} + +void Panner::resizeContents( int w, int h ) +{ + _viewport->resize(w, h); + setContentsPos(contentsX(), contentsY()); + updateScrollButtons(); +} + +QPoint Panner::contentsToViewport( const QPoint& p ) const +{ + return QPoint(p.x() - contentsX() - _clipper->x(), p.y() - contentsY() - _clipper->y()); +} + +QPoint Panner::viewportToContents( const QPoint& vp ) const +{ + return QPoint(vp.x() + contentsX() + _clipper->x(), vp.y() + contentsY() + _clipper->y()); +} + +void Panner::contentsToViewport( int x, int y, int& vx, int& vy ) const +{ + const QPoint v = contentsToViewport(QPoint(x,y)); + vx = v.x(); + vy = v.y(); +} + +void Panner::viewportToContents( int vx, int vy, int& x, int& y ) const +{ + const QPoint c = viewportToContents(QPoint(vx,vy)); + x = c.x(); + y = c.y(); +} + +void Panner::ensureVisible( int x, int y ) +{ + ensureVisible(x, y, 50, 50); +} + +void Panner::ensureVisible( int x, int y, int xmargin, int ymargin ) +{ + int pw=visibleWidth(); + int ph=visibleHeight(); + + int cx=-contentsX(); + int cy=-contentsY(); + int cw=contentsWidth(); + int ch=contentsHeight(); + + if ( pw < xmargin*2 ) + xmargin=pw/2; + if ( ph < ymargin*2 ) + ymargin=ph/2; + + if ( cw <= pw ) { + xmargin=0; + cx=0; + } + if ( ch <= ph ) { + ymargin=0; + cy=0; + } + + if ( x < -cx+xmargin ) + cx = -x+xmargin; + else if ( x >= -cx+pw-xmargin ) + cx = -x+pw-xmargin; + + if ( y < -cy+ymargin ) + cy = -y+ymargin; + else if ( y >= -cy+ph-ymargin ) + cy = -y+ph-ymargin; + + if ( cx > 0 ) + cx=0; + else if ( cx < pw-cw && cw>pw ) + cx=pw-cw; + + if ( cy > 0 ) + cy=0; + else if ( cy < ph-ch && ch>ph ) + cy=ph-ch; + + setContentsPos( -cx, -cy ); +} + +bool Panner::eventFilter( QObject *obj, QEvent *e ) +{ + if ( obj == _viewport || obj == _clipper ) + { + switch ( e->type() ) + { + case QEvent::Resize: + viewportResizeEvent((QResizeEvent *)e); + break; + case QEvent::MouseButtonPress: + viewportMousePressEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseButtonRelease: + viewportMouseReleaseEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseButtonDblClick: + viewportMouseDoubleClickEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + case QEvent::MouseMove: + viewportMouseMoveEvent( (QMouseEvent*)e ); + if ( ((QMouseEvent*)e)->isAccepted() ) + return true; + break; + default: + break; + } + } + + return QWidget::eventFilter( obj, e ); // always continue with standard event processing +} + +void Panner::viewportResizeEvent( QResizeEvent* ) +{ +} + +void Panner::viewportMousePressEvent( QMouseEvent* e) +{ + e->ignore(); +} + +void Panner::viewportMouseReleaseEvent( QMouseEvent* e ) +{ + e->ignore(); +} + +void Panner::viewportMouseDoubleClickEvent( QMouseEvent* e ) +{ + e->ignore(); +} + +void Panner::viewportMouseMoveEvent( QMouseEvent* e ) +{ + e->ignore(); +} diff --git a/kicker/libkicker/panner.h b/kicker/libkicker/panner.h new file mode 100644 index 000000000..6657c9a76 --- /dev/null +++ b/kicker/libkicker/panner.h @@ -0,0 +1,115 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __panner_h__ +#define __panner_h__ + +#include <qwidget.h> + +#include "simplebutton.h" + +class QBoxLayout; +class QTimer; + +class KDE_EXPORT Panner : public QWidget +{ + Q_OBJECT + +public: + Panner( QWidget* parent, const char* name = 0 ); + ~Panner(); + + QSize minimumSizeHint() const { return QWidget::minimumSizeHint(); } + + Qt::Orientation orientation() const { return _orient; } + virtual void setOrientation(Orientation orientation); + + QWidget *viewport() const { return _viewport; } + + QRect contentsRect() const { return QRect(0, 0, width(), height()); } + + int contentsX() const { return _viewport ? -_viewport->x() : 0; } + int contentsY() const { return _viewport ? -_viewport->y() : 0; } + int contentsWidth() const { return _viewport ? _viewport->width() : 0; } + int contentsHeight() const { return _viewport ? _viewport->height() : 0; } + void setContentsPos(int x, int y); + + int visibleWidth() const { return _clipper->width(); } + int visibleHeight() const { return _clipper->height(); } + + void contentsToViewport( int x, int y, int& vx, int& vy ) const; + void viewportToContents( int vx, int vy, int& x, int& y ) const; + QPoint contentsToViewport( const QPoint& ) const; + QPoint viewportToContents( const QPoint& ) const; + + void addChild(QWidget *child) { child->show(); } + void removeChild(QWidget *child) { child->hide(); } + int childX(QWidget *child) const { return child->x(); } + int childY(QWidget *child) const { return child->y(); } + void moveChild(QWidget *child, int x, int y) { child->move(x, y); } + + void ensureVisible( int x, int y ); + void ensureVisible( int x, int y, int xmargin, int ymargin ); + +public slots: + virtual void resizeContents( int w, int h ); + void startScrollRightDown(); + void startScrollLeftUp(); + void stopScroll(); + void scrollRightDown(); + void scrollLeftUp(); + void reallyUpdateScrollButtons(); + void scrollBy(int dx, int dy); + +signals: + void contentsMoving(int x, int y); + +protected: + virtual bool eventFilter( QObject *obj, QEvent *e ); + virtual void resizeEvent(QResizeEvent *ev); + virtual void viewportResizeEvent( QResizeEvent* ); + virtual void viewportMousePressEvent( QMouseEvent* ); + virtual void viewportMouseReleaseEvent( QMouseEvent* ); + virtual void viewportMouseDoubleClickEvent( QMouseEvent* ); + virtual void viewportMouseMoveEvent( QMouseEvent* ); + +private: + void setupButtons(); + void createScrollButtons(); + void updateScrollButtons(); + + Orientation _orient; + QBoxLayout *_layout; + SimpleArrowButton *_luSB; // Left Scroll Button + SimpleArrowButton *_rdSB; // Right Scroll Button + QTimer *_updateScrollButtonsTimer; + QTimer *_scrollTimer; + + QWidget *_clipper; + QWidget *_viewport; + int _cwidth, _cheight; + int _cx, _cy; + int _step; +}; + +#endif diff --git a/kicker/libkicker/simplebutton.cpp b/kicker/libkicker/simplebutton.cpp new file mode 100644 index 000000000..223e71982 --- /dev/null +++ b/kicker/libkicker/simplebutton.cpp @@ -0,0 +1,258 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan <nhasan@kde.org> + Copyright (C) 2004-2005 Aaron J. Seigo <aseigo@kde.org> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "simplebutton.h" + +#include <qpainter.h> +#include <qstyle.h> + +#include <kapplication.h> +#include <kcursor.h> +#include <kdialog.h> +#include <kglobalsettings.h> +#include <kiconeffect.h> +#include <kicontheme.h> +#include <kipc.h> +#include <kstandarddirs.h> + +#define BUTTON_MARGIN KDialog::spacingHint() + +SimpleButton::SimpleButton(QWidget *parent, const char *name) + : QButton(parent, name), + m_highlight(false), + m_orientation(Qt::Horizontal) +{ + setBackgroundOrigin( AncestorOrigin ); + + connect( kapp, SIGNAL( settingsChanged( int ) ), + SLOT( slotSettingsChanged( int ) ) ); + connect( kapp, SIGNAL( iconChanged( int ) ), + SLOT( slotIconChanged( int ) ) ); + + kapp->addKipcEventMask( KIPC::SettingsChanged ); + kapp->addKipcEventMask( KIPC::IconChanged ); + + slotSettingsChanged( KApplication::SETTINGS_MOUSE ); +} + +void SimpleButton::setPixmap(const QPixmap &pix) +{ + QButton::setPixmap(pix); + generateIcons(); + update(); +} + +void SimpleButton::setOrientation(Qt::Orientation orientation) +{ + m_orientation = orientation; + update(); +} + +QSize SimpleButton::sizeHint() const +{ + const QPixmap* pm = pixmap(); + + if (!pm) + return QButton::sizeHint(); + else + return QSize(pm->width() + BUTTON_MARGIN, pm->height() + BUTTON_MARGIN); +} + +QSize SimpleButton::minimumSizeHint() const +{ + const QPixmap* pm = pixmap(); + + if (!pm) + return QButton::minimumSizeHint(); + else + return QSize(pm->width(), pm->height()); +} + +void SimpleButton::drawButton( QPainter *p ) +{ + drawButtonLabel(p); +} + +void SimpleButton::drawButtonLabel( QPainter *p ) +{ + if (!pixmap()) + { + return; + } + + QPixmap pix = isEnabled() ? (m_highlight? m_activeIcon : m_normalIcon) : m_disabledIcon; + + if (isOn() || isDown()) + { + pix = pix.convertToImage().smoothScale(pix.width() - 2, + pix.height() - 2); + } + + int h = height(); + int w = width(); + int ph = pix.height(); + int pw = pix.width(); + int margin = BUTTON_MARGIN; + QPoint origin(margin / 2, margin / 2); + + if (ph < (h - margin)) + { + origin.setY((h - ph) / 2); + } + + if (pw < (w - margin)) + { + origin.setX((w - pw) / 2); + } + + p->drawPixmap(origin, pix); +} + +void SimpleButton::generateIcons() +{ + if (!pixmap()) + { + return; + } + + QImage image = pixmap()->convertToImage(); + KIconEffect effect; + + m_normalIcon = effect.apply(image, KIcon::Panel, KIcon::DefaultState); + m_activeIcon = effect.apply(image, KIcon::Panel, KIcon::ActiveState); + m_disabledIcon = effect.apply(image, KIcon::Panel, KIcon::DisabledState); + + updateGeometry(); +} + +void SimpleButton::slotSettingsChanged(int category) +{ + if (category != KApplication::SETTINGS_MOUSE) + { + return; + } + + bool changeCursor = KGlobalSettings::changeCursorOverIcon(); + + if (changeCursor) + { + setCursor(KCursor::handCursor()); + } + else + { + unsetCursor(); + } +} + +void SimpleButton::slotIconChanged( int group ) +{ + if (group != KIcon::Panel) + { + return; + } + + generateIcons(); + update(); +} + +void SimpleButton::enterEvent( QEvent *e ) +{ + m_highlight = true; + + repaint( false ); + QButton::enterEvent( e ); +} + +void SimpleButton::leaveEvent( QEvent *e ) +{ + m_highlight = false; + + repaint( false ); + QButton::enterEvent( e ); +} + +void SimpleButton::resizeEvent( QResizeEvent * ) +{ + generateIcons(); +} + + +SimpleArrowButton::SimpleArrowButton(QWidget *parent, Qt::ArrowType arrow, const char *name) + : SimpleButton(parent, name) +{ + setBackgroundOrigin(AncestorOrigin); + _arrow = arrow; + _inside = false; +} + +QSize SimpleArrowButton::sizeHint() const +{ + return QSize( 12, 12 ); +} + +void SimpleArrowButton::setArrowType(Qt::ArrowType a) +{ + if (_arrow != a) + { + _arrow = a; + update(); + } +} + +Qt::ArrowType SimpleArrowButton::arrowType() const +{ + return _arrow; +} + +void SimpleArrowButton::drawButton( QPainter *p ) +{ + QRect r(1, 1, width() - 2, height() - 2); + + QStyle::PrimitiveElement pe = QStyle::PE_ArrowLeft; + switch (_arrow) + { + case Qt::LeftArrow: pe = QStyle::PE_ArrowLeft; break; + case Qt::RightArrow: pe = QStyle::PE_ArrowRight; break; + case Qt::UpArrow: pe = QStyle::PE_ArrowUp; break; + case Qt::DownArrow: pe = QStyle::PE_ArrowDown; break; + } + + int flags = QStyle::Style_Default | QStyle::Style_Enabled; + if (isDown() || isOn()) flags |= QStyle::Style_Down; + style().drawPrimitive(pe, p, r, colorGroup(), flags); +} + +void SimpleArrowButton::enterEvent( QEvent *e ) +{ + _inside = true; + SimpleButton::enterEvent( e ); + update(); +} + +void SimpleArrowButton::leaveEvent( QEvent *e ) +{ + _inside = false; + SimpleButton::enterEvent( e ); + update(); +} + +#include "simplebutton.moc" + +// vim:ts=4:sw=4:et diff --git a/kicker/libkicker/simplebutton.h b/kicker/libkicker/simplebutton.h new file mode 100644 index 000000000..5423dff6b --- /dev/null +++ b/kicker/libkicker/simplebutton.h @@ -0,0 +1,89 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2004 Nadeem Hasan <nhasan@kde.org> + Copyright (C) 2004-2005 Aaron J. Seigo <aseigo@kde.org> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SIMPLEBUTTON_H +#define SIMPLEBUTTON_H + +#include <qbutton.h> +#include <qpixmap.h> + +#include <kdemacros.h> + +class KDE_EXPORT SimpleButton : public QButton +{ + Q_OBJECT + + public: + SimpleButton(QWidget *parent, const char *name = 0); + void setPixmap(const QPixmap &pix); + void setOrientation(Qt::Orientation orientaton); + QSize sizeHint() const; + QSize minimumSizeHint() const; + + protected: + void drawButton( QPainter *p ); + void drawButtonLabel( QPainter *p ); + void generateIcons(); + + void enterEvent( QEvent *e ); + void leaveEvent( QEvent *e ); + void resizeEvent( QResizeEvent *e ); + + protected slots: + virtual void slotSettingsChanged( int category ); + virtual void slotIconChanged( int group ); + + private: + bool m_highlight; + QPixmap m_normalIcon; + QPixmap m_activeIcon; + QPixmap m_disabledIcon; + Qt::Orientation m_orientation; + class SimpleButtonPrivate; + SimpleButtonPrivate* d; +}; + +class KDE_EXPORT SimpleArrowButton: public SimpleButton +{ + Q_OBJECT + + public: + SimpleArrowButton(QWidget *parent = 0, Qt::ArrowType arrow = Qt::UpArrow, const char *name = 0); + virtual ~SimpleArrowButton() {}; + QSize sizeHint() const; + + protected: + virtual void enterEvent( QEvent *e ); + virtual void leaveEvent( QEvent *e ); + virtual void drawButton(QPainter *p); + Qt::ArrowType arrowType() const; + + public slots: + void setArrowType(Qt::ArrowType a); + + private: + Qt::ArrowType _arrow; + bool _inside; +}; + + +#endif // HIDEBUTTON_H + +// vim:ts=4:sw=4:et diff --git a/kicker/menuext/Makefile.am b/kicker/menuext/Makefile.am new file mode 100644 index 000000000..6d672d29a --- /dev/null +++ b/kicker/menuext/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = find kdeprint prefmenu recentdocs konsole konq-profiles remote system kate + diff --git a/kicker/menuext/find/Makefile.am b/kicker/menuext/find/Makefile.am new file mode 100644 index 000000000..223781dcf --- /dev/null +++ b/kicker/menuext/find/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_find.la + +kickermenu_find_la_SOURCES = findmenu.cpp +kickermenu_find_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_find_la_LIBADD = $(LIB_KDEUI) + +kickermenu_find_la_METASOURCES = AUTO + +desktopmenu_DATA = find.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +findmenu_data_DATA = kfind.desktop websearch.desktop +findmenu_datadir = $(kde_datadir)/kicker/menuext/find + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_find.pot diff --git a/kicker/menuext/find/find.desktop b/kicker/menuext/find/find.desktop new file mode 100644 index 000000000..c4dd2258e --- /dev/null +++ b/kicker/menuext/find/find.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Find +Name[af]=Soek +Name[ar]=إبØØ« +Name[az]=Tap +Name[be]=Шукаць +Name[bg]=ТърÑене +Name[bn]=অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ +Name[br]=Klask +Name[bs]=Traži +Name[ca]=Cerca +Name[cs]=NajÃt +Name[csb]=Szëkba +Name[cy]=Canfod +Name[de]=Suchen +Name[el]=Αναζήτηση +Name[eo]=Trovi +Name[es]=Buscar +Name[et]=Otsing +Name[eu]=Bilatu +Name[fa]=یاÙتن +Name[fi]=Etsi +Name[fr]=Recherche +Name[fy]=Sykje +Name[ga]=Aimsigh +Name[gl]=Procurar +Name[he]=×ž×¦× +Name[hi]=ढूंढें +Name[hr]=Traži +Name[hu]=Keresés +Name[is]=Leita +Name[it]=Trova +Name[ja]=検索 +Name[ka]=ძიებრ+Name[kk]=Іздеп табу +Name[km]=រក +Name[lt]=Rasti +Name[lv]=MeklÄ“t +Name[mk]=Ðајди +Name[mn]=Олох +Name[ms]=Cari +Name[mt]=Fittex +Name[nb]=Finn +Name[nds]=Söken +Name[ne]=फेला पारà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Name[nl]=Zoeken +Name[nn]=Finn +Name[pa]=ਖੋਜ +Name[pl]=Wyszukiwanie +Name[pt]=Procurar +Name[pt_BR]=Procurar +Name[ro]=Caută +Name[ru]=ПоиÑк +Name[rw]=Gushaka +Name[se]=Oza +Name[sk]=NájsÅ¥ +Name[sl]=Najdi +Name[sr]=Ðађи +Name[sr@Latn]=NaÄ‘i +Name[sv]=Sök +Name[ta]=தேட௠+Name[te]=వెతà±à°•à± +Name[tg]=Кофтан +Name[th]=ค้นหา +Name[tr]=Bul +Name[tt]=Ezläw +Name[uk]=Пошук +Name[uz]=Qidirish +Name[uz@cyrillic]=Қидириш +Name[vi]=Tìm kiếm +Name[wa]=Trover +Name[zh_CN]=查找 +Name[zh_TW]=尋找 +Comment=Menu for starting a file or web search +Comment[af]=Kieslys om 'n lêer of web bladsy te soek +Comment[ar]=قائمة لتشغيل مل٠أو للبØØ« ÙÙŠ الشبكة +Comment[be]=Меню Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку пошуку файлаў ці Ñž Сеціве +Comment[bg]=Меню за Ñтартиране на файл или Ñ‚ÑŠÑ€Ñене в Интернет +Comment[bn]=ফাইল বা ওয়েব অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করার জনà§à¦¯ মেনৠ+Comment[bs]=Meni za pokretanje datoteke ili pretrage weba +Comment[ca]=Menú per iniciar una cerca de fitxers o web +Comment[cs]=NabÃdka pro spuÅ¡tÄ›nà souboru nebo hledánà na webu +Comment[csb]=Menu naczãca szëkbë w sécë abò lopków +Comment[da]=Menu for hurtigt at starte en fil- eller netsøgning +Comment[de]=Menü zur Datei- oder Websuche +Comment[el]=ÎœÎµÎ½Î¿Ï Î³Î¹Î± την εκκίνηση ενός αÏχείου ή αναζήτηση στον ιστό +Comment[eo]=Menuo por lanĉi dosier- aÅ TTT-serĉadon +Comment[es]=Menú para comenzar la búsqueda de un archivo o página web +Comment[et]=Menüü faili- või veebiotsingu käivitamiseks +Comment[eu]=Fitxategiak edo interneten bilaketak abiarazteko menua +Comment[fa]=گزینگان برای آغاز جستجوی پرونده یا وب +Comment[fi]=Valikko tiedoston käynnistämiseen tai verkkohakuun +Comment[fr]=Menu permettant d'effectuer une recherche de fichiers ou sur Internet +Comment[fy]=Menu foar it sykjen nei triemmen of op't ynternet +Comment[gl]=Menú para abrir un ficheiro ou buscar na web +Comment[he]=תפריט לחיפוש קובץ, ×ו ביצוע חיפוש ברשת +Comment[hr]=Izbornik za pokretanje pretraživanja datoteka ili Interneta +Comment[hu]=Menü webes vagy fájlkereséshez +Comment[is]=Einföld leið til að ræsa skrár eða hefja vefleit +Comment[it]=Menu per avviare una ricerca web o di file +Comment[ja]=ファイルã¾ãŸã¯ã‚¦ã‚§ãƒ–検索を開始ã™ã‚‹ãŸã‚ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=ფáƒáƒ˜áƒšáƒ¨áƒ˜ áƒáƒœ ვებში ძიების დáƒáƒ¬áƒ§áƒ”ბის მენიუ +Comment[kk]=Файңлды жегу не вебте іздеу мәзірі +Comment[km]=ម៉ឺនុយ​សម្រាប់​ចាប់ផ្ážáž¾áž˜â€‹ážŸáŸ’វែងរក​ឯកសារ ឬ ទំពáŸážšâ€‹áž”ណ្ážáž¶áž‰ +Comment[lt]=Bylų ar žiniatinklio paieÅ¡kos meniu +Comment[mk]=Мени за пребарување на датотека или пребарување на мрежа +Comment[nb]=Meny for Ã¥ starte en fil eller et nettsøk +Comment[nds]=Menü för dat Söken na Dateien oder binnen dat Nett +Comment[ne]=फाइल सà¥à¤°à¥à¤†à¤¤ गरà¥à¤¨à¥‡ वा वेब खोजà¥à¤¨à¤•à¤¾ लागि मेनॠ+Comment[nl]=Menu voor het zoeken naar bestanden of op internet +Comment[nn]=Meny for Ã¥ starta ei fil eller eit nettsøk +Comment[pa]=ਇੱਕ ਫਾਇਲ ਜਾਂ ਵੈੱਬ ਖੋਜ ਸ਼à©à¨°à©‚ ਕਰਨ ਲਈ ਮੇਨੂ +Comment[pl]=Menu rozpoczÄ™cia przeszukiwania sieci lub plików +Comment[pt]=Um menu para iniciar uma pesquisa de ficheiros ou na Web +Comment[pt_BR]=Menu para iniciar um arquivo ou uma busca web +Comment[ro]=Meniu pentru pornirea unei căutări de fiÈ™iere sau pe web +Comment[ru]=БыÑтрый доÑтуп к поиÑку файлов и Ñтраниц в Интернете +Comment[se]=Fállu mas álggahat fiila- dahje fierpmádatohcama +Comment[sk]=Menu pre vyhľadávanie súborov alebo webu +Comment[sl]=Meni za zaÄetek iskanja datotek in iskanja po spletu +Comment[sr]=Мени за започињање претраге фајлова или Веба +Comment[sr@Latn]=Meni za zapoÄinjanje pretrage fajlova ili Veba +Comment[sv]=Meny för att snabbt starta en fil- eller webbsökning +Comment[th]=เมนูสำหรับเริ่มà¸à¸²à¸£à¸„้นหาà¹à¸Ÿà¹‰à¸¡ หรืà¸à¹€à¸§à¹‡à¸š +Comment[tr]=Bir dosya ya da web araması baÅŸlatmak için menü +Comment[uk]=Меню Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ файлів або пошуку в Тенетах +Comment[vi]=Thá»±c Ä‘Æ¡n giúp tìm táºp tin hay tìm trên mạng +Comment[wa]=Menu po-z enonder on cweraedje d' on fitchî ou sol daegntoele +Comment[zh_CN]=å¯åŠ¨æ–‡ä»¶æˆ– Web æœç´¢çš„èœå• +Comment[zh_TW]=開始檔案或網é æœå°‹çš„é¸å–® +Icon=kfind + +X-KDE-Library=kickermenu_find diff --git a/kicker/menuext/find/findmenu.cpp b/kicker/menuext/find/findmenu.cpp new file mode 100644 index 000000000..fc3ae12a6 --- /dev/null +++ b/kicker/menuext/find/findmenu.cpp @@ -0,0 +1,84 @@ +/* + This file is part of Kicker. + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kapplication.h> +#include <kiconloader.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> + +#include "findmenu.h" + +K_EXPORT_KICKER_MENUEXT( find, FindMenu ) + + +FindMenu::FindMenu( QWidget *parent, const char *name, + const QStringList &/*args*/) + : KPanelMenu( "", parent, name ) +{ +} + +FindMenu::~FindMenu() +{ + mConfigList.clear(); +} + +void FindMenu::initialize() +{ + QStringList list = KGlobal::dirs()->findAllResources( "data", "kicker/menuext/find/*.desktop", false, true ); + + list.sort(); + + int id = 0; + + mConfigList.clear(); + for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { + KSimpleConfig config( *it, true ); + config.setDesktopGroup(); + + mConfigList.append( *it ); + QString text = config.readEntry( "Name" ); + + insertItem( SmallIconSet( config.readEntry( "Icon" ) ), text, id ); + id++; + } +} + +void FindMenu::slotExec( int pos ) +{ + QString app = mConfigList[ pos ]; + + kapp->propagateSessionManager(); + + KSimpleConfig config(app, true); + config.setDesktopGroup(); + if (kapp && config.readEntry("Type") == "Link") + { + kapp->invokeBrowser(config.readEntry("URL")); + } + else + { + KApplication::startServiceByDesktopPath( app ); + } +} + +#include "findmenu.moc" diff --git a/kicker/menuext/find/findmenu.h b/kicker/menuext/find/findmenu.h new file mode 100644 index 000000000..2297c4dff --- /dev/null +++ b/kicker/menuext/find/findmenu.h @@ -0,0 +1,47 @@ +/* + This file is part of Kicker. + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef FINDMENU_H +#define FINDMENU_H + +#include <kpanelmenu.h> + +class QStringList; + +class FindMenu : public KPanelMenu +{ + Q_OBJECT + + public: + FindMenu( QWidget* parent, const char* name, const QStringList &/*args*/ ); + ~FindMenu(); + + protected slots: + void initialize(); + void slotExec( int ); + + private: + QStringList mConfigList; +}; + +#endif diff --git a/kicker/menuext/find/kfind.desktop b/kicker/menuext/find/kfind.desktop new file mode 100644 index 000000000..fff29f223 --- /dev/null +++ b/kicker/menuext/find/kfind.desktop @@ -0,0 +1,89 @@ +[Desktop Entry] +Exec=kfind %f +Icon=kfind +DocPath=kfind/index.html +Path= +Type=Application +Terminal=false +Name=Find Files +Name[af]=Soek Lêers +Name[ar]=ابØØ« عن ملÙات +Name[be]=Шукаць файлы +Name[bg]=ТърÑене на файлове +Name[bn]=ফাইল অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ +Name[br]=Klask restroù +Name[bs]=PronaÄ‘i datoteke +Name[ca]=Cerca fitxers +Name[cs]=NajÃt soubory +Name[csb]=Nalezë lopczi +Name[cy]=Canfod Ffeiliau +Name[da]=Find filer +Name[de]=Dateien suchen +Name[el]=Αναζήτηση αÏχείων +Name[eo]=Trovi dosierojn +Name[es]=KFind +Name[et]=Failide otsimine +Name[eu]=Bilatu fitxategiak +Name[fa]=یاÙتن پرونده‌ها +Name[fi]=Etsi tiedostoja +Name[fr]=Recherche de fichiers +Name[fy]=Triemmen sykje +Name[ga]=Aimsigh Comhaid +Name[gl]=Buscar Ficheiros +Name[he]=חפש ×§×‘×¦×™× +Name[hi]=फ़ाइलें ढूंढें +Name[hr]=Traži datoteke +Name[hu]=FájlkeresÅ‘ +Name[id]=Cari Berkas +Name[is]=Finna skrár +Name[it]=Trova file +Name[ja]=ファイルを検索 +Name[ka]=ფáƒáƒ˜áƒšáƒ—რძიებრ+Name[kk]=Файлдарды табу +Name[km]=រក​ឯកសារ +Name[ko]=글꼴 íŒŒì¼ +Name[lo]=ຄົ້ນຫາà»àºŸà»‰àº¡ +Name[lt]=Rasti bylas +Name[lv]=MeklÄ“t Failus +Name[mk]=Пронајди датотеки +Name[mn]=Файл хайх +Name[ms]=Cari Fail +Name[mt]=Sib Fajls +Name[nb]=Finn filer +Name[nds]=Dateien söken +Name[ne]=फाइल फेला पारà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ +Name[nl]=Bestanden zoeken +Name[nn]=Finn filer +Name[nso]=Hwetsa Difaele +Name[oc]=Cerca fiquièrs +Name[pa]=ਫਾਇਲ ਖੋਜ +Name[pl]=Znajdź pliki +Name[pt]=Procurar Ficheiros +Name[pt_BR]=Procurar arquivos +Name[ro]=Caută fiÈ™iere +Name[ru]=ПоиÑк файлов +Name[rw]=Gushaka Amadosiye +Name[se]=Oza fiillaid +Name[sk]=HľadaÅ¥ súbory +Name[sl]=Najdi datoteke +Name[sr]=Претрага фајлова +Name[sr@Latn]=Pretraga fajlova +Name[sv]=Hitta filer +Name[ta]=கோபà¯à®ªà¯à®•à®³à¯ˆà®•à¯ கணà¯à®Ÿà¯à®ªà®¿à®Ÿà®¿ +Name[te]=దసà±à°¤à±à°°à°¾à°²à°¨à± వెతà±à°•à± +Name[tg]=Ðфтани файлҳо +Name[th]=ค้นหาà¹à¸Ÿà¹‰à¸¡ +Name[tr]=Dosyalarda Bul +Name[tt]=Birem Ezläw +Name[uk]=Пошук файлів +Name[uz]=Fayllarni qidirish +Name[uz@cyrillic]=Файлларни қидириш +Name[ven]=Todani faela +Name[vi]=Tìm Táºp tin +Name[wa]=Trover des fitchîs +Name[xh]=Fumana Iifayile +Name[zh_CN]=查找文件 +Name[zh_TW]=尋找檔案 +Name[zu]=Thola Amafayela +X-KDE-StartupNotify=true +Categories=Qt;KDE;Find; diff --git a/kicker/menuext/find/websearch.desktop b/kicker/menuext/find/websearch.desktop new file mode 100644 index 000000000..b3d2a0254 --- /dev/null +++ b/kicker/menuext/find/websearch.desktop @@ -0,0 +1,80 @@ +# KDE Config File +[Desktop Entry] +Type=Link +URL=http://www.google.com +Icon=enhanced_browsing +Terminal=false +Name=Web Search +Name[af]=Web Soektog +Name[ar]=بØØ« ÙÙŠ الشبكة +Name[az]=VebdÉ™ Axtrarış +Name[be]=Шукаць у Сеціве +Name[bg]=ТърÑене в Интернет +Name[bn]=ওয়েব অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ +Name[br]=Klask ar gwiad +Name[bs]=Web pretraga +Name[ca]=Recerca web +Name[cs]=Vyhledávánà na webu +Name[csb]=Szëkba w sécë WWW +Name[cy]=Chwiliad Gwê +Name[da]=Internetsøgning +Name[de]=Web-Suche +Name[el]=Αναζήτηση στο διαδίκτυο +Name[eo]=TTT-serĉo +Name[es]=Búsqueda web +Name[et]=Veebiotsing +Name[eu]=Web arakaketa +Name[fa]=جستجوی وب +Name[fi]=Verkkohaku +Name[fr]=Recherche web +Name[fy]=Web-sykje-opdracht +Name[ga]=Cuardach LÃn +Name[gl]=Procura na Web +Name[he]=חיפוש ברשת +Name[hi]=वेब खोज +Name[hr]=Web pretraživanje +Name[hu]=Keresés a weben +Name[is]=Vefleit +Name[it]=Ricerca sul web +Name[ja]=ウェブ検索 +Name[ka]=ვებ ძიებრ+Name[kk]=Вебте табу +Name[km]=ស្វែងរក​ážáž¶áž˜â€‹áž”ណ្ដាញ +Name[lt]=Žiniatinklio paieÅ¡ka +Name[lv]=MeklÄ“t tÄ«klÄ +Name[mk]=Веб-пребарување +Name[mn]=Ð’Ñб хайлт +Name[ms]=Carian Web +Name[mt]=Fittex fuq il-web +Name[nb]=Søk pÃ¥ nettsteder +Name[nds]=In't Nett söken +Name[ne]=वेब खोजी +Name[nl]=Web-zoekopdracht +Name[nn]=Søk pÃ¥ nettstader +Name[pa]=ਵੈੱਬ ਖੋਜ +Name[pl]=Wyszukiwanie w sieci WWW +Name[pt]=Pesquisa na Web +Name[pt_BR]=Busca na Web +Name[ro]=Căutare Web +Name[ru]=ПоиÑк в Интернете +Name[rw]=Ishakisha ry'Urubugamakuru +Name[se]=Web-ohcan +Name[sk]=Hľadanie na WWW +Name[sl]=Spletno iskanje +Name[sr]=Претраживање Веба +Name[sr@Latn]=Pretraživanje Veba +Name[sv]=Webbsökning +Name[ta]=வலை தேட௠+Name[te]=వెబౠఅనà±à°µà±†à°·à°£ +Name[tg]=ҶуÑтуҷӯи Ð’Ñб +Name[th]=ค้นหาจาà¸à¹€à¸§à¹‡à¸š +Name[tr]=Web Arama +Name[tt]=Web-Ezläw +Name[uk]=Пошук в Тенетах +Name[uz]=Internetda qidirish +Name[uz@cyrillic]=Интернетда қидириш +Name[vi]=Tìm kiếm trên mạng +Name[wa]=Cweraedje sol daegntoele +Name[zh_CN]=Web æœç´¢ +Name[zh_TW]=網é æœå°‹ +Categories=Qt;KDE;Find; diff --git a/kicker/menuext/kate/Makefile.am b/kicker/menuext/kate/Makefile.am new file mode 100644 index 000000000..bc629e0f9 --- /dev/null +++ b/kicker/menuext/kate/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_kate.la + +kickermenu_kate_la_SOURCES = katesessionmenu.cpp +kickermenu_kate_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_kate_la_LIBADD = $(LIB_KDEUI) + +kickermenu_kate_la_METASOURCES = AUTO + +desktopmenu_DATA = katesessionmenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kickermenu_kate.pot
\ No newline at end of file diff --git a/kicker/menuext/kate/katesessionmenu.cpp b/kicker/menuext/kate/katesessionmenu.cpp new file mode 100644 index 000000000..63cee8106 --- /dev/null +++ b/kicker/menuext/kate/katesessionmenu.cpp @@ -0,0 +1,150 @@ +/* + 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2005, Anders Lund <anders@alweb.dk> + */ + +#include "katesessionmenu.h" +#include "katesessionmenu.moc" + +#include <kapplication.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kinputdialog.h> +#include <klibloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> + +#include <qvalidator.h> + +class Validator : public QValidator { + public: + Validator( QObject *parent ) : QValidator( parent, 0 ) {} + ~Validator() {} + virtual QValidator::State validate( QString &, int & ) const { return QValidator::Acceptable; } +}; + +K_EXPORT_KICKER_MENUEXT(kate, KateSessionMenu) + +KateSessionMenu::KateSessionMenu( QWidget *parent, const char *name, const QStringList& ) + : KPanelMenu( parent, name ), + m_parent( parent ) +{ +} + +KateSessionMenu::~KateSessionMenu() +{ +} + +// update the session list and rebuild the menu +void KateSessionMenu::initialize() +{ + if ( initialized() ) + { + return; + } + + m_sessions.clear(); + + int id = 0; + + // no session - exec 'kate' + insertItem( SmallIconSet("kate"), i18n("Start Kate (no arguments)"), id++ ); + + // new session - prompt for a name and exec 'kate --start NAME' + insertItem( SmallIconSet("new"), i18n("New Kate Session"), id++ ); + + // new anonymous session, 'kate --start ""' + insertItem( SmallIconSet("new"), i18n("New Anonymous Session"), id++ ); + + insertSeparator(); + + QStringList list = KGlobal::dirs()->findAllResources( "data", "kate/sessions/*.katesession", false, true); + for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) + { + KSimpleConfig config( *it, true ); + config.setGroup( "General" ); + m_sessions.append( config.readEntry( "Name" ) ); + } + + m_sessions.sort(); + + for ( QStringList::ConstIterator it1 = m_sessions.begin(); it1 != m_sessions.end(); ++it1 ) + { + insertItem( *it1, id++ ); + } + + // means for updating, to let the user manually update if he/she added new sessions. + insertSeparator(); + insertItem( SmallIconSet("reload"), i18n("Reload Session List"), this, SLOT(reinitialize()) ); +} + +void KateSessionMenu::slotExec( int id ) +{ + if ( id < 0 ) + return; + + QStringList args; + if ( id > 0 ) + args << "--start"; + + // If a new session is requested we try to ask for a name. + if ( id == 1 ) + { + bool ok (false); + QString name = KInputDialog::getText( i18n("Session Name"), + i18n("Please enter a name for the new session"), + QString::null, + &ok, 0, 0, new Validator( m_parent ) ); + if ( ! ok ) + return; + + if ( name.isEmpty() && KMessageBox::questionYesNo( 0, + i18n("An unnamed session will not be saved automatically. " + "Do you want to create such a session?"), + i18n("Create anonymous session?"), + KStdGuiItem::yes(), KStdGuiItem::cancel(), + "kate_session_button_create_anonymous" ) == KMessageBox::No ) + return; + + if ( m_sessions.contains( name ) && + KMessageBox::warningYesNo( 0, + i18n("You allready have a session named %1. Do you want to open that session?").arg( name ), + i18n("Session exists") ) == KMessageBox::No ) + return; + else + // mark the menu as dirty so that it gets rebuild at next display + // to show the new session + setInitialized( false ); + + args << name; + } + + else if ( id == 2 ) + args << ""; + + else if ( id > 2 ) + args << m_sessions[ id-3 ]; + + kapp->kdeinitExec("kate", args); +} + + +// kate: space-indent: on; indent-width 2; replace-tabs on; diff --git a/kicker/menuext/kate/katesessionmenu.desktop b/kicker/menuext/kate/katesessionmenu.desktop new file mode 100644 index 000000000..24eea8be4 --- /dev/null +++ b/kicker/menuext/kate/katesessionmenu.desktop @@ -0,0 +1,98 @@ +[Desktop Entry] +Name=Kate Session Menu +Name[bg]=Меню ÑеÑии на Kate +Name[bn]=কেট সেশন মেনৠ+Name[ca]=Menú de la sessió Kate +Name[cs]=NabÃdka relace Kate +Name[csb]=Menu sesëji Kate +Name[da]=Kate Sessionsmenu +Name[de]=Kate Sitzungsmenü +Name[el]=ÎœÎµÎ½Î¿Ï ÏƒÏ…Î½ÎµÎ´Ïίας του Kate +Name[eo]=Kate Seanco Menuo +Name[es]=Menú de la sesión de Kate +Name[et]=Kate seansimenüü +Name[fa]=گزینگان نشست Kate +Name[fi]=Katen istuntojenhallinta +Name[fr]=Menu de sessions de Kate +Name[fy]=Kate Sesjemenu +Name[gl]=Menú de Sesións de Kate +Name[he]=תפריט ההפעלה של Kate +Name[hr]=Kate izbornik sesija +Name[hu]=Kate munkafolyamat-menü +Name[is]=Kate setuvalmynd +Name[it]=Menu delle sessioni di Kate +Name[ja]=Kate セッションメニュー +Name[kk]=Kate ÑÐµÐ°Ð½Ñ Ð¼Ó™Ð·Ñ–Ñ€Ñ– +Name[km]=ម៉ឺនុយ​សមáŸáž™â€‹ážšáž”ស់ Kate +Name[lt]=Kate sesijų meniu +Name[nb]=Meny for Kate-økter +Name[nds]=Kate-Törnmenü +Name[ne]=केट सतà¥à¤° मेनॠ+Name[nl]=Kate sessiemenu +Name[pa]=ਕੇਟ ਸ਼ੈਸ਼ਨ ਮੇਨੂ +Name[pl]=Menu sesji Kate +Name[pt]=Menu de Sessões do Kate +Name[pt_BR]=Menu de Sessões do Kate +Name[ro]=Meniu sesiune Kate +Name[ru]=Ð¡ÐµÐ°Ð½Ñ Kate +Name[sk]=Kate menu sedenia +Name[sl]=Meni s sejami za Kate +Name[sr]=Kate-ин мени ÑеÑија +Name[sr@Latn]=Kate-in meni sesija +Name[sv]=Kate sessionsmeny +Name[te]=కేటౠసెషనౠపటà±à°Ÿà±€ +Name[th]=เมนูเซสชั่นขà¸à¸‡ Kate +Name[tr]=Kate Oturum Menüsü +Name[uk]=Меню ÑеанÑів Kate +Name[uz]=Kate seans menyusi +Name[uz@cyrillic]=Kate ÑÐµÐ°Ð½Ñ Ð¼ÐµÐ½ÑŽÑи +Name[wa]=Dressêye di sessions Kate +Name[zh_CN]=Kate 会è¯èœå• +Name[zh_TW]=Kate 工作階段é¸å–® +Comment=Allows you to open Kate with a specified session, or create a new one +Comment[bg]=ÐŸÐ¾Ð·Ð²Ð¾Ð»Ñ Ð¾Ñ‚Ð²Ð°Ñ€Ñнето на определена ÑеÑÐ¸Ñ Ð½Ð° Kate или Ñъздаването на нова +Comment[ca]=Us permet obrir Kate amb una sessió especÃfica o bé crear-ne una de nova +Comment[cs]=Umožňuje otevÅ™Ãt Kate s urÄitou relacà nebo si vytvoÅ™it novou +Comment[csb]=Pòzwôlô òtemknÄ…c apartnÄ… sesëjã Kate abò ùsôdzëc nowÄ… +Comment[da]=Tillader dig at Ã¥bne Kate med en bestemt session, eller at oprette en ny +Comment[de]=Lässt Sie Kate mit einer vorhandenen oder neuen Sitzung starten +Comment[el]=Σας επιτÏÎπει να ανοίξετε το Kate μα μια καθοÏισμÎνη συνεδÏία, ή να δημιουÏγήσετε μία νÎα +Comment[eo]=Ebligas vin malfermi Kate-n kun aparta seanco, aÅ krei novan +Comment[es]=Le permite abrir Kate con una sesión especÃfica, o crear una nueva +Comment[et]=Võimaldab avada Kate määratud seansiga või luua uue seansi +Comment[fa]=به شما اجازه می‌دهد Kate را توسط نشست مشخص‌شده باز کنید، یا مورد جدیدی را ایجاد نمایید +Comment[fi]=Voit avata Katesta määritellyn istunnon, tai luoda uuden +Comment[fr]=Vous permet d'ouvrir Kate avec une session spécifiée, ou d'en créer une nouvelle +Comment[fy]=Stiet jo ta om Kate mei in oantsjutte sesje te iepenjen, of in nije oan te meitsjen +Comment[gl]=PermÃtelle abrir Kate cunha sesión especificada, ou crear unha nova. +Comment[hr]=DopuÅ¡ta otvaranje Kate uz odreÄ‘enu sesiju ili izradu nove sesije +Comment[hu]=LehetÅ‘vé teszi a Kate megnyitását egy megadott munkafolyamattal vagy egy újonnan létrehozottal +Comment[is]=Gerir þér kleyft að opna Kate með ákveðinni setu, eða búa til nýja +Comment[it]=Ti permette di aprire Kate con una particolare sessione, o di crearne una nuova +Comment[ja]=æ–°è¦ã¾ãŸã¯æ—¢å˜ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã§ Kate ã‚’èµ·å‹•ã—ã¾ã™ +Comment[kk]=Kate-Ñ‚Ñ–Ò£ керек ÑеанÑын ашады, немеÑе жаңаÑын баÑтайды +Comment[km]= អនុញ្ញាážâ€‹áž²áŸ’យ​អ្នក​បើក​ Kate ជា​មួយ​នឹង​សមáŸáž™â€‹ážŠáŸ‚ល​បាន​បញ្ជាក់ ឬ​បង្កើážâ€‹ážáŸ’មី​មួយ +Comment[lt]=Leidžia atverti Kate su nurodyta sesija arba sukurti naujÄ… +Comment[nb]=Brukes til Ã¥ Ã¥pne Kate med en bestemt økt, eller opprette en ny +Comment[nds]=Lett Di Kate mit en angeven oder niegen Törn opmaken +Comment[ne]=निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ गरिà¤à¤•à¥‹ सतà¥à¤°à¤¸à¤à¤— केट खोलà¥à¤¨,वा à¤à¤‰à¤Ÿà¤¾ नयाठसिरà¥à¤œà¤¨à¤¾ गरà¥à¤¨ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤› +Comment[nl]=Stelt u in staat om Kate te openen met een opgegeven sessie, of u kunt een nieuwe sessie aanmaken +Comment[pl]=Pozwala otworzyć okreÅ›lonÄ… sesjÄ™ Kate albo utworzyć nowÄ… +Comment[pt]=Permite-lhe abrir o Kate com uma determinada sessão ou criar uma nova +Comment[pt_BR]=Permite que você abra o Kate com uma sessão especÃfica, ou criar uma nova +Comment[ro]=Vă permite să deschideÈ›i Kate cu o sesiune specificată, sau să creaÈ›i una nouă +Comment[ru]=ПозволÑет открыть заданный ÑÐµÐ°Ð½Ñ Kate +Comment[sk]=Umožnà otvoriÅ¥ Kate so Å¡pecifickým sedenÃm alebo vytvoriÅ¥ nové sedenie +Comment[sl]=OmogoÄa vam, da Kate odprete z izbrano sejo, ali pa ustvarite novo sejo +Comment[sr]=Омогућава вам да отворите Kate Ñа задатом ÑеÑијом, или да направите нову +Comment[sr@Latn]=Omogućava vam da otvorite Kate sa zadatom sesijom, ili da napravite novu +Comment[sv]=Gör det möjligt att öppna Kate med en angiven session, eller skapa en ny +Comment[te]=కెటౠనౠఇవà±à°µà°¬à°¡à°¿à°¨ సెషనౠతొ తెరà±à°µà°¬à°¡à±à°¨à±, లేక కొతà±à°¤à°¦à°¿ సృషà±à°Ÿà°¿à°‚చబడà±à°¨à± +Comment[th]=ให้คุณเปิด Kate ด้วยเซสชั่นที่ระบุ หรืà¸à¸ªà¸£à¹‰à¸²à¸‡à¹€à¸‹à¸ªà¸Šà¸±à¹ˆà¸™à¹ƒà¸«à¸¡à¹ˆ +Comment[tr]=Kate'i belirli bir oturumla açmanızı saÄŸlar +Comment[uk]=Ðадає можливіÑÑ‚ÑŒ відкривати Kate з певним ÑеанÑом або Ñтворювати новий +Comment[wa]=Vos permete di drovi Kate avou ene sipecifieye session oudonbén nd ahiver ene novele +Comment[zh_CN]=å…许您用指定会è¯æ‰“å¼€ Kateï¼Œæˆ–åˆ›å»ºæ–°ä¼šè¯ +Comment[zh_TW]=讓您å¯ä»¥ç”¨æŒ‡å®šçš„工作階段來開啟 Kate,或是建立新的工作階段 +Icon=kate +X-KDE-Library=kickermenu_kate diff --git a/kicker/menuext/kate/katesessionmenu.h b/kicker/menuext/kate/katesessionmenu.h new file mode 100644 index 000000000..ea78bf6ba --- /dev/null +++ b/kicker/menuext/kate/katesessionmenu.h @@ -0,0 +1,45 @@ +/* + 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2005, Anders Lund <anders@alweb.dk> + */ + +#ifndef _KateSessionMenu_h_ +#define _KateSessionMenu_h_ + +#include <kpanelmenu.h> + +class KateSessionMenu : public KPanelMenu { + Q_OBJECT + public: + KateSessionMenu( QWidget *parent=0, const char *name=0, const QStringList& /*args*/=QStringList() ); + ~KateSessionMenu(); + + public slots: + virtual void initialize(); + + protected slots: + virtual void slotExec( int id ); + + private: + QStringList m_sessions; + QWidget *m_parent; +}; + +#endif // _KateSessionMenu_h_ + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kicker/menuext/kdeprint/Makefile.am b/kicker/menuext/kdeprint/Makefile.am new file mode 100644 index 000000000..051c087fb --- /dev/null +++ b/kicker/menuext/kdeprint/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_kdeprint.la + +kickermenu_kdeprint_la_SOURCES = print_mnu.cpp +kickermenu_kdeprint_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_kdeprint_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) -lkdeprint + +kickermenu_kdeprint_la_METASOURCES = AUTO + +desktopmenu_DATA = printmenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_kdeprint.pot diff --git a/kicker/menuext/kdeprint/print_mnu.cpp b/kicker/menuext/kdeprint/print_mnu.cpp new file mode 100644 index 000000000..8b2679432 --- /dev/null +++ b/kicker/menuext/kdeprint/print_mnu.cpp @@ -0,0 +1,139 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "print_mnu.h" +#include <kiconloader.h> +#include <klocale.h> +#include <kglobal.h> +#include <kapplication.h> +#include <krun.h> +#include <kdeprint/kmmanager.h> +#include <qregexp.h> + +K_EXPORT_KICKER_MENUEXT(kdeprint, PrintMenu) + +#define ADD_PRINTER_ID 0 +#define KDEPRINT_SETTINGS_ID 1 +#define CONFIG_SERVER_ID 2 +#define PRINT_MANAGER_ID 3 +#define PRINT_BROWSER_ID 4 +#define KPRINTER_ID 5 +#define PRINTER_LIST_ID 10 + +PrintMenu::PrintMenu(QWidget *parent, const char *name, const QStringList & /*args*/) +: KPanelMenu("", parent, name) +{ + static bool kdeprintIconsInitialized = false; + if ( !kdeprintIconsInitialized ) { + KGlobal::iconLoader()->addAppDir("kdeprint"); + kdeprintIconsInitialized = true; + } +} + +PrintMenu::~PrintMenu() +{ +} + +void PrintMenu::initialize() +{ + if (initialized()) clear(); + setInitialized(true); + + int ID = PRINTER_LIST_ID; + // just to be sure the plugin is loaded -> icons are available + KMManager::self(); + + if ((KMManager::self()->printerOperationMask() & KMManager::PrinterCreation) && KMManager::self()->hasManagement()) + insertItem(SmallIconSet("wizard"), i18n("Add Printer..."), ADD_PRINTER_ID); + insertItem(SmallIconSet("kdeprint_configmgr"), i18n("KDE Print Settings"), KDEPRINT_SETTINGS_ID); + if (KMManager::self()->serverOperationMask() & KMManager::ServerConfigure) + insertItem(SmallIconSet("kdeprint_configsrv"), i18n("Configure Server"), CONFIG_SERVER_ID); + insertSeparator(); + insertItem(SmallIconSet("kcontrol"), i18n("Print Manager"), PRINT_MANAGER_ID); + insertItem(SmallIconSet("konqueror"), i18n("Print Browser (Konqueror)"), PRINT_BROWSER_ID); + insertSeparator(); + insertItem(SmallIconSet("fileprint"), i18n("Print File..."), KPRINTER_ID); + + // printer list + QPtrList<KMPrinter> *l = KMManager::self()->printerList(); + if (l && !l->isEmpty()) + { + bool separatorInserted = false; + QPtrListIterator<KMPrinter> it(*l); + for (; it.current(); ++it) + { + // no special, implicit or pure instances + if (it.current()->isSpecial() || it.current()->isVirtual()) + continue; + if (!separatorInserted) + { + // we insert a separator only when we find the first + // printer + insertSeparator(); + separatorInserted = true; + } + insertItem(SmallIconSet(it.current()->pixmap()), + it.current()->printerName(), ID++); + } + } +} + +void PrintMenu::slotExec(int ID) +{ + switch (ID) + { + case ADD_PRINTER_ID: + kapp->kdeinitExec("kaddprinterwizard"); + break; + case KDEPRINT_SETTINGS_ID: + kapp->kdeinitExec("kaddprinterwizard", QStringList("--kdeconfig")); + break; + case CONFIG_SERVER_ID: + kapp->kdeinitExec("kaddprinterwizard", QStringList("--serverconfig")); + break; + case PRINT_MANAGER_ID: + KRun::runCommand("kcmshell kde-printers.desktop"); + break; + case PRINT_BROWSER_ID: + KRun::runCommand("kfmclient openProfile filemanagement print:/", "kfmclient", "konqueror"); + break; + case KPRINTER_ID: + kapp->kdeinitExec("kprinter"); + break; + default: + { + // start kjobviewer + QStringList args; + args << "--show" << "-d" << text(ID).remove('&'); + kapp->kdeinitExec("kjobviewer", args); + } + break; + } +} + +void PrintMenu::reload() +{ + initialize(); +} + +#include "print_mnu.moc" diff --git a/kicker/menuext/kdeprint/print_mnu.h b/kicker/menuext/kdeprint/print_mnu.h new file mode 100644 index 000000000..a80da4be2 --- /dev/null +++ b/kicker/menuext/kdeprint/print_mnu.h @@ -0,0 +1,46 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _print_mnu_h_ +#define _print_mnu_h_ + +#include <kpanelmenu.h> +#include <kdeprint/kpreloadobject.h> + +class PrintMenu : public KPanelMenu, public KPReloadObject +{ + Q_OBJECT + +public: + PrintMenu(QWidget *parent, const char *name, const QStringList & /*args*/); + ~PrintMenu(); + +protected slots: + void slotExec(int id); + void initialize(); + +protected: + void reload(); +}; + +#endif diff --git a/kicker/menuext/kdeprint/printmenu.desktop b/kicker/menuext/kdeprint/printmenu.desktop new file mode 100644 index 000000000..2bc90f1b8 --- /dev/null +++ b/kicker/menuext/kdeprint/printmenu.desktop @@ -0,0 +1,144 @@ +[Desktop Entry] +Name=Print System +Name[af]=Drukker Stelsel +Name[ar]=نظام الطباعة +Name[az]=Çap Sistemi +Name[be]=СіÑÑ‚Ñма друку +Name[bg]=СиÑтема за печат +Name[bn]=মà§à¦¦à§à¦°à¦£ বà§à¦¯à¦¬à¦¸à§à¦¥à¦¾ +Name[br]=Reizhiad moulañ +Name[bs]=Sistem Å¡tampe +Name[ca]=Sistema d'impressió +Name[cs]=Tiskový systém +Name[csb]=Systema drëkù +Name[cy]=Cysawd Argraffu +Name[da]=Udskriftssystem +Name[de]=Drucksystem +Name[el]=ΣÏστημα εκτÏπωσης +Name[eo]=Printosistemo +Name[es]=Sistema de impresión +Name[et]=Trükkimissüsteem +Name[eu]=Inprimaketa sistema +Name[fa]=سیستم چاپ +Name[fi]=Tulostusjärjestelmä +Name[fr]=Système d'impression +Name[fy]=Printsysteem +Name[ga]=Córas Priontála +Name[gl]=Sistema de Impresión +Name[he]=מערכת הדפסה +Name[hi]=छापा तंतà¥à¤° +Name[hr]=Sustav za ispisivanje +Name[hu]=Nyomtatási rendszer +Name[is]=Prentkerfi +Name[it]=Sistema di stampa +Name[ja]=å°åˆ·ã‚·ã‚¹ãƒ†ãƒ +Name[ka]=ბეáƒáƒ“ვის სისტემრ+Name[kk]=БаÑып шығару +Name[km]=ប្រពáŸáž“្ធ​បោះពុម្ព +Name[ko]=ëª¨ë˜ ì‹œìŠ¤í…œ +Name[ku]=Pergala Çapkirinê +Name[lo]=ລະບົບàºàº²àº™àºžàº´àº¡ +Name[lt]=Spausdinimo sistema +Name[lv]=Drukas SistÄ“ma +Name[mk]=ПечатарÑки ÑиÑтем +Name[mn]=Ð¥ÑвлÑÑ… ÑиÑтем +Name[ms]=Cetak Sistem +Name[mt]=Sistema tal-ipprintjar +Name[nb]=Utskriftsystem +Name[nds]=Drucksysteem +Name[ne]=मà¥à¤¦à¥à¤°à¤£ पà¥à¤°à¤£à¤¾à¤²à¥€ +Name[nl]=Afdruksysteem +Name[nn]=Utskriftssystem +Name[nso]=System ya Kgatiso +Name[pa]=ਪਰਿੰਟ ਸਿਸਟਮ +Name[pl]=System drukowania +Name[pt]=Sistema de Impressão +Name[pt_BR]=Sistema de Impressão +Name[ro]=Sistem de tipărire +Name[ru]=СиÑтема печати +Name[rw]=Sisitemu Gucapa +Name[se]=Čálihanvuogádat +Name[sk]=TlaÄový systém +Name[sl]=TiskalniÅ¡ki sistem +Name[sr]=СиÑтем за штампу +Name[sr@Latn]=Sistem za Å¡tampu +Name[sv]=Skrivarsystem +Name[ta]=அசà¯à®šà¯ அமைபà¯à®ªà¯ +Name[te]=à°ªà±à°°à°šà±à°°à°£ à°µà±à°¯à°µà°¸à±à°¥ +Name[tg]=СиÑтемаи Чоп +Name[th]=ระบบà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ +Name[tr]=Yazıcı Sistemi +Name[tt]=Bastıru Sisteme +Name[uk]=СиÑтема друку +Name[uz]=Bosib chiqarish tizimi +Name[uz@cyrillic]=БоÑиб чиқариш тизими +Name[ven]=Maitele au phirintha +Name[vi]=Hệ thống In ấn +Name[wa]=Sistinme d' imprimaedje +Name[xh]=Indlela Yoshicilelo +Name[zh_CN]=打å°ç³»ç»Ÿ +Name[zh_TW]=列å°ç³»çµ± +Name[zu]=Isistimu yokushicilela +Comment=Menu for the print system +Comment[af]=Kieslys vir die drukker stelsel +Comment[ar]=قائمة لنظام الطباعة +Comment[be]=Меню Ð´Ð»Ñ ÑÑ–ÑÑ‚Ñмы друку +Comment[bg]=Меню на ÑиÑтемата за печат +Comment[bn]=মà§à¦¦à§à¦°à¦£ বà§à¦¯à¦¬à¦¸à§à¦¥à¦¾à¦° জনà§à¦¯ মেনৠ+Comment[bs]=Meni za sistem Å¡tampe +Comment[ca]=Menú per al sistema d'impressió +Comment[cs]=NabÃdka tiskového systému +Comment[csb]=Menu systemë drëkù +Comment[da]=Menu for udskriftssystemet +Comment[de]=Einfacher Zugriff auf das Drucksystem +Comment[el]=ÎœÎµÎ½Î¿Ï Î³Î¹Î± το σÏστημα εκτÏπωσης +Comment[eo]=Menuo por printosistemo +Comment[es]=Menú para el sistema de impresión +Comment[et]=Trükkimissüsteemi menüü +Comment[eu]=Inprimaketa sistemarako menua +Comment[fa]=گزینگان برای سیستم چاپ +Comment[fi]=Tulostusjärjestelmävalikko +Comment[fr]=Menu du système d'impression +Comment[fy]=Menu foar it printsysteem +Comment[gl]=Menu para o sistema de impresión +Comment[he]=תפריט למערכת ההדפסה +Comment[hr]=Izbornik sustava ispisivanja +Comment[hu]=Menü a nyomtatási rendszer eléréséhez +Comment[is]=Fljótleg leið að prentkerfinu +Comment[it]=Menu del sistema di stampa +Comment[ja]=å°åˆ·ã‚·ã‚¹ãƒ†ãƒ 用メニュー +Comment[ka]=ბეáƒáƒ“ვის სისტემის მენიუ +Comment[kk]=БаÑып шығару жүйеÑінің мәзірі +Comment[km]=ម៉ឺនុយ​សម្រាប់​ប្រពáŸáž“្ធ​បោះពុម្ព +Comment[lt]=Spausdinimo sistemos meniu +Comment[mk]=Мени за ÑиÑтемот за печатење +Comment[nb]=Meny for utskriftssystemet +Comment[nds]=Menü för dat Drucksysteem +Comment[ne]=मà¥à¤¦à¥à¤°à¤£ पà¥à¤°à¤£à¤¾à¤²à¥€à¤•à¤¾ लागि मेनॠ+Comment[nl]=Menu voor het afdruksysteem +Comment[nn]=Meny for utskriftssystemet +Comment[pa]=ਪਰਿੰਟ ਸਿਸਟਮ ਲਈ ਮੇਨੂ +Comment[pl]=Menu systemu drukowania +Comment[pt]=Um menu para o sistema de impressão +Comment[pt_BR]=Menu para o sistema de impressão +Comment[ro]=Meniu pentru sistemul de tipărire +Comment[ru]=БыÑтрый доÑтуп к ÑиÑтеме печати +Comment[se]=Čálihanvuogádaga fállu +Comment[sk]=Menu pre tlaÄový systém +Comment[sl]=Meni za tiskalniÅ¡ki sistem +Comment[sr]=Мени за ÑиÑтем штампања +Comment[sr@Latn]=Meni za sistem Å¡tampanja +Comment[sv]=Meny för skrivarsystemet +Comment[te]=à°ªà±à°°à°šà±à°°à°£ à°µà±à°¯à°µà°¸à±à°¥ కొరకౠపటà±à°Ÿà°¿ +Comment[th]=เมนูสำหรับระบบà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ +Comment[tr]=Yazıcı sistemi menüsü +Comment[uk]=Меню Ð´Ð»Ñ ÑиÑтеми друку +Comment[uz]=Bosib chiqarish tizimining menyusi +Comment[uz@cyrillic]=БоÑиб чиқариш тизимининг менюÑи +Comment[vi]=Thá»±c Ä‘Æ¡n cho hệ thống in ấn +Comment[wa]=DresseÅ·e pol sistinme d' imprimaedje +Comment[zh_CN]=打å°ç³»ç»Ÿèœå• +Comment[zh_TW]=用於列å°ç³»çµ±çš„é¸å–® +Icon=fileprint + +X-KDE-Library=kickermenu_kdeprint diff --git a/kicker/menuext/konq-profiles/Makefile.am b/kicker/menuext/konq-profiles/Makefile.am new file mode 100644 index 000000000..07df8f9ab --- /dev/null +++ b/kicker/menuext/konq-profiles/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_konqueror.la + +kickermenu_konqueror_la_SOURCES = konqy_menu.cpp +kickermenu_konqueror_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_konqueror_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) + +kickermenu_konqueror_la_METASOURCES = AUTO + +desktopmenu_DATA = konquerormenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_konqueror.pot diff --git a/kicker/menuext/konq-profiles/konquerormenu.desktop b/kicker/menuext/konq-profiles/konquerormenu.desktop new file mode 100644 index 000000000..e051239b5 --- /dev/null +++ b/kicker/menuext/konq-profiles/konquerormenu.desktop @@ -0,0 +1,136 @@ +[Desktop Entry] +Name=Konqueror Profiles +Name[af]=Konqueror Profiele +Name[ar]=مواصÙات ÙÙŠ Konqueror +Name[az]=Konqueror ProfillÉ™ri +Name[be]=Профілі Konqueror +Name[bg]=Профили на браузъра +Name[bn]=কংকরার পà§à¦°à§‹à¦«à¦¾à¦‡à¦² +Name[br]=Profiloù Konqueror +Name[bs]=Konqueror profili +Name[ca]=Perfils de Konqueror +Name[cs]=Profily Konqueroru +Name[csb]=Profile Konquerora +Name[cy]=Proffilau Konqueror +Name[da]=Konqueror-profiler +Name[de]=Konqueror-Profile +Name[el]=Î Ïοφίλ του Konqueror +Name[eo]=Konkerantaj Profiloj +Name[es]=Perfiles de Konqueror +Name[et]=Konquerori profiilid +Name[eu]=Konquerorren profilak +Name[fa]=Profileهای Konqueror +Name[fi]=Konquerorin profiilit +Name[fr]=Profils de Konqueror +Name[fy]=Konqueror-profielen +Name[ga]=PróifÃlà Konqueror +Name[gl]=Perfis de Konqueror +Name[he]=×¤×¨×•×¤×™×œ×™× ×©×œ Konqueror +Name[hi]=कॉनà¥à¤•à¤°à¤° पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤²à¥à¤¸ +Name[hr]=Konqueror profili +Name[hu]=Konqueror-profilok +Name[is]=Konqueror sniðmát +Name[it]=Profili di Konqueror +Name[ja]=Konqueror プãƒãƒ•ã‚¡ã‚¤ãƒ« +Name[ka]=Konqueror-ის პრáƒáƒ¤áƒ˜áƒšáƒ”ბი +Name[kk]=Konqueror профильдер +Name[km]=ទម្រង់ Konqueror +Name[ko]=Konqueror ì œìŠ¤ì²˜ +Name[lt]=Konqueror profiliai +Name[lv]=IekarotÄja profili +Name[mk]=Профили за Konqueror +Name[ms]=Profil Konqueror +Name[mt]=Profili ta' Konqueror +Name[nb]=Profiler for Konqueror +Name[nds]=Konqueror-Profilen +Name[ne]=कनà¥à¤•à¥à¤µà¥‡à¤°à¤° पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤² +Name[nl]=Konqueror-profielen +Name[nn]=Profilar for Konqueror +Name[pa]=ਕੋਨਕਿਉਰੋਰ ਪਰੋਫਾਇਲ +Name[pl]=Profile Konquerora +Name[pt]=Perfis do Konqueror +Name[pt_BR]=Perfis do Konqueror +Name[ro]=Profile Konqueror +Name[ru]=Профили Konqueror +Name[rw]=Ibijyana na Konqueror +Name[se]=Konqueror-profiillat +Name[sk]=Profily pre Konqueror +Name[sl]=Profili Konquerorja +Name[sr]=Konqueror-ови профили +Name[sr@Latn]=Konqueror-ovi profili +Name[sv]=Konqueror-profiler +Name[ta]=Konqueror விவரகà¯à®•à¯à®±à®¿à®ªà¯à®ªà¯à®•à®³à¯ +Name[te]=కాంకెరరౠపà±à°°à±Šà°«à±ˆà°²à±à°²à± +Name[th]=โปรไฟล์ขà¸à¸‡à¸„à¸à¸™à¹€à¸„วà¸à¸£à¹Œà¹€à¸£à¸à¸£à¹Œ +Name[tr]=Konqueror Profilleri +Name[tt]=Konqueror Caybireme +Name[uk]=Профілі Konqueror +Name[uz]=Konqueror profillari +Name[uz@cyrillic]=Konqueror профиллари +Name[vi]=Thông số Konqueror +Name[wa]=Profils Konqueror +Name[zh_CN]=Konqueror é…置文件 +Name[zh_TW]=Konqueror è¨å®šçµ„åˆ +Comment=Menu for accessing the Konqueror profiles +Comment[af]=Kieslys om toegang tot die Konqueror profiele te verkry +Comment[ar]=قائمة للوصول إلى مواصÙات ÙÙŠ Konqueror +Comment[be]=Меню Ð´Ð»Ñ Ð´Ð¾Ñтупу да профілÑÑž Konqueror +Comment[bg]=Меню за доÑтъп до профилите на браузъра +Comment[bn]=সহজে বিà¦à¦¿à¦¨à§à¦¨ কংকরার পà§à¦°à§‹à¦«à¦¾à¦‡à¦² খোলার জনà§à¦¯ মেনৠ+Comment[bs]=Meni za pristup do profila Konquerora +Comment[ca]=Menú per accedir als perfils Konqueror +Comment[cs]=PÅ™Ãstup k profilům Konqueroru +Comment[csb]=Menu przistãpù do profilów Konquerora +Comment[da]=Menu for adgang til Konquerors profiler +Comment[de]=Vereinfachter Zugang zu den Konqueror-Profilen +Comment[el]=ÎœÎµÎ½Î¿Ï Ï€Ïόσβασης στα Ï€Ïοφίλ του Konqueror +Comment[eo]=Menuo por atingi Konkerantajn profilojn +Comment[es]=Menú para acceder a los perfiles de Konqueror +Comment[et]=Menüü Konquerori profiilide kasutamiseks +Comment[eu]=Konqueror profilak atzitzeko menua +Comment[fa]=گزینگان برای دستیابی به profileهای Konqueror +Comment[fi]=Valikko Konquerorin profiileille +Comment[fr]=Menu d'accès aux profils de Konqueror +Comment[fy]=Menu foar tagong ta de Konqueror-profielen +Comment[gl]=Aceso doado aos perfis de Konqueror +Comment[he]=תפריט גישה ×œ×¤×¨×•×¤×™×œ×™× ×©×œ Konqueror +Comment[hr]=Izbornik za pristupanje Konqueror profilima +Comment[hu]=Menü a Konqueror profiljainak eléréséhez +Comment[is]=Einföld leið að sniðmátum Konqueror +Comment[it]=Menu per accedere ai profili di Konqueror +Comment[ja]=Konqueror プãƒãƒ•ã‚¡ã‚¤ãƒ«ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=Konqueror-ის პრáƒáƒ¤áƒ˜áƒšáƒ”ბის წვდáƒáƒ›áƒ˜áƒ¡ მენიუ +Comment[kk]=Konqueror профильдеріне қатынау мәзірі +Comment[km]=ម៉ឺនុយ​សម្រាប់​ចូល​ដំណើរការ​ទម្រង់​របស់ Konqueror +Comment[lt]=Konqueror profilių pasiekimo meniu +Comment[mk]=Мени за приÑтапување до профилите на Konqueror +Comment[nb]=Meny for Konquerors profiler +Comment[nds]=Menü för Konqueror sien Profilen +Comment[ne]=कनà¥à¤•à¥à¤µà¥‡à¤°à¤° पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤² पहà¥à¤à¤šà¤•à¤¾ लागि मेनॠ+Comment[nl]=Menu voor toegang tot de Konqueror-profielen +Comment[nn]=Meny for Konqueror-profilane +Comment[pa]=ਕੋਨਕਿਉਰੋਰ ਪਰੋਫਾਇਲ ਲਈ ਸੌਖੀ ਪਹà©à©°à¨š ਲਈ ਮੇਨੂ +Comment[pl]=Menu dostÄ™pu do profili Konquerora +Comment[pt]=Um menu para aceder aos perfis do Konqueror +Comment[pt_BR]=Acesso fácil aos perfis do Konqueror +Comment[ro]=Meniu pentru accesul profilelor Konqueror +Comment[ru]=БыÑтрый доÑтуп к профилÑм Konqueror +Comment[se]=Fállu mii Äájeha Konqueror-profiillaid +Comment[sk]=Menu pre prÃstup k profilom pre Konqueror +Comment[sl]=Meni za dostop do profilov Konquerorja +Comment[sr]=Мени за приÑтуп Konqueror-овим профилима +Comment[sr@Latn]=Meni za pristup Konqueror-ovim profilima +Comment[sv]=Meny för att komma Ã¥t Konquerors profiler +Comment[te]=కాంకెరరౠపà±à°°à±Šà°«à±ˆà°²à±à°²à± చూసెందà±à°•à± కొరకౠపటà±à°Ÿà°¿ +Comment[th]=เมนูสำหรับเข้าใช้โปรไฟล์ขà¸à¸‡à¸„à¸à¸™à¹€à¸„วà¸à¸£à¹Œà¹€à¸£à¸à¸£à¹Œà¸§à¸”เร็ว +Comment[tr]=Konqueror profillerine kolay eriÅŸim menüsü +Comment[uk]=Меню Ð´Ð»Ñ Ð´Ð¾Ñтупу до профілів Konqueror +Comment[uz]=Konqueror profillarining menyusi +Comment[uz@cyrillic]=Konqueror профилларининг менюÑи +Comment[vi]=Thá»±c Ä‘Æ¡n truy cáºp đến các thông số của Konqueror +Comment[wa]=Dressêye poz aveur accès Ã¥s profils di Konqueror +Comment[zh_CN]=访问 Konqueror é…置文件的èœå• +Comment[zh_TW]=方便å˜å– Konqueror è¨å®šçµ„åˆçš„é¸å–® +Icon=konqueror + +X-KDE-Library=kickermenu_konqueror diff --git a/kicker/menuext/konq-profiles/konqy_menu.cpp b/kicker/menuext/konq-profiles/konqy_menu.cpp new file mode 100644 index 000000000..3ac09e050 --- /dev/null +++ b/kicker/menuext/konq-profiles/konqy_menu.cpp @@ -0,0 +1,102 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "konqy_menu.h" +#include <kiconloader.h> +#include <klocale.h> +#include <kglobal.h> +#include <kapplication.h> +#include <krun.h> +#include <kstandarddirs.h> +#include <kio/global.h> +#include <ksimpleconfig.h> + +#include <qregexp.h> +#include <qfileinfo.h> + +K_EXPORT_KICKER_MENUEXT(konqueror, KonquerorProfilesMenu) + +KonquerorProfilesMenu::KonquerorProfilesMenu(QWidget *parent, const char *name, const QStringList & /*args*/) +: KPanelMenu("", parent, name) +{ + static bool kdeprintIconsInitialized = false; + if ( !kdeprintIconsInitialized ) { + KGlobal::iconLoader()->addAppDir("kdeprint"); + kdeprintIconsInitialized = true; + } +} + +KonquerorProfilesMenu::~KonquerorProfilesMenu() +{ +} + +void KonquerorProfilesMenu::initialize() +{ + if (initialized()) clear(); + setInitialized(true); + + QStringList profiles = KGlobal::dirs()->findAllResources( "data", "konqueror/profiles/*", false, true ); + + m_profiles.resize(profiles.count()); + int id=1; + QStringList::ConstIterator pEnd = profiles.end(); + for (QStringList::ConstIterator pIt = profiles.begin(); pIt != pEnd; ++pIt ) + { + QFileInfo info( *pIt ); + QString profileName = KIO::decodeFileName( info.baseName() ); + QString niceName=profileName; + KSimpleConfig cfg( *pIt, true ); + if ( cfg.hasGroup( "Profile" ) ) + { + cfg.setGroup( "Profile" ); + if ( cfg.hasKey( "Name" ) ) + niceName = cfg.readEntry( "Name" ); + + insertItem(niceName, id); + m_profiles[id-1]=profileName; + id++; + } + } +} + +void KonquerorProfilesMenu::slotExec(int id) +{ + QStringList args; + args<<"--profile"<<m_profiles[id-1]; + kapp->kdeinitExec("konqueror", args); +} + +void KonquerorProfilesMenu::reload() +{ + initialize(); +} + +void KonquerorProfilesMenu::slotAboutToShow() +{ + reinitialize(); + KPanelMenu::slotAboutToShow(); +} + + +#include "konqy_menu.moc" + diff --git a/kicker/menuext/konq-profiles/konqy_menu.h b/kicker/menuext/konq-profiles/konqy_menu.h new file mode 100644 index 000000000..f47b026ee --- /dev/null +++ b/kicker/menuext/konq-profiles/konqy_menu.h @@ -0,0 +1,50 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _konqy_menu_h_ +#define _konqy_menu_h_ + +#include <kpanelmenu.h> + +#include <qvaluevector.h> + +class KonquerorProfilesMenu : public KPanelMenu +{ + Q_OBJECT + + public: + KonquerorProfilesMenu(QWidget *parent, const char *name, const QStringList & /*args*/); + ~KonquerorProfilesMenu(); + + protected slots: + void slotExec(int id); + void initialize(); + void slotAboutToShow(); + + protected: + void reload(); + QValueVector<QString> m_profiles; + +}; + +#endif diff --git a/kicker/menuext/konsole/Makefile.am b/kicker/menuext/konsole/Makefile.am new file mode 100644 index 000000000..907e79769 --- /dev/null +++ b/kicker/menuext/konsole/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_konsole.la + +kickermenu_konsole_la_SOURCES = konsole_mnu.cpp konsolebookmarkhandler.cpp konsolebookmarkmenu.cpp +kickermenu_konsole_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_konsole_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) + +kickermenu_konsole_la_METASOURCES = AUTO + +desktopmenu_DATA = konsolemenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_konsole.pot diff --git a/kicker/menuext/konsole/konsole_mnu.cpp b/kicker/menuext/konsole/konsole_mnu.cpp new file mode 100644 index 000000000..87df6f268 --- /dev/null +++ b/kicker/menuext/konsole/konsole_mnu.cpp @@ -0,0 +1,318 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> +#include <dirent.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <qdir.h> +#include <qfileinfo.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kio/global.h> +#include <klocale.h> +#include <krun.h> +#include <kshell.h> +#include <ksimpleconfig.h> +#include <kstandarddirs.h> + +#include "konsole_mnu.h" + +K_EXPORT_KICKER_MENUEXT(konsole, KonsoleMenu) + +KonsoleMenu::KonsoleMenu(QWidget *parent, const char *name, const QStringList& /* args */) + : KPanelMenu("", parent, name), + m_profileMenu(0), + m_bookmarksSession(0), + m_bookmarkHandlerSession(0) +{ +} + +KonsoleMenu::~KonsoleMenu() +{ + KGlobal::locale()->removeCatalogue("libkickermenu_konsole"); +} + +static void insertItemSorted(KPopupMenu *menu, + const QIconSet &iconSet, + const QString &txt, int id) +{ + const int defaultId = 1; // The id of the 'new' item. + int index = menu->indexOf(defaultId); + int count = menu->count(); + if (index >= 0) + { + index++; // Skip separator + while(true) + { + index++; + if (index >= count) + { + index = -1; // Insert at end + break; + } + if (menu->text(menu->idAt(index)) > txt) + break; // Insert before this item + } + } + menu->insertItem(iconSet, txt, id, index); +} + + +void KonsoleMenu::initialize() +{ + if (initialized()) + { + clear(); + } + else + { + kapp->iconLoader()->addAppDir("konsole"); + } + + setInitialized(true); + + QStringList list = KGlobal::dirs()->findAllResources("data", + "konsole/*.desktop", + false, true); + + QString defaultShell = locate("data", "konsole/shell.desktop"); + list.prepend(defaultShell); + + int id = 1; + + sessionList.clear(); + for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) + { + if ((*it == defaultShell) && (id != 1)) + { + continue; + } + + KSimpleConfig conf(*it, true /* read only */); + conf.setDesktopGroup(); + QString text = conf.readEntry("Name"); + + // try to locate the binary + QString exec= conf.readPathEntry("Exec"); + if (exec.startsWith("su -c \'")) + { + exec = exec.mid(7,exec.length()-8); + } + + exec = KRun::binaryName(exec, false); + exec = KShell::tildeExpand(exec); + QString pexec = KGlobal::dirs()->findExe(exec); + if (text.isEmpty() || + conf.readEntry("Type") != "KonsoleApplication" || + (!exec.isEmpty() && pexec.isEmpty())) + { + continue; + } + insertItemSorted(this, SmallIconSet(conf.readEntry("Icon", "konsole")), + text, id++); + QFileInfo fi(*it); + sessionList.append(fi.baseName(true)); + + if (id == 2) + { + insertSeparator(); + } + } + + m_bookmarkHandlerSession = new KonsoleBookmarkHandler(this, false); + m_bookmarksSession = m_bookmarkHandlerSession->menu(); + insertSeparator(); + insertItem(SmallIconSet("keditbookmarks"), + i18n("New Session at Bookmark"), m_bookmarksSession); + connect(m_bookmarkHandlerSession, + SIGNAL(openURL(const QString&, const QString&)), + SLOT(newSession(const QString&, const QString&))); + + + screenList.clear(); + QCString screenDir = getenv("SCREENDIR"); + + if (screenDir.isEmpty()) + { + screenDir = QFile::encodeName(QDir::homeDirPath()) + "/.screen/"; + } + + QStringList sessions; + // Can't use QDir as it doesn't support FIFOs :( + DIR *dir = opendir(screenDir); + if (dir) + { + struct dirent *entry; + while ((entry = readdir(dir))) + { + QCString path = screenDir + "/" + entry->d_name; + struct stat st; + if (stat(path, &st) != 0) + { + continue; + } + + int fd; + if (S_ISFIFO(st.st_mode) && !(st.st_mode & 0111) && // xbit == attached + (fd = open(path, O_WRONLY | O_NONBLOCK)) != -1) + { + ::close(fd); + screenList.append(QFile::decodeName(entry->d_name)); + insertItem(SmallIconSet("konsole"), + i18n("Screen is a program controlling screens!", + "Screen at %1").arg(entry->d_name), id); + id++; + } + } + closedir(dir); + } + + // reset id as we are now going to populate the profiles submenu + id = 0; + + delete m_profileMenu; + m_profileMenu = new KPopupMenu(this); + QStringList profiles = KGlobal::dirs()->findAllResources("data", + "konsole/profiles/*", + false, true ); + m_profiles.resize(profiles.count()); + QStringList::ConstIterator pEnd = profiles.end(); + for (QStringList::ConstIterator pIt = profiles.begin(); pIt != pEnd; ++pIt) + { + QFileInfo info(*pIt); + QString profileName = KIO::decodeFileName(info.baseName()); + QString niceName = profileName; + KSimpleConfig cfg(*pIt, true); + if (cfg.hasGroup("Profile")) + { + cfg.setGroup("Profile"); + if (cfg.hasKey("Name")) + { + niceName = cfg.readEntry("Name"); + } + } + + m_profiles[id] = profileName; + ++id; + m_profileMenu->insertItem(niceName, id); + } + + int profileID = insertItem(i18n("New Session Using Profile"), + m_profileMenu); + if (id == 1) + { + // we don't have any profiles, disable the menu + setItemEnabled(profileID, false); + } + connect(m_profileMenu, SIGNAL(activated(int)), SLOT(launchProfile(int))); + + insertSeparator(); + insertItem(SmallIconSet("reload"), + i18n("Reload Sessions"), this, SLOT(reinitialize())); +} + +void KonsoleMenu::slotExec(int id) +{ + if (id < 1) + { + return; + } + + --id; + kapp->propagateSessionManager(); + QStringList args; + if (static_cast<unsigned int>(id) < sessionList.count()) + { + args << "--type"; + args << sessionList[id]; + } + else + { + args << "-e"; + args << "screen"; + args << "-r"; + args << screenList[id - sessionList.count()]; + } + KApplication::kdeinitExec("konsole", args); + return; +} + +void KonsoleMenu::launchProfile(int id) +{ + if (id < 1 || id > m_profiles.count()) + { + return; + } + + --id; + // this is a session, not a bookmark, so execute that instead + QStringList args; + args << "--profile" << m_profiles[id]; + kapp->kdeinitExec("konsole", args); +} + +KURL KonsoleMenu::baseURL() const +{ + KURL url; + /*url.setPath(se->getCwd()+"/");*/ + return url; +} + +void KonsoleMenu::newSession(const QString& sURL, const QString& title) +{ + QStringList args; + + KURL url = KURL(sURL); + if ((url.protocol() == "file") && (url.hasPath())) + { + args << "-T" << title; + args << "--workdir" << url.path(); + KApplication::kdeinitExec("konsole", args); + return; + } + else if ((!url.protocol().isEmpty()) && (url.hasHost())) + { + QString protocol = url.protocol(); + QString host = url.host(); + args << "-T" << title; + args << "-e" << protocol.latin1(); /* argv[0] == command to run. */ + if (url.hasUser()) { + args << "-l" << url.user().latin1(); + } + args << host.latin1(); + KApplication::kdeinitExec("konsole", args); + return; + } + /* + * We can't create a session without a protocol. + * We should ideally popup a warning, about an invalid bookmark. + */ +} + + +#include "konsole_mnu.moc" diff --git a/kicker/menuext/konsole/konsole_mnu.h b/kicker/menuext/konsole/konsole_mnu.h new file mode 100644 index 000000000..988764124 --- /dev/null +++ b/kicker/menuext/konsole/konsole_mnu.h @@ -0,0 +1,64 @@ +/***************************************************************** + +Copyright (c) 1996-2001 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _konsole_mnu_h_ +#define _konsole_mnu_h_ + +#include <qvaluevector.h> + +#include <kpanelmenu.h> +#include <klibloader.h> + +#include "konsolebookmarkmenu.h" +#include "konsolebookmarkhandler.h" + + +class KonsoleMenu : public KPanelMenu/*, public KPReloadObject*/ +{ + Q_OBJECT + +public: + KonsoleMenu(QWidget *parent, const char *name, const QStringList& /* args */); + ~KonsoleMenu(); + KURL baseURL() const; + + +protected slots: + void slotExec(int id); + void launchProfile(int id); + void initialize(); + void newSession(const QString& sURL, const QString& title); + + +private: + QStringList sessionList; + QStringList screenList; + QValueVector<QString> m_profiles; + KPopupMenu* m_profileMenu; + KPopupMenu* m_bookmarksSession; + + KonsoleBookmarkHandler *m_bookmarkHandlerSession; +}; + +#endif + diff --git a/kicker/menuext/konsole/konsolebookmarkhandler.cpp b/kicker/menuext/konsole/konsolebookmarkhandler.cpp new file mode 100644 index 000000000..c9f8e2806 --- /dev/null +++ b/kicker/menuext/konsole/konsolebookmarkhandler.cpp @@ -0,0 +1,117 @@ +// Born as kdelibs/kio/kfile/kfilebookmarkhandler.cpp + +#include <stdio.h> +#include <stdlib.h> + +#include <qtextstream.h> + +#include <kbookmarkimporter.h> +#include <kmimetype.h> +#include <kpopupmenu.h> +#include <ksavefile.h> +#include <kstandarddirs.h> + +#include "konsole_mnu.h" +#include "konsolebookmarkmenu.h" +#include "konsolebookmarkhandler.h" + +KonsoleBookmarkHandler::KonsoleBookmarkHandler( KonsoleMenu *konsole, bool ) + : QObject( konsole, "KonsoleBookmarkHandler" ), + KBookmarkOwner(), + m_konsole( konsole ), + m_importStream( 0L ) +{ + m_menu = new KPopupMenu( konsole, "bookmark menu" ); + + QString file = locate( "data", "konsole/bookmarks.xml" ); + if ( file.isEmpty() ) + file = locateLocal( "data", "konsole/bookmarks.xml" ); + + // import old bookmarks + if ( !KStandardDirs::exists( file ) ) { + QString oldFile = locate( "data", "kfile/bookmarks.html" ); + if ( !oldFile.isEmpty() ) + importOldBookmarks( oldFile, file ); + } + + KBookmarkManager *manager = KBookmarkManager::managerForFile( file, false); + manager->setUpdate( true ); + manager->setShowNSBookmarks( false ); + + connect( manager, SIGNAL( changed(const QString &, const QString &) ), + SLOT( slotBookmarksChanged(const QString &, const QString &) ) ); + m_bookmarkMenu = new KonsoleBookmarkMenu( manager, this, m_menu, + NULL, false, /*Not toplevel*/ + false /*No 'Add Bookmark'*/ ); +} + +QString KonsoleBookmarkHandler::currentURL() const +{ + return m_konsole->baseURL().url(); +} + +void KonsoleBookmarkHandler::importOldBookmarks( const QString& path, + const QString& destinationPath ) +{ + KSaveFile file( destinationPath ); + if ( file.status() != 0 ) + return; + + m_importStream = file.textStream(); + *m_importStream << "<!DOCTYPE xbel>\n<xbel>\n"; + + KNSBookmarkImporter importer( path ); + connect( &importer, + SIGNAL( newBookmark( const QString&, const QCString&, const QString& )), + SLOT( slotNewBookmark( const QString&, const QCString&, const QString& ))); + connect( &importer, + SIGNAL( newFolder( const QString&, bool, const QString& )), + SLOT( slotNewFolder( const QString&, bool, const QString& ))); + connect( &importer, SIGNAL( newSeparator() ), SLOT( newSeparator() )); + connect( &importer, SIGNAL( endMenu() ), SLOT( endMenu() )); + + importer.parseNSBookmarks( false ); + + *m_importStream << "</xbel>"; + + file.close(); + m_importStream = 0L; +} + +void KonsoleBookmarkHandler::slotNewBookmark( const QString& /*text*/, + const QCString& url, + const QString& additionalInfo ) +{ + *m_importStream << "<bookmark icon=\"" << KMimeType::iconForURL( KURL( url ) ); + *m_importStream << "\" href=\"" << QString::fromUtf8(url) << "\">\n"; + *m_importStream << "<title>" << (additionalInfo.isEmpty() ? QString::fromUtf8(url) : additionalInfo) << "</title>\n</bookmark>\n"; +} + +void KonsoleBookmarkHandler::slotNewFolder( const QString& text, bool /*open*/, + const QString& /*additionalInfo*/ ) +{ + *m_importStream << "<folder icon=\"bookmark_folder\">\n<title=\""; + *m_importStream << text << "\">\n"; +} + +void KonsoleBookmarkHandler::slotBookmarksChanged( const QString &, + const QString & ) +{ + // This is called when someone changes bookmarks in konsole.... + m_bookmarkMenu->slotBookmarksChanged(""); +} + +void KonsoleBookmarkHandler::newSeparator() +{ + *m_importStream << "<separator/>\n"; +} + +void KonsoleBookmarkHandler::endFolder() +{ + *m_importStream << "</folder>\n"; +} + +void KonsoleBookmarkHandler::virtual_hook( int id, void* data ) +{ KBookmarkOwner::virtual_hook( id, data ); } + +#include "konsolebookmarkhandler.moc" diff --git a/kicker/menuext/konsole/konsolebookmarkhandler.h b/kicker/menuext/konsole/konsolebookmarkhandler.h new file mode 100644 index 000000000..b22f0d03d --- /dev/null +++ b/kicker/menuext/konsole/konsolebookmarkhandler.h @@ -0,0 +1,60 @@ +// Born as kdelibs/kio/kfile/kfilebookmarkhandler.h + +#ifndef KONSOLEBOOKMARKHANDLER_H +#define KONSOLEBOOKMARKHANDLER_H + +#include <kbookmarkmanager.h> +#include "konsolebookmarkmenu.h" + + +class QTextStream; +class KPopupMenu; +class KonsoleBookmarkMenu; +class KonsoleMenu; + +class KonsoleBookmarkHandler : public QObject, public KBookmarkOwner +{ + Q_OBJECT + +public: + KonsoleBookmarkHandler( KonsoleMenu *konsole, bool toplevel ); + + QPopupMenu * popupMenu(); + + // KBookmarkOwner interface: + virtual void openBookmarkURL( const QString& url, const QString& title ) + { emit openURL( url, title ); } + virtual QString currentURL() const; + + KPopupMenu *menu() const { return m_menu; } + +signals: + void openURL( const QString& url, const QString& title ); + +private slots: + // for importing + void slotNewBookmark( const QString& text, const QCString& url, + const QString& additionalInfo ); + void slotNewFolder( const QString& text, bool open, + const QString& additionalInfo ); + void slotBookmarksChanged( const QString &, const QString & caller ); + void newSeparator(); + void endFolder(); + +private: + void importOldBookmarks( const QString& path, const QString& destinationPath ); + + KonsoleMenu *m_konsole; + KPopupMenu *m_menu; + KonsoleBookmarkMenu *m_bookmarkMenu; + QTextStream *m_importStream; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class KonsoleBookmarkHandlerPrivate; + KonsoleBookmarkHandlerPrivate *d; +}; + + +#endif // KONSOLEBOOKMARKHANDLER_H diff --git a/kicker/menuext/konsole/konsolebookmarkmenu.cpp b/kicker/menuext/konsole/konsolebookmarkmenu.cpp new file mode 100644 index 000000000..b10d26c40 --- /dev/null +++ b/kicker/menuext/konsole/konsolebookmarkmenu.cpp @@ -0,0 +1,187 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <qtextstream.h> + +#include <kbookmarkimporter.h> +#include <kmimetype.h> +#include <kpopupmenu.h> +#include <ksavefile.h> +#include <kstandarddirs.h> +//#include <kbookmarkmenu.h> + +#include "konsole_mnu.h" +#include "konsolebookmarkmenu.h" +#include "konsolebookmarkhandler.h" + +#include <qfile.h> + +#include <kaction.h> +#include <klocale.h> + + +KonsoleBookmarkMenu::KonsoleBookmarkMenu( KBookmarkManager* mgr, + KonsoleBookmarkHandler * _owner, KPopupMenu * _parentMenu, + KActionCollection *collec, bool _isRoot, bool _add, + const QString & parentAddress ) +: KBookmarkMenu( mgr, _owner, _parentMenu, collec, _isRoot, _add, + parentAddress), + m_kOwner(_owner) +{ + /* + * First, we disconnect KBookmarkMenu::slotAboutToShow() + * Then, we connect KonsoleBookmarkMenu::slotAboutToShow(). + * They are named differently because the SLOT() macro thinks we want + * KonsoleBookmarkMenu::KBookmarkMenu::slotAboutToShow() + * Could this be solved if slotAboutToShow() is virtual in KBookmarMenu? + */ + disconnect( _parentMenu, SIGNAL( aboutToShow() ), this, + SLOT( slotAboutToShow() ) ); + connect( _parentMenu, SIGNAL( aboutToShow() ), + SLOT( slotAboutToShow2() ) ); +} + +/* + * Duplicate this exactly because KBookmarkMenu::slotBookmarkSelected can't + * be overrided. I would have preferred to NOT have to do this. + * + * Why did I do this? + * - when KBookmarkMenu::fillbBookmarkMenu() creates sub-KBookmarkMenus. + * - when ... adds KActions, it uses KBookmarkMenu::slotBookmarkSelected() + * instead of KonsoleBookmarkMenu::slotBookmarkSelected(). + */ +void KonsoleBookmarkMenu::slotAboutToShow2() +{ + // Did the bookmarks change since the last time we showed them ? + if ( m_bDirty ) + { + m_bDirty = false; + refill(); + } +} + +void KonsoleBookmarkMenu::refill() +{ + //kdDebug(1203) << "KBookmarkMenu::refill()" << endl; + m_lstSubMenus.clear(); + QPtrListIterator<KAction> it( m_actions ); + for (; it.current(); ++it ) + it.current()->unplug( m_parentMenu ); + m_parentMenu->clear(); + m_actions.clear(); + fillBookmarkMenu(); + m_parentMenu->adjustSize(); +} + +void KonsoleBookmarkMenu::fillBookmarkMenu() +{ + if ( m_bIsRoot ) + { + if ( m_bAddBookmark ) + addAddBookmark(); + + addEditBookmarks(); + + if ( m_bAddBookmark ) + addNewFolder(); + + if ( m_pManager->showNSBookmarks() + && QFile::exists( KNSBookmarkImporter::netscapeBookmarksFile() ) ) + { + m_parentMenu->insertSeparator(); + + KActionMenu * actionMenu = new KActionMenu( i18n("Netscape Bookmarks"), + "netscape", + m_actionCollection, 0L ); + actionMenu->plug( m_parentMenu ); + m_actions.append( actionMenu ); + KonsoleBookmarkMenu *subMenu = new KonsoleBookmarkMenu( m_pManager, + m_kOwner, actionMenu->popupMenu(), + m_actionCollection, false, + m_bAddBookmark, QString::null ); + m_lstSubMenus.append(subMenu); + connect( actionMenu->popupMenu(), SIGNAL(aboutToShow()), subMenu, + SLOT(slotNSLoad())); + } + } + + KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup(); + Q_ASSERT(!parentBookmark.isNull()); + bool separatorInserted = false; + for ( KBookmark bm = parentBookmark.first(); !bm.isNull(); + bm = parentBookmark.next(bm) ) + { + QString text = bm.text(); + text.replace( '&', "&&" ); + if ( !separatorInserted && m_bIsRoot) { // inserted before the first konq bookmark, to avoid the separator if no konq bookmark + m_parentMenu->insertSeparator(); + separatorInserted = true; + } + if ( !bm.isGroup() ) + { + if ( bm.isSeparator() ) + { + m_parentMenu->insertSeparator(); + } + else + { + // kdDebug(1203) << "Creating URL bookmark menu item for " << bm.text() << endl; + // create a normal URL item, with ID as a name + KAction * action = new KAction( text, bm.icon(), 0, + this, SLOT( slotBookmarkSelected() ), + m_actionCollection, bm.url().url().utf8() ); + + action->setStatusText( bm.url().prettyURL() ); + + action->plug( m_parentMenu ); + m_actions.append( action ); + } + } + else + { + // kdDebug(1203) << "Creating bookmark submenu named " << bm.text() << endl; + KActionMenu * actionMenu = new KActionMenu( text, bm.icon(), + m_actionCollection, 0L ); + actionMenu->plug( m_parentMenu ); + m_actions.append( actionMenu ); + KonsoleBookmarkMenu *subMenu = new KonsoleBookmarkMenu( m_pManager, + m_kOwner, actionMenu->popupMenu(), + m_actionCollection, false, + m_bAddBookmark, bm.address() ); + m_lstSubMenus.append( subMenu ); + } + } + + if ( !m_bIsRoot && m_bAddBookmark ) + { + m_parentMenu->insertSeparator(); + addAddBookmark(); + addNewFolder(); + } +} + +void KonsoleBookmarkMenu::slotBookmarkSelected() +{ + KAction * a; + QString b; + + if ( !m_pOwner ) return; // this view doesn't handle bookmarks... + a = (KAction*)sender(); + b = a->text(); + m_kOwner->openBookmarkURL( QString::fromUtf8(sender()->name()), /* URL */ + ( (KAction *)sender() )->text() /* Title */ ); +} + +void KonsoleBookmarkMenu::slotNSBookmarkSelected() +{ + KAction *a; + QString b; + + QString link(sender()->name()+8); + a = (KAction*)sender(); + b = a->text(); + m_kOwner->openBookmarkURL( link, /*URL */ + ( (KAction *)sender() )->text() /* Title */ ); +} + +#include "konsolebookmarkmenu.moc" diff --git a/kicker/menuext/konsole/konsolebookmarkmenu.h b/kicker/menuext/konsole/konsolebookmarkmenu.h new file mode 100644 index 000000000..65e87f0f5 --- /dev/null +++ b/kicker/menuext/konsole/konsolebookmarkmenu.h @@ -0,0 +1,58 @@ +#ifndef KONSOLEBOOKMARKMENU_H +#define KONSOLEBOOKMARKMENU_H + +#include <qptrlist.h> +#include <qptrstack.h> +#include <qobject.h> +#include <sys/types.h> +#include <kbookmark.h> +#include <kbookmarkmenu.h> + +#include "konsolebookmarkhandler.h" + + +class QString; +class KBookmark; +class KAction; +class KActionMenu; +class KActionCollection; +class KBookmarkOwner; +class KBookmarkMenu; +class KPopupMenu; +class KonsoleBookmarkMenu; + +class KonsoleBookmarkMenu : public KBookmarkMenu +{ + Q_OBJECT + +public: + KonsoleBookmarkMenu( KBookmarkManager* mgr, + KonsoleBookmarkHandler * _owner, KPopupMenu * _parentMenu, + KActionCollection *collec, bool _isRoot, + bool _add = true, const QString & parentAddress = ""); + + void fillBookmarkMenu(); + +public slots: + +signals: + +private slots: + +private: + KonsoleBookmarkHandler * m_kOwner; + +protected slots: + void slotAboutToShow2(); + void slotBookmarkSelected(); + void slotNSBookmarkSelected(); + +protected: + void refill(); + +private: + class KonsoleBookmarkMenuPrivate; + KonsoleBookmarkMenuPrivate *d; +}; + +#endif // KONSOLEBOOKMARKMENU_H diff --git a/kicker/menuext/konsole/konsolemenu.desktop b/kicker/menuext/konsole/konsolemenu.desktop new file mode 100644 index 000000000..5766d7f03 --- /dev/null +++ b/kicker/menuext/konsole/konsolemenu.desktop @@ -0,0 +1,137 @@ +[Desktop Entry] +Name=Terminal Sessions +Name[af]=Terminaal Sessies +Name[ar]=جلسات مطرا٠سطر الأوامر +Name[az]=Terminal Ä°clasları +Name[be]=ТÑÑ€Ð¼Ñ–Ð½Ð°Ð»ÑŒÐ½Ñ‹Ñ ÑеÑÑ–Ñ– +Name[bg]=Терминални ÑеÑии +Name[bn]=টারà§à¦®à¦¿à¦¨à¦¾à¦² সেশন +Name[br]=Dalc'hoù an termenell +Name[bs]=Sesije terminala +Name[ca]=Sessions de terminal +Name[cs]=Terminálové relace +Name[csb]=Sesëje terminala +Name[cy]=Sesiynnau Terfynell +Name[da]=Terminalsessioner +Name[de]=Terminalsitzungen +Name[el]=ΣυνεδÏίες τεÏÎ¼Î±Ï„Î¹ÎºÎ¿Ï +Name[eo]=Terminalaj seancoj +Name[es]=Sesiones de terminal +Name[et]=Terminali seansid +Name[eu]=Terminal saioak +Name[fa]=نشستهای پایانه +Name[fi]=Komentoikkunaistunnot +Name[fr]=Sessions de terminal +Name[fy]=Terminal-sesjes +Name[ga]=Seisiúin Teirminéil +Name[gl]=Sesións de Terminal +Name[he]=משימות מסוף +Name[hi]=टरà¥à¤®à¤¿à¤¨à¤² सतà¥à¤° +Name[hr]=Terminalske sesije +Name[hu]=Terminálablakok +Name[is]=Skjáhermisforrit +Name[it]=Sessioni terminale +Name[ja]=ターミナルセッション +Name[ka]=სერმინáƒáƒšáƒ˜áƒ¡ სეáƒáƒœáƒ¡áƒ”ბი +Name[kk]=Терминал ÑеанÑтары +Name[km]=សមáŸáž™â€‹ážŸáŸ’ážáž¶áž“ីយ +Name[ko]=í„°ë¯¸ë„ í”„ë¡œê·¸ëž¨ +Name[lo]=ໂປຣà»àºàº£àº¡à»€àº—ີມິເນລ +Name[lt]=Terminalo sesijos +Name[lv]=TerminÄla sesijas +Name[mk]=ТерминалÑки ÑеÑии +Name[mn]=Терминал-Суултууд +Name[ms]=Sesi Terminal +Name[mt]=Sessjonijiet tat-terminal +Name[nb]=Terminaløkter +Name[nds]=Terminal-Törns +Name[ne]=टरà¥à¤®à¤¿à¤¨à¤² सतà¥à¤° +Name[nl]=Terminal-sessies +Name[nn]=Terminaløkter +Name[nso]=Ditiragalo tsa Terminal +Name[pa]=ਟਰਮੀਨਲ ਸ਼ੈਸ਼ਨ +Name[pl]=Sesje terminala +Name[pt]=Sessões de Terminal +Name[pt_BR]=Sessões de Terminal +Name[ro]=Sesiuni de terminal +Name[ru]=Терминальные ÑеанÑÑ‹ +Name[rw]=Imikoro Ihera +Name[se]=Terminálbargovuorut +Name[sk]=Sedenia terminálu +Name[sl]=Terminalske seje +Name[sr]=СеÑије терминала +Name[sr@Latn]=Sesije terminala +Name[sv]=Terminalsessioner +Name[ta]=கடைசி அமரà¯à®µà¯à®•à®³à¯ +Name[te]=టెరà±à°®à°¿à°¨à°²à± సెషనà±à°²à± +Name[tg]=ҶалаÑаҳои терминал +Name[th]=เซสชันขà¸à¸‡à¹€à¸—à¸à¸£à¹Œà¸¡à¸´à¸™à¸±à¸¥ +Name[tr]=Uçbirim Oturumları +Name[tt]=Terminal Sessiläre +Name[uk]=СеанÑи терміналів +Name[uz]=Terminal seanslari +Name[uz@cyrillic]=Терминал ÑеанÑлари +Name[ven]=Zwitenwa zwa theminala +Name[vi]=Phiên chạy đầu cuối +Name[wa]=Sessions do terminÃ¥ +Name[xh]=Intlanganiso Yesiphelo sendlela +Name[zh_CN]=ç»ˆç«¯ä¼šè¯ +Name[zh_TW]=終端機工作階段 +Name[zu]=Iziqendu Zangaphandle +Comment=Menu for starting a terminal emulator with a session or bookmark +Comment[af]='n Kieslys wat 'n terminaal emuleerder met 'n sessie of boekmerk kan begin +Comment[ar]=قائمة لبدء تشغيل مضاه٠مطرا٠مع جلسة أو علامة موقع +Comment[be]=Меню Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку ÑмулÑтара Ñ‚Ñрміналу з ÑеÑÑ–Ñй ці закладкай +Comment[bg]=Меню за Ñтартиране на ÑеÑÐ¸Ñ Ð² терминален прозорец +Comment[bs]=Meni za pokretanje simulatora terminala sa sesijom ili zabiljeÅ¡kom +Comment[ca]=Menú per engegar un emulador de terminal amb una sessió o punt +Comment[cs]=NabÃdka pro spuÅ¡tÄ›nà teminálu s relacà nebo záložkou +Comment[csb]=Menu zrëszëniô òkna terminala ze spamiãtónÄ… sesëjÄ… abò załóżka +Comment[da]=Menu til at starte en terminalemulator med en session eller bogmærke +Comment[de]=Menü zum Starten des Terminal-Emulators mit einer Sitzung oder Lesezeichen +Comment[el]=ÎœÎµÎ½Î¿Ï Î³Î¹Î± την εκκίνηση ενός εξομοιωτή τεÏÎ¼Î±Ï„Î¹ÎºÎ¿Ï Î¼Îµ μια συνεδÏία ή σελιδοδείκτη +Comment[eo]=Menuo por lanĉi terminalsimulilon jam ÅarÄita kun seaco aÅ legosigno +Comment[es]=Menú para iniciar un emulador de terminal con una sesión o marcador +Comment[et]=Menüü seansi või järjehoidja käivitamiseks terminali emulaatoris +Comment[eu]=Terminal emuladorea saio edo laster-markaz abiarazteko menua +Comment[fa]=گزینگانی برای آغاز مقلد پایانه، توسط یک نشست یا چوب ‌ال٠+Comment[fi]=Valikko pääteikkunan käynnistämiseen istunnon tai kirjanmerkin kanssa +Comment[fr]=Menu permettant de démarrer un émulateur de terminal à partir d'une session ou un signet +Comment[fy]=Menu foar it begjinnen fan in terminalemulaasje mei in sesje of blêdwizer +Comment[gl]=Menu para lanzar un emulador de terminal +Comment[he]=תפריט להפעלת מסוף ×¢× ×”×¤×¢×œ×” ×ו ×¡×™×ž× ×™×™×” +Comment[hr]=Izbornik za pokretanje terminalske emulacije putem sesije ili oznake +Comment[hu]=Menü parancsértelmezÅ‘ indÃtásához (könyvjelzÅ‘vel is) +Comment[is]=Valmynd til að ræsa skjáhermi með setu eða bókamerki +Comment[it]=Menu per l'emulatore di terminale con una data sessione o segnalibro +Comment[ja]=指定ã—ãŸã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚„ブックマーク先ã§ã‚¿ãƒ¼ãƒŸãƒŠãƒ«ã‚¨ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚¿ã‚’èµ·å‹•ã—ã¾ã™ +Comment[kk]=Терминал ÑеанÑын не бетбелгіні ашу мәзірі +Comment[km]=ម៉ឺនុយ​សម្រាប់​ចាប់ផ្ដើម​កម្មវិធី​ážáŸ’រាប់ážáž¶áž˜â€‹áž€áž˜áŸ’មវិធី​ស្ážáž¶áž“ីយ​ជា​មួយ​នឹង​សមáŸáž™ ឬ​ចំណាំ +Comment[lt]=Meniu terminalo emuliatoriaus paleidimui su tam tikra sesija ar - nuo žymeklio +Comment[mk]=Мени за Ñтартување на терминалÑки емулатор Ñо ÑеÑија или обележувач +Comment[nb]=Meny for Ã¥ starte en terminalemulator med en økt eller et bokmerke +Comment[nds]=Menü för dat Starten vun en Terminal-Emulator mit Leestekens oder Törns +Comment[ne]=सतà¥à¤° वा पà¥à¤¸à¥à¤¤à¤•à¤šà¤¿à¤¨à¥‹à¤¸à¤à¤— टरà¥à¤®à¤¿à¤¨à¤² इमà¥à¤²à¥‡à¤Ÿà¤° सà¥à¤°à¥à¤†à¤¤ गरà¥à¤¨à¤•à¤¾ लागि मेनॠ+Comment[nl]=Menu voor het starten van een terminalemulatie met een sessie of bladwijzer +Comment[nn]=Meny for Ã¥ starta ein terminalemulator med ei økt eller eit bokmerke +Comment[pl]=Menu uruchomienia okna terminala z zapamiÄ™tanÄ… sesjÄ… lub zakÅ‚adkÄ… +Comment[pt]=Um menu para iniciar um emulador de terminal com uma sessão ou favorito +Comment[pt_BR]=Menu para inÃcio de um emulador de terminal, com uma sessão ou favorito +Comment[ro]=Meniu pentru pornirea unui emulator de terminal cu o sesiune sau semn de carte +Comment[ru]=БыÑтрый доÑтуп к ÑеанÑам и закладкам терминала +Comment[sk]=Menu pre spustenie emulátora terminálu so sedenÃm alebo záložkou +Comment[sl]=Meni za zaganjanje terminalskega emulatorja s sejo ali zaznamkom +Comment[sr]=Мени за покретање емулатора терминала Ñа ÑеÑијом или маркером +Comment[sr@Latn]=Meni za pokretanje emulatora terminala sa sesijom ili markerom +Comment[sv]=Meny för att starta en terminalemulator med en session eller bokmärke +Comment[th]=เมนูสำหรับเริ่มโปรà¹à¸à¸£à¸¡à¸ˆà¸³à¸¥à¸à¸‡à¹€à¸—à¸à¸£à¹Œà¸¡à¸´à¸™à¸±à¸¥ พร้à¸à¸¡à¸à¸±à¸šà¸§à¸²à¸£à¸° หรืà¸à¸—ี่คั่นหน้า +Comment[tr]=Bir uçbirim düzenleyiciyi oturum ya da yer imi ile açmanızı saÄŸlar +Comment[uk]=Меню Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку терміналу емулÑтора через ÑÐµÐ°Ð½Ñ Ð°Ð±Ð¾ закладку +Comment[vi]=Thá»±c Ä‘Æ¡n chạy má»™t trình đầu cuối vá»›i má»™t phiên chạy hay má»™t địa chỉ lÆ°u trong sổ +Comment[wa]=Dressêye po-z enonder on terminÃ¥ avou ene session ou ene rimÃ¥ke +Comment[zh_CN]=以会è¯æˆ–书ç¾å¯åŠ¨ç»ˆç«¯æ¨¡æ‹Ÿå™¨çš„èœå• +Comment[zh_TW]=用來啟動作æ¥éšŽæ®µå’Œæ›¸ç±¤çš„終端機模擬程å¼çš„é¸å–® +Icon=konsole + +X-KDE-Library=kickermenu_konsole +X-KDE-AuthorizeAction=shell_access diff --git a/kicker/menuext/prefmenu/Makefile.am b/kicker/menuext/prefmenu/Makefile.am new file mode 100644 index 000000000..2ccbb4ba2 --- /dev/null +++ b/kicker/menuext/prefmenu/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I../../libkicker -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_prefmenu.la + +kickermenu_prefmenu_la_SOURCES = prefmenu.cpp +kickermenu_prefmenu_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_prefmenu_la_LIBADD = $(LIB_KDEUI) $(top_builddir)/kicker/libkicker/libkickermain.la + +kickermenu_prefmenu_la_METASOURCES = AUTO + +desktopmenu_DATA = prefmenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_prefmenu.pot + +prefmenu.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/menuext/prefmenu/prefmenu.cpp b/kicker/menuext/prefmenu/prefmenu.cpp new file mode 100644 index 000000000..dd157d2cb --- /dev/null +++ b/kicker/menuext/prefmenu/prefmenu.cpp @@ -0,0 +1,394 @@ +/***************************************************************** + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qcursor.h> +#include <qtimer.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kservice.h> +#include <kservicegroup.h> +#include <kstandarddirs.h> +#include <ksycoca.h> +#include <kurl.h> +#include <kurldrag.h> + +#include "global.h" +#include "kickerSettings.h" +#include "prefmenu.h" + +K_EXPORT_KICKER_MENUEXT(prefmenu, PrefMenu) + +const int idStart = 4242; + +PrefMenu::PrefMenu(QWidget *parent, + const char *name, + const QStringList &/*args*/) + : KPanelMenu(i18n("Settings"), parent, name), + m_clearOnClose(false) +{ +} + +PrefMenu::PrefMenu(const QString& label, + const QString& root, + QWidget *parent) + : KPanelMenu(label, parent), + m_clearOnClose(false), + m_root(root) +{ + m_subMenus.setAutoDelete(true); + + connect(KSycoca::self(), SIGNAL(databaseChanged()), + this, SLOT(clearOnClose())); + + connect(this, SIGNAL(aboutToHide()), + this, SLOT(aboutToClose())); +} + +PrefMenu::~PrefMenu() +{ +} + +void PrefMenu::insertMenuItem(KService::Ptr& s, + int nId, + int nIndex, + const QStringList *suppressGenericNames) +{ + QString serviceName = s->name(); + // add comment + QString comment = s->genericName(); + if (!comment.isEmpty()) + { + if (KickerSettings::menuEntryFormat() == KickerSettings::NameAndDescription) + { + if (!suppressGenericNames || + !suppressGenericNames->contains(s->untranslatedGenericName())) + { + serviceName = QString("%1 (%2)").arg(serviceName).arg(comment); + } + } + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName) + { + serviceName = QString("%1 (%2)").arg(comment).arg(serviceName); + } + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly) + { + serviceName = comment; + } + } + + // restrict menu entries to a sane length + if (serviceName.length() > 60) + { + serviceName.truncate(57); + serviceName += "..."; + } + + // check for NoDisplay + if (s->noDisplay()) + { + return; + } + + // ignore dotfiles. + if ((serviceName.at(0) == '.')) + { + return; + } + + // item names may contain ampersands. To avoid them being converted + // to accelerators, replace them with two ampersands. + serviceName.replace("&", "&&"); + + int newId = insertItem(KickerLib::menuIconSet(s->icon()), serviceName, nId, nIndex); + m_entryMap.insert(newId, static_cast<KSycocaEntry*>(s)); +} + +void PrefMenu::mousePressEvent(QMouseEvent * ev) +{ + m_dragStartPos = ev->pos(); + KPanelMenu::mousePressEvent(ev); +} + +void PrefMenu::mouseMoveEvent(QMouseEvent * ev) +{ + KPanelMenu::mouseMoveEvent(ev); + + if ((ev->state() & LeftButton) != LeftButton) + { + return; + } + + QPoint p = ev->pos() - m_dragStartPos; + if (p.manhattanLength() <= QApplication::startDragDistance()) + { + return; + } + + int id = idAt(m_dragStartPos); + + // Don't drag items we didn't create. + if (id < idStart) + { + return; + } + + if (!m_entryMap.contains(id)) + { + kdDebug(1210) << "Cannot find service with menu id " << id << endl; + return; + } + + KSycocaEntry * e = m_entryMap[id]; + + QPixmap icon; + KURL url; + + switch (e->sycocaType()) + { + case KST_KService: + { + icon = static_cast<KService *>(e)->pixmap(KIcon::Small); + QString filePath = static_cast<KService *>(e)->desktopEntryPath(); + if (filePath[0] != '/') + { + filePath = locate("apps", filePath); + } + url.setPath(filePath); + break; + } + + case KST_KServiceGroup: + { + icon = KGlobal::iconLoader()->loadIcon(static_cast<KServiceGroup*>(e)->icon(), + KIcon::Small); + url = "programs:/" + static_cast<KServiceGroup*>(e)->relPath(); + break; + } + + default: + { + return; + break; + } + } + + // If the path to the desktop file is relative, try to get the full + // path from KStdDirs. + KURLDrag *d = new KURLDrag(KURL::List(url), this); + connect(d, SIGNAL(destroyed()), this, SLOT(dragObjectDestroyed())); + d->setPixmap(icon); + d->dragCopy(); + + // Set the startposition outside the panel, so there is no drag initiated + // when we use drag and click to select items. A drag is only initiated when + // you click to open the menu, and then press and drag an item. + m_dragStartPos = QPoint(-1,-1); +} + +void PrefMenu::dragEnterEvent(QDragEnterEvent *event) +{ + // Set the DragObject's target to this widget. This is needed because the + // widget doesn't accept drops, but we want to determine if the drag object + // is dropped on it. This avoids closing on accidental drags. If this + // widget accepts drops in the future, these lines can be removed. + if (event->source() == this) + { + KURLDrag::setTarget(this); + } + event->ignore(); +} + +void PrefMenu::dragLeaveEvent(QDragLeaveEvent */*event*/) +{ + // see PrefMenu::dragEnterEvent why this is nescessary + if (!frameGeometry().contains(QCursor::pos())) + { + KURLDrag::setTarget(0); + } +} + +void PrefMenu::initialize() +{ + if (initialized()) + { + return; + } + + // Set the startposition outside the panel, so there is no drag initiated + // when we use drag and click to select items. A drag is only initiated when + // you click to open the menu, and then press and drag an item. + m_dragStartPos = QPoint(-1,-1); + + if (m_root.isEmpty()) + { + insertItem(KickerLib::menuIconSet("kcontrol"), + i18n("Control Center"), + this, SLOT(launchControlCenter())); + insertSeparator(); + } + + // We ask KSycoca to give us all services under Settings/ + KServiceGroup::Ptr root = KServiceGroup::group(m_root.isEmpty() ? "Settings/" : m_root); + + if (!root || !root->isValid()) + { + return; + } + + KServiceGroup::List list = root->entries(true, true, true, + KickerSettings::menuEntryFormat() == KickerSettings:: NameAndDescription); + + if (list.isEmpty()) + { + setItemEnabled(insertItem(i18n("No Entries")), false); + return; + } + + int id = idStart; + + QStringList suppressGenericNames = root->suppressGenericNames(); + + KServiceGroup::List::ConstIterator it = list.begin(); + for (; it != list.end(); ++it) + { + KSycocaEntry* e = *it; + + if (e->isType(KST_KServiceGroup)) + { + + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); + QString groupCaption = g->caption(); + + // Avoid adding empty groups. + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(g->relPath()); + if (subMenuRoot->childCount() == 0) + { + continue; + } + + // Ignore dotfiles. + if ((g->name().at(0) == '.')) + { + continue; + } + + // Item names may contain ampersands. To avoid them being converted + // to accelerators, replace each ampersand with two ampersands. + groupCaption.replace("&", "&&"); + + PrefMenu* m = new PrefMenu(g->name(), g->relPath(), this); + m->setCaption(groupCaption); + + int newId = insertItem(KickerLib::menuIconSet(g->icon()), groupCaption, m, id++); + m_entryMap.insert(newId, static_cast<KSycocaEntry*>(g)); + // We have to delete the sub menu our selves! (See Qt docs.) + m_subMenus.append(m); + } + else if (e->isType(KST_KService)) + { + KService::Ptr s(static_cast<KService *>(e)); + insertMenuItem(s, id++, -1, &suppressGenericNames); + } + else if (e->isType(KST_KServiceSeparator)) + { + insertSeparator(); + } + } + + setInitialized(true); +} + +void PrefMenu::slotExec(int id) +{ + if (!m_entryMap.contains(id)) + { + return; + } + + kapp->propagateSessionManager(); + KSycocaEntry *e = m_entryMap[id]; + KService::Ptr service = static_cast<KService *>(e); + KApplication::startServiceByDesktopPath(service->desktopEntryPath(), + QStringList(), 0, 0, 0, "", true); + m_dragStartPos = QPoint(-1,-1); +} + +void PrefMenu::clearOnClose() +{ + if (!initialized()) + { + return; + } + + m_clearOnClose = isVisible(); + if (!m_clearOnClose) + { + // we aren't visible right now so clear immediately + slotClear(); + } +} + +void PrefMenu::slotClear() +{ + if( isVisible()) + { + // QPopupMenu's aboutToHide() is emitted before the popup is really hidden, + // and also before a click in the menu is handled, so do the clearing + // only after that has been handled + QTimer::singleShot( 100, this, SLOT( slotClear())); + return; + } + + m_entryMap.clear(); + KPanelMenu::slotClear(); + m_subMenus.clear(); +} + +void PrefMenu::aboutToClose() +{ + if (m_clearOnClose) + { + m_clearOnClose = false; + slotClear(); + } +} + +void PrefMenu::launchControlCenter() +{ + KApplication::startServiceByDesktopName("kcontrol", QStringList(), + 0, 0, 0, "", true); +} + + +void PrefMenu::dragObjectDestroyed() +{ + if (KURLDrag::target() != this) + { + close(); + } +} + +#include "prefmenu.moc" diff --git a/kicker/menuext/prefmenu/prefmenu.desktop b/kicker/menuext/prefmenu/prefmenu.desktop new file mode 100644 index 000000000..f3206d4e3 --- /dev/null +++ b/kicker/menuext/prefmenu/prefmenu.desktop @@ -0,0 +1,135 @@ +[Desktop Entry] +Name=Settings +Name[af]=Instellings +Name[ar]=التعيينات +Name[az]=QurÄŸular +Name[be]=ÐаÑтаўленні +Name[bg]=ÐаÑтройки +Name[bn]=সেটিংস +Name[br]=Dibarzhoù +Name[bs]=Postavke +Name[ca]=Preferències +Name[cs]=Nastavenà +Name[csb]=Ùstôw +Name[cy]=Gosodiadau +Name[da]=Opsætning +Name[de]=Einstellungen +Name[el]=Ρυθμίσεις +Name[eo]=Agordo +Name[es]=Preferencias +Name[et]=Seadistused +Name[eu]=Ezarpenak +Name[fa]=تنظیمات +Name[fi]=Asetukset +Name[fr]=Configuration +Name[fy]=Ynstellings +Name[ga]=Socruithe +Name[gl]=Opcións +Name[he]=הגדרות +Name[hi]=विनà¥à¤¯à¤¾à¤¸ +Name[hr]=Postavke +Name[hsb]=Nastajenja +Name[hu]=BeállÃtások +Name[is]=Stillingar +Name[it]=Impostazioni +Name[ja]=è¨å®š +Name[ka]=პáƒáƒ áƒáƒ›áƒ”ტრები +Name[kk]=Параметрлері +Name[km]=ការ​កំណážáŸ‹ +Name[ko]=ì„¤ì • +Name[lt]=Parinktys +Name[lv]=Parametri +Name[mk]=ПоÑтавувања +Name[mn]=Тохируулга +Name[ms]=Tempatan +Name[nb]=Innstillinger +Name[nds]=Instellen +Name[ne]=सेटिङ +Name[nl]=Instellingen +Name[nn]=Innstillingar +Name[pa]=ਸੈਟਿੰਗ +Name[pl]=Ustawienia +Name[pt]=Configuração +Name[pt_BR]=Configurações +Name[ro]=Setări +Name[ru]=ÐаÑтройка +Name[rw]=Amagenamiterere +Name[se]=Heivehusat +Name[sk]=Nastavenia +Name[sl]=Nastavitve +Name[sr]=ПоÑтавке +Name[sr@Latn]=Postavke +Name[sv]=Inställningar +Name[ta]=அமைபà¯à®ªà¯à®•à®³à¯ +Name[te]=అమరికలౠ+Name[tg]=Танзимот +Name[th]=ตั้งค่าต่างๆ +Name[tr]=Ayarlar +Name[tt]=Caylaw +Name[uk]=Параметри +Name[uz]=Moslamalar +Name[uz@cyrillic]=МоÑламалар +Name[vi]=Thiết láºp +Name[wa]=Apontiaedjes +Name[zh_CN]=设置 +Name[zh_TW]=è¨å®š +Comment=Control Center modules menu +Comment[af]=Beheer Sentrum Modules kieslys +Comment[ar]=قائمة ÙˆØدات مركز التØكّم +Comment[be]=Меню модулÑÑž ЦÑнтра ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½Ñ +Comment[bg]=Меню на модулите в ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ð½Ð¸Ñ Ñ†ÐµÐ½Ñ‚ÑŠÑ€ +Comment[bn]=বিà¦à¦¿à¦¨à§à¦¨ নিয়নà§à¦¤à§à¦°à¦£ কেনà§à¦¦à§à¦° মডিউল সমà§à¦¬à¦²à¦¿à¦¤ মেনৠ+Comment[ca]=Menú dels mòduls del centre de control +Comment[cs]=NabÃdka modulů OvládacÃho centra +Comment[csb]=Menu mòdułów Centróm kòntrolë +Comment[da]=Menu med moduler i kontrolcentret +Comment[de]=Das Menü für Kontrollzentrum-Module +Comment[el]=ÎœÎµÎ½Î¿Ï Î±ÏθÏωμάτων κÎντÏου ελÎγχου +Comment[en_GB]=Control Centre modules menu +Comment[eo]=Menuo de Stircentraj Moduloj +Comment[es]=Menú de los módulos del Centro de control +Comment[et]=Juhtimiskeskuse moodulite menüü +Comment[eu]=Kontrol gunearen moduluen menua +Comment[fa]=گزینگان پیمانه‌های مرکز کنترل +Comment[fi]=Ohjauskeskuksen moduulivalikko +Comment[fr]=Menu des modules du Centre de configuration +Comment[fy]=Menu mei Konfiguraasjemodules +Comment[gl]=Menu dos Módulos do Centro de Control +Comment[he]=תפריט מודולי מרכז בקרה +Comment[hr]=Izbornik modula upravljaÄkog srediÅ¡ta +Comment[hu]=Menü a VezérlÅ‘pult moduljaival +Comment[is]=Valmynd stjórnborðseininga +Comment[it]=Menu dei moduli del centro di controllo +Comment[ja]=コントãƒãƒ¼ãƒ«ã‚»ãƒ³ã‚¿ãƒ¼ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[kk]=БаÑқару орталықтың модульдер мәзірі +Comment[km]=ម៉ឺនុយ​ម៉ូឌុល​មជ្ឈមណ្ឌល​បញ្ជា +Comment[ko]=ì œì–´íŒ ëª¨ë“ˆ +Comment[lt]=Valdymo centro modulių meniu +Comment[mk]=Мени Ñо модулите од Контролниот центар +Comment[nb]=Meny for kontrollpanelmoduler +Comment[nds]=Kuntrullzentrum-Modulen +Comment[ne]=नियनà¥à¤¤à¥à¤°à¤£ केनà¥à¤¦à¥à¤° मोडà¥à¤¯à¥à¤² मेनॠ+Comment[nl]=Menu met Configuratiemodules +Comment[nn]=Meny for kontrollsentermodular +Comment[pa]=ਕੰਟਰੋਲ ਕੇਂਦਰ ਮੈਡੀਊਲ ਮੇਨੂ +Comment[pl]=Menu modułów Centrum sterowania +Comment[pt]=Menu de módulos do Centro de Controlo +Comment[pt_BR]=Menu dos módulos do Centro de Controle +Comment[ru]=Модули Центра ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ +Comment[sk]=Menu pre moduly Ovládacieho centra +Comment[sl]=Meni z moduli Nadzornega srediÅ¡Äa +Comment[sr]=Мени модула Контролног центра +Comment[sr@Latn]=Meni modula Kontrolnog centra +Comment[sv]=Meny med moduler i Inställningscentralen +Comment[th]=เมนูขà¸à¸‡à¹‚มดูลขà¸à¸‡à¸¨à¸¹à¸™à¸¢à¹Œà¸„วบคุม +Comment[tr]=Kontrol Merkezi modülleri menüsü +Comment[uk]=Меню модулів в Центрі ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ +Comment[uz]=Boshqaruv markazining modullari +Comment[uz@cyrillic]=Бошқарув марказининг модуллари +Comment[vi]=Trung tâm Ä‘iá»u khiển mô Ä‘un thá»±c Ä‘Æ¡n +Comment[wa]=Dressêye des modules do cinte di contrôle +Comment[zh_CN]=控制ä¸å¿ƒæ¨¡å—èœå• +Comment[zh_TW]=控制ä¸å¿ƒæ¨¡çµ„é¸å–® +Icon=package_settings + +X-KDE-Library=kickermenu_prefmenu diff --git a/kicker/menuext/prefmenu/prefmenu.h b/kicker/menuext/prefmenu/prefmenu.h new file mode 100644 index 000000000..99c3772fc --- /dev/null +++ b/kicker/menuext/prefmenu/prefmenu.h @@ -0,0 +1,74 @@ +/***************************************************************** + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _prefmenu_h_ +#define _prefmenu_h_ + +#include <qmap.h> + +#include <kpanelmenu.h> +#include <ksycocaentry.h> + +typedef QMap<int, KSycocaEntry::Ptr> EntryMap; +typedef QPtrList<QPopupMenu> PopupMenuList; + +class PrefMenu : public KPanelMenu +{ + Q_OBJECT + + public: + PrefMenu(QWidget *parent, + const char *name, + const QStringList & /*args*/); + PrefMenu(const QString& label, + const QString& root, + QWidget *parent); + ~PrefMenu(); + + protected: + void insertMenuItem(KService::Ptr & s, + int nId, + int nIndex= -1, + const QStringList *suppressGenericNames = 0); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + + bool m_clearOnClose; + QString m_root; + QPoint m_dragStartPos; + EntryMap m_entryMap; + PopupMenuList m_subMenus; + + protected slots: + void initialize(); + void slotExec(int id); // from KPanelMenu + void slotClear(); // from KPanelMenu + void clearOnClose(); + void aboutToClose(); + void launchControlCenter(); + void dragObjectDestroyed(); +}; + +#endif diff --git a/kicker/menuext/recentdocs/Makefile.am b/kicker/menuext/recentdocs/Makefile.am new file mode 100644 index 000000000..38f95814b --- /dev/null +++ b/kicker/menuext/recentdocs/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_recentdocs.la + +kickermenu_recentdocs_la_SOURCES = recentdocsmenu.cpp +kickermenu_recentdocs_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined +kickermenu_recentdocs_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) + +kickermenu_recentdocs_la_METASOURCES = AUTO + +desktopmenu_DATA = recentdocs.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_recentdocs.pot diff --git a/kicker/menuext/recentdocs/recentdocs.desktop b/kicker/menuext/recentdocs/recentdocs.desktop new file mode 100644 index 000000000..a2f406079 --- /dev/null +++ b/kicker/menuext/recentdocs/recentdocs.desktop @@ -0,0 +1,140 @@ +[Desktop Entry] +Name=Recent Documents +Name[af]=Onlangse Dokumente +Name[ar]=مستندات Øديثة +Name[az]=Son SÉ™nÉ™dlÉ™r +Name[be]=Ð Ð°Ð½ÐµÐ¹ÑˆÑ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹ +Name[bg]=Документи +Name[bn]=সমà§à¦ªà§à¦°à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à§ƒà¦¤ নথী +Name[br]=Teulioù nevez +Name[bs]=Najnoviji dokumenti +Name[ca]=Documents recents +Name[cs]=Nedávné dokumenty +Name[csb]=Slédno òtemkłé dokùmentë +Name[cy]=Dogfenni Diweddar +Name[da]=Nylige dokumenter +Name[de]=Zuletzt geöffnete Dokumente +Name[el]=Î Ïόσφατα ÎγγÏαφα +Name[eo]=Lastaj dokumentoj +Name[es]=Documentos recientes +Name[et]=Viimati kasutatud dokumendid +Name[eu]=Azken dokumentuak +Name[fa]=سندهای اخیر +Name[fi]=Viimeaikaiset asiakirjat +Name[fr]=Documents récents +Name[fy]=Nijste dokuminten +Name[ga]=Cáipéisà is déanaà +Name[gl]=Documentos Recentes +Name[he]=×ž×¡×ž×›×™× ××—×¨×•× ×™× +Name[hi]=हालिया दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ +Name[hr]=Nedavno pristupljeni dokumenti +Name[hu]=A legutóbbi dokumentumok +Name[is]=Nýleg skjöl +Name[it]=Documenti recenti +Name[ja]=最近開ã„ãŸãƒ‰ã‚ュメント +Name[ka]=ბáƒáƒšáƒ დáƒáƒ™áƒ£áƒ›áƒ”ნტები +Name[kk]=Жуырдағы құжаттар +Name[km]=ឯកសារ​ážáŸ’មីៗ​នáŸáŸ‡ +Name[lo]=ເàºàºàº°àºªàº²àº™àº‚à»à»‰àº„ວາມ +Name[lt]=Neseni dokumentai +Name[lv]=Nesenie dokumenti +Name[mk]=Скорешни документи +Name[mn]=Сүүлд нÑÑгдÑÑн баримтууд +Name[ms]=Dokumen Terkini +Name[mt]=Dokumenti riÄ‹enti +Name[nb]=Nylig brukte dokumenter +Name[nds]=Tolest bruukte Dokmenten +Name[ne]=हालको कागजात +Name[nl]=Recente documenten +Name[nn]=Nyleg bruka dokument +Name[nso]=Ditokomane tsa Gabjale +Name[pa]=ਤਾਜ਼ਾ ਦਸਤਾਵੇਜ਼ +Name[pl]=Ostatnio otwarte dokumenty +Name[pt]=Documentos Recentes +Name[pt_BR]=Documentos Recentes +Name[ro]=Documente recente +Name[ru]=ПоÑледние документы +Name[rw]=Inyandiko za Vuba +Name[se]=Ãiddo geavahuvvon dokumeanttat +Name[sk]=Nedávne dokumenty +Name[sl]=Nedavni dokumenti +Name[sr]=Пређашњи документи +Name[sr@Latn]=PreÄ‘aÅ¡nji dokumenti +Name[sv]=Senaste dokument +Name[ta]=தறà¯à®ªà¯‹à®¤à¯ˆà®¯ ஆவணஙà¯à®•à®³à¯ +Name[tg]=Ҳуҷҷатҳои охирин +Name[th]=เà¸à¸à¸ªà¸²à¸£à¸—ี่เคยเรียà¸à¹ƒà¸Šà¹‰ +Name[tr]=Son Kullanılan Belgeler +Name[tt]=Soñğı Ä°stäleklär +Name[uk]=Ðедавні документи +Name[uz]=Yaqinda ochilgan hujjatlar +Name[uz@cyrillic]=Яқинда очилган ҳужжатлар +Name[ven]=Manwalwa a Zwino +Name[vi]=Tà i liệu Gần đây +Name[wa]=Documints d' enawaire +Name[xh]=Uxwebhu Olusandukusebenziswa +Name[zh_CN]=最近文档 +Name[zh_TW]=最近的文件 +Name[zu]=Ushicilelo olusanda kuvulwa +Comment=Menu of documents you have used recently +Comment[af]=Kieslys met dokumente wat onlangs deur jou gebruik is +Comment[ar]=قائمة المستنادات التي إستخدمتها Øديثاً +Comment[be]=Меню раней выкарыÑтаных дакументаў +Comment[bg]=ПоÑледно използвани документи +Comment[bn]=আপনি সমà§à¦ªà§à¦°à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করেছেন à¦à¦®à¦¨ নথীর তালিকা +Comment[bs]=Meni sa dokumentima koje ste nedavno koristili +Comment[ca]=Menú dels documents usats fa poc +Comment[cs]=NabÃdka nedávno použitých dokumentů +Comment[csb]=Menu slédno òtemkłëch dokùmentów +Comment[da]=Menu med dokumenter du har brugt for nyligt +Comment[de]=Menü mit Dokumenten, die Sie zuletzt geöffnet hatten +Comment[el]=ÎœÎµÎ½Î¿Ï ÎµÎ³Î³Ïάφων που χÏησιμοποιήθηκαν Ï€Ïόσφατα +Comment[eo]=Menuo de dokumentoj kiujn vi laste uzis +Comment[es]=Menú de los documentos recientemente usados +Comment[et]=Viimati kasutatud dokumentide menüü +Comment[eu]=Erabili dituzun azken dokumentuen menua +Comment[fa]=گزینگان سندهایی Ú©Ù‡ اخیراً استÙاده کرده‌اید +Comment[fi]=Viimeksi käyttämiesi asiakirjojen valikko +Comment[fr]=Menu des documents récemment utilisés +Comment[fy]=Menu mei dokuminten dy jo koartlyn iepene ha +Comment[gl]=Os documentos que usou recentemente +Comment[he]=תפריט ×”×ž×¡×ž×›×™× ×©×”×©×ª×ž×©×ª ×‘×”× ×œ××—×¨×•× ×” +Comment[hr]=Izbornik s nedavno pristupljenim dokumentima +Comment[hu]=A nemrég használt dokumentumok menüje +Comment[is]=Listi yfir skjöl sem þú hefur nýlega notað +Comment[it]=Menu dei documenti usati recentemente +Comment[ja]=最近使ã£ãŸãƒ‰ã‚ュメントã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=ბáƒáƒšáƒ დრáƒáƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებული დáƒáƒ™áƒ£áƒ›áƒ”ნტების მენიუ +Comment[kk]=Жуырда қолданған құжаттар мәзірі +Comment[km]=ម៉ឺនុយ​ឯកសារ​ដែល​អ្នក​បាន​ប្រើ​ážáŸ’មីៗនáŸáŸ‡ +Comment[lt]=Nesenai naudotų dokumentų meniu +Comment[mk]=Мени Ñо поÑледните документи што Ñте ги кориÑтеле +Comment[nb]=Meny over dokumenter du nylig har brukt +Comment[nds]=Menü vun Dokmenten, de Du tolest bruukt hest +Comment[ne]=तपाईà¤à¤²à¥‡ à¤à¤°à¤–रै पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥ à¤à¤à¤•à¥‹ कागजातका मेनॠ+Comment[nl]=Menu met documenten die u recentelijk hebt geopend +Comment[nn]=Meny over dokument du nyleg har bruka +Comment[pa]=ਤਾਜ਼ਾ ਦਸਤਾਵੇਜ਼, ਜੋ ਕਿ ਤà©à¨¸à©€à¨‚ ਹà©à¨£à©‡ ਵਰਤੇ ਹਨ +Comment[pl]=Menu ostatnio używanych dokumentów +Comment[pt]=Menu com os documentos recentes que você usou +Comment[pt_BR]=Menu de documentos que você usou recentemente +Comment[ro]=Meniu cu lista de documente pe care le-aÈ›i utilizat recent +Comment[ru]=ПоÑледние документы +Comment[se]=Fállu mii Äájeha dokumeanttaid mat áiddo leat geavahuvvon +Comment[sk]=Menu nedávno použitých dokumentov +Comment[sl]=Meni z dokumenti, ki ste jih uporabljali pred kratkim +Comment[sr]=Мени докумената које Ñте Ñкорије кориÑтили +Comment[sr@Latn]=Meni dokumenata koje ste skorije koristili +Comment[sv]=Meny med dokument som du nyligen har använt +Comment[th]=เมนูขà¸à¸‡à¹€à¸à¸à¸ªà¸²à¸£à¸—ี่คุณเคยเรียà¸à¹ƒà¸Šà¹‰à¸¡à¸²à¹à¸¥à¹‰à¸§ +Comment[tr]=Son kullanılan belgelerin menüsü +Comment[uk]=Меню документів, Ñкі ви недавно викориÑтовували +Comment[uz]=Yaqinda ishlatilgan hujjatlarning menyusi +Comment[uz@cyrillic]=Яқинда ишлатилган ҳужжатларнинг менюÑи +Comment[vi]=Thá»±c Ä‘Æ¡n chứa các tà i liệu bạn má»›i truy cáºp gần đây +Comment[wa]=Dressêye des documints ki vs avoz eployîz enawaire +Comment[zh_CN]=您最近使用过的文档的èœå• +Comment[zh_TW]=您最近使用éŽçš„文件é¸å–® +Icon=document + +X-KDE-Library=kickermenu_recentdocs diff --git a/kicker/menuext/recentdocs/recentdocsmenu.cpp b/kicker/menuext/recentdocs/recentdocsmenu.cpp new file mode 100644 index 000000000..98357fe52 --- /dev/null +++ b/kicker/menuext/recentdocs/recentdocsmenu.cpp @@ -0,0 +1,139 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qdragobject.h> + +#include <kglobal.h> +#include <kiconloader.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kdesktopfile.h> +#include <kglobalsettings.h> +#include <kapplication.h> +#include <kurldrag.h> +#include <krecentdocument.h> + +#include "recentdocsmenu.h" + +K_EXPORT_KICKER_MENUEXT(recentdocs, RecentDocsMenu) + +RecentDocsMenu::RecentDocsMenu(QWidget *parent, const char *name, + const QStringList &/*args*/) + : KPanelMenu(KRecentDocument::recentDocumentDirectory(), parent, name) +{ +} + +RecentDocsMenu::~RecentDocsMenu() +{ +} + +void RecentDocsMenu::initialize() { + if (initialized()) clear(); + + insertItem(SmallIconSet("history_clear"), i18n("Clear History"), + this, SLOT(slotClearHistory())); + insertSeparator(); + + _fileList = KRecentDocument::recentDocuments(); + + if (_fileList.isEmpty()) { + insertItem(i18n("No Entries"), 0); + setItemEnabled(0, false); + return; + } + + int id = 0; + + for (QStringList::ConstIterator it = _fileList.begin(); + it != _fileList.end(); + ++it) + { + KDesktopFile f(*it, true /* read only */); + insertItem(SmallIconSet(f.readIcon()), f.readName().replace('&', QString::fromAscii("&&") ), id++); + } + + setInitialized(true); +} + +void RecentDocsMenu::slotClearHistory() { + KRecentDocument::clear(); + reinitialize(); +} + +void RecentDocsMenu::slotExec(int id) { + if (id >= 0) { + kapp->propagateSessionManager(); + KURL u; + u.setPath(_fileList[id]); + KDEDesktopMimeType::run(u, true); + } +} + +void RecentDocsMenu::mousePressEvent(QMouseEvent* e) { + _mouseDown = e->pos(); + QPopupMenu::mousePressEvent(e); +} + +void RecentDocsMenu::mouseMoveEvent(QMouseEvent* e) { + KPanelMenu::mouseMoveEvent(e); + + if (!(e->state() & LeftButton)) + return; + + if (!rect().contains(_mouseDown)) + return; + + int dragLength = (e->pos() - _mouseDown).manhattanLength(); + + if (dragLength <= KGlobalSettings::dndEventDelay()) + return; // ignore it + + int id = idAt(_mouseDown); + + // Don't drag 'manual' items. + if (id < 0) + return; + + KDesktopFile f(_fileList[id], true /* read only */); + + KURL url ( f.readURL() ); + + if (url.isEmpty()) // What are we to do ? + return; + + KURL::List lst; + lst.append(url); + + KURLDrag* d = new KURLDrag(lst, this); + d->setPixmap(SmallIcon(f.readIcon())); + d->dragCopy(); + close(); +} + +void RecentDocsMenu::slotAboutToShow() +{ + reinitialize(); + KPanelMenu::slotAboutToShow(); +} + +#include "recentdocsmenu.moc" diff --git a/kicker/menuext/recentdocs/recentdocsmenu.h b/kicker/menuext/recentdocs/recentdocsmenu.h new file mode 100644 index 000000000..1e3157495 --- /dev/null +++ b/kicker/menuext/recentdocs/recentdocsmenu.h @@ -0,0 +1,55 @@ +/***************************************************************** + +Copyright (c) 1996-2002 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef RECENTDOCSMENU_H +#define RECENTDOCSMENU_H + +#include <kpanelmenu.h> + +class QStringList; +class QPoint; + +class RecentDocsMenu : public KPanelMenu +{ + Q_OBJECT + +public: + RecentDocsMenu(QWidget* parent, const char* name, const QStringList &/*args*/); + ~RecentDocsMenu(); + void initialize(); + +protected slots: + void slotClearHistory(); + void slotExec(int id); + void slotAboutToShow(); + +protected: + void mousePressEvent(QMouseEvent* e); + void mouseMoveEvent(QMouseEvent* e); + +private: + QStringList _fileList; + QPoint _mouseDown; +}; + +#endif // RECENTDOCSMENU_H diff --git a/kicker/menuext/remote/Makefile.am b/kicker/menuext/remote/Makefile.am new file mode 100644 index 000000000..85736d0a2 --- /dev/null +++ b/kicker/menuext/remote/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I$(srcdir)/../../ui -I../../libkicker $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_remotemenu.la + +kickermenu_remotemenu_la_SOURCES = remotemenu.cpp remotemenu.skel +kickermenu_remotemenu_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_remotemenu_la_LIBADD = $(LIB_KDEUI) $(top_builddir)/kicker/libkicker/libkickermain.la + +kickermenu_remotemenu_la_METASOURCES = AUTO + +desktopmenu_DATA = remotemenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_remotemenu.pot + +remotemenu.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/menuext/remote/remotemenu.cpp b/kicker/menuext/remote/remotemenu.cpp new file mode 100644 index 000000000..42b3d5339 --- /dev/null +++ b/kicker/menuext/remote/remotemenu.cpp @@ -0,0 +1,164 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "remotemenu.h" + +#include <kdebug.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <krun.h> +#include <kiconloader.h> +#include <kdesktopfile.h> +#include <kservice.h> + +#include <qpixmap.h> +#include <qdir.h> +#include <qtimer.h> + +#include "kickerSettings.h" + +#define WIZARD_SERVICE "knetattach" + +K_EXPORT_KICKER_MENUEXT(remotemenu, RemoteMenu) + + +RemoteMenu::RemoteMenu(QWidget *parent, const char *name, + const QStringList &/*args*/) + : KPanelMenu(parent, name), KDirNotify() +{ + KGlobal::dirs()->addResourceType("remote_entries", + KStandardDirs::kde_default("data") + "remoteview"); + + QString path = KGlobal::dirs()->saveLocation("remote_entries"); + + QDir dir = path; + if (!dir.exists()) + { + dir.cdUp(); + dir.mkdir("remoteview"); + } +} + +RemoteMenu::~RemoteMenu() +{ +} + +void RemoteMenu::initialize() +{ + int id = 0; + if (KickerSettings::showMenuTitles()) + { + insertTitle(i18n("Network Folders")); + } + + id = insertItem(SmallIcon("wizard"), i18n("Add Network Folder")); + connectItem(id, this, SLOT(startWizard())); + id = insertItem(SmallIcon("kfm"), i18n("Manage Network Folders")); + connectItem(id, this, SLOT(openRemoteDir())); + + insertSeparator(); + + m_desktopMap.clear(); + QStringList names_found; + QStringList dirList = KGlobal::dirs()->resourceDirs("remote_entries"); + + QStringList::ConstIterator dirpath = dirList.begin(); + QStringList::ConstIterator end = dirList.end(); + for(; dirpath!=end; ++dirpath) + { + QDir dir = *dirpath; + if (!dir.exists()) continue; + + QStringList filenames + = dir.entryList( QDir::Files | QDir::Readable ); + + QStringList::ConstIterator name = filenames.begin(); + QStringList::ConstIterator endf = filenames.end(); + + for(; name!=endf; ++name) + { + if (!names_found.contains(*name)) + { + names_found.append(*name); + QString filename = *dirpath+*name; + KDesktopFile desktop(filename); + id = insertItem(SmallIcon(desktop.readIcon()), desktop.readName()); + m_desktopMap[id] = filename; + } + } + } +} + +void RemoteMenu::startWizard() +{ + KURL url; + KService::Ptr service = KService::serviceByDesktopName(WIZARD_SERVICE); + + if (service && service->isValid()) + { + url.setPath(locate("apps", service->desktopEntryPath())); + new KRun(url, 0, true); // will delete itself + } +} + +void RemoteMenu::openRemoteDir() +{ + new KRun(KURL("remote:/")); +} + +void RemoteMenu::slotExec(int id) +{ + if (m_desktopMap.contains(id)) + { + new KRun(m_desktopMap[id]); + } +} + +ASYNC RemoteMenu::FilesAdded(const KURL &directory) +{ + if (directory.protocol()=="remote") reinitialize(); +} + +ASYNC RemoteMenu::FilesRemoved(const KURL::List &fileList) +{ + KURL::List::ConstIterator it = fileList.begin(); + KURL::List::ConstIterator end = fileList.end(); + + for (; it!=end; ++it) + { + if ((*it).protocol()=="remote") + { + reinitialize(); + return; + } + } +} + +ASYNC RemoteMenu::FilesChanged(const KURL::List &fileList) +{ + FilesRemoved(fileList); +} + +ASYNC RemoteMenu::FilesRenamed(const KURL &src, const KURL &dest) +{ + if (src.protocol()=="remote" || dest.protocol()=="remote") + reinitialize(); +} + +#include "remotemenu.moc" diff --git a/kicker/menuext/remote/remotemenu.desktop b/kicker/menuext/remote/remotemenu.desktop new file mode 100644 index 000000000..82f0de72c --- /dev/null +++ b/kicker/menuext/remote/remotemenu.desktop @@ -0,0 +1,133 @@ +[Desktop Entry] +Name=Network Folders +Name[af]=Netwerk Gidse +Name[ar]=مجلّدات الشبكة +Name[be]=Ð¡ÐµÑ‚ÐºÐ°Ð²Ñ‹Ñ Ñ‚Ñчкі +Name[bg]=Мрежови директории +Name[bn]=নেটওয়ারà§à¦• ফোলà§à¦¡à¦¾à¦° +Name[br]=Renkelloù rouedad +Name[bs]=Mrežni folderi +Name[ca]=Carpetes de xarxa +Name[cs]=SÃÅ¥ové složky +Name[csb]=Sécowé katalodżi +Name[da]=Netværksmapper +Name[de]=Netzwerkordner +Name[el]=Δικτυακοί φάκελοι +Name[eo]=Retaj Dosierujoj +Name[es]=Carpetas de red +Name[et]=Võrgukataloogid +Name[eu]=Sareko karpetak +Name[fa]=پوشه‌های شبکه +Name[fi]=Verkkokansiot +Name[fr]=Dossiers réseau +Name[fy]=Netwurkmappen +Name[ga]=Fillteáin LÃonra +Name[gl]=Cartafoles en Rede +Name[he]=תיקיות רשת +Name[hi]=नेटवरà¥à¤• फोलà¥à¤¡à¤°à¥à¤¸ +Name[hr]=Mrežne mape +Name[hu]=Hálózati mappák +Name[is]=Netmöppur +Name[it]=Cartelle di rete +Name[ja]=ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ•ã‚©ãƒ«ãƒ€ +Name[ka]=ქსელური სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ეები +Name[kk]=Желідегі қапшықтар +Name[km]=ážážâ€‹áž”ណ្ដាញ +Name[ko]=ë„¤íŠ¸ì›Œí¬ í´ë” 마법사 +Name[lt]=Tinklo aplankai +Name[lv]=TÄ«kla mape +Name[mk]=Мрежни папки +Name[ms]=Folder Rangkaian +Name[nb]=Nettverksmapper +Name[nds]=Nettwarkorner +Name[ne]=सञà¥à¤œà¤¾à¤² फोलà¥à¤¡à¤° +Name[nl]=Netwerkmappen +Name[nn]=Nettverksmapper +Name[pa]=ਨੈੱਟਵਰਕ ਫੋਲਡਰ +Name[pl]=Foldery sieciowe +Name[pt]=Pastas de Rede +Name[pt_BR]=Pastas de Rede +Name[ro]=Foldere de reÈ›ea +Name[ru]=Сетевые папки +Name[rw]=Ububiko bw'Urusobemiyoboro +Name[se]=Fierpmádatmáhpat +Name[sk]=SieÅ¥ové prieÄinky +Name[sl]=Omrežne mape +Name[sr]=Мрежне фаÑцикле +Name[sr@Latn]=Mrežne fascikle +Name[sv]=Nätverkskataloger +Name[ta]=வலைபà¯à®ªà®¿à®©à¯à®©à®²à¯ அடைவà¯à®•à®³à¯ +Name[te]=నెటà±à°µà°°à±à°•à± ఫొలà±à°¡à°°à±à°²à± +Name[tg]=ФеҳраÑтҳои шабака +Name[th]=โฟลเดà¸à¸£à¹Œà¹€à¸„รืà¸à¸‚่าย +Name[tr]=AÄŸ Dizinleri +Name[tt]=Çeltärle Törgäklär +Name[uk]=Мережні теки +Name[uz]=Tarmoq jildlari +Name[uz@cyrillic]=Тармоқ жилдлари +Name[vi]=ThÆ° mục Mạng +Name[wa]=Ridants rantoele +Name[zh_CN]=网络文件夹 +Name[zh_TW]=網路資料夾 +Comment=Menu of network folders +Comment[af]=Kieslys vir netwerk gidse +Comment[ar]=قائمة مجلّدات الشبكة +Comment[be]=Меню Ñеткавых Ñ‚Ñчак +Comment[bg]=Меню за доÑтъп до мрежови директории +Comment[bn]=নেটওয়ারà§à¦• ফোলà§à¦¡à¦¾à¦°-à¦à¦° তালিকা +Comment[bs]=Meni sa mrežnim direktorijima +Comment[ca]=Menú de les carpetes de xarxa +Comment[cs]=NabÃdka sÃÅ¥ových složek +Comment[csb]=Menu sécowëch katalogów +Comment[da]=Menu med netværksmapper +Comment[de]=Menü für den Zugriff auf Netzwerkordner +Comment[el]=ÎœÎµÎ½Î¿Ï Ï„Ï‰Î½ δικτυακών φακÎλων +Comment[eo]=Menuo de retaj dosierujoj +Comment[es]=Menú de las carpetas de red +Comment[et]=Võrgukataloogide menüü +Comment[eu]=Sareko karpeten menua +Comment[fa]=گزینگان پوشه‌های شبکه +Comment[fi]=Verkkokansiovalikko +Comment[fr]=Menu des dossiers réseau +Comment[fy]=Menu mei netwurkmappen +Comment[gl]=Aceso doado cartafoles en rede +Comment[he]=תפריט של תיקיות רשת +Comment[hr]=Izbornik mrežnih mapa +Comment[hu]=A hálózati mappák menüje +Comment[is]=Einföld leið að netmöppum +Comment[it]=Menu delle cartelle di rete +Comment[ja]=ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ•ã‚©ãƒ«ãƒ€ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=ქსელური დáƒáƒ¡áƒ¢áƒ”ბის მენიუ +Comment[kk]=Желідегі қапшықтар мәзірі +Comment[km]=ម៉ឺនុយ​របស់​ážážâ€‹áž”ណ្ážáž¶áž‰ +Comment[lt]=Tinklo aplankų meniu +Comment[mk]=Мени на мрежните папки +Comment[nb]=Meny over nettverksmappene +Comment[nds]=Menü vun Nettwarkornern +Comment[ne]=सञà¥à¤œà¤¾à¤² फोलà¥à¤¡à¤°à¤•à¥‹ मेनॠ+Comment[nl]=Menu met netwerkmappen +Comment[nn]=Meny over nettverksmapper +Comment[pa]=ਨੈੱਟਵਰਕ ਫੋਲਡਰ ਲਈ ਮੇਨੂ +Comment[pl]=Menu folderów sieciowych +Comment[pt]=Menu de pastas de rede +Comment[pt_BR]=Acesso fácil à s pastas de rede +Comment[ro]=Meniu cu folderele de reÈ›ea +Comment[ru]=БыÑтрый доÑтуп к Ñетевым папкам +Comment[se]=Fállu mii Äájeha fierpmádatmáhpaid +Comment[sk]=Menu sieÅ¥ových prieÄinkov +Comment[sl]=Meni z omrežnimi mapami +Comment[sr]=Мени мрежних фаÑцикли +Comment[sr@Latn]=Meni mrežnih fascikli +Comment[sv]=Meny med nätverkskataloger +Comment[th]=เมนูขà¸à¸‡à¹‚ฟลเดà¸à¸£à¹Œà¸šà¸™à¹€à¸„รืà¸à¸‚่าย +Comment[tr]=AÄŸ dizinlerinin menüsü +Comment[uk]=Меню мережних тек +Comment[uz]=Tarmoq jildlarining menyusi +Comment[uz@cyrillic]=Тармоқ жилдларининг менюÑи +Comment[vi]=Thá»±c Ä‘Æ¡n chứa thÆ° mục mạng +Comment[wa]=Dressêye des ridants rantoele +Comment[zh_CN]=网络文件夹èœå• +Comment[zh_TW]=網路資料夾é¸å–® +Icon=network + +X-KDE-Library=kickermenu_remotemenu diff --git a/kicker/menuext/remote/remotemenu.h b/kicker/menuext/remote/remotemenu.h new file mode 100644 index 000000000..1e46bb4e3 --- /dev/null +++ b/kicker/menuext/remote/remotemenu.h @@ -0,0 +1,53 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef REMOTEMENU_H +#define REMOTEMENU_H + +#include <kdirnotify.h> +#include <kpanelmenu.h> +#include <qmap.h> + +class RemoteMenu : public KPanelMenu, public KDirNotify +{ + Q_OBJECT + K_DCOP + + public: + RemoteMenu(QWidget *parent, const char *name, + const QStringList & /*args*/); + ~RemoteMenu(); + + k_dcop: + virtual ASYNC FilesAdded(const KURL &directory); + virtual ASYNC FilesRemoved(const KURL::List &fileList); + virtual ASYNC FilesChanged(const KURL::List &fileList); + virtual ASYNC FilesRenamed(const KURL &src, const KURL &dest); + + protected slots: + void initialize(); + void startWizard(); + void openRemoteDir(); + void slotExec(int id); + + private: + QMap<int, QString> m_desktopMap; +}; + +#endif diff --git a/kicker/menuext/system/Makefile.am b/kicker/menuext/system/Makefile.am new file mode 100644 index 000000000..aa5d3d33f --- /dev/null +++ b/kicker/menuext/system/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_systemmenu.la + +kickermenu_systemmenu_la_SOURCES = systemmenu.cpp +kickermenu_systemmenu_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined +kickermenu_systemmenu_la_LIBADD = $(LIB_KDEUI) $(LIB_KIO) $(top_builddir)/kicker/libkicker/libkickermain.la + +kickermenu_systemmenu_la_METASOURCES = AUTO + +desktopmenu_DATA = systemmenu.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +messages: + $(XGETTEXT) *.cpp -o $(podir)/libkickermenu_systemmenu.pot diff --git a/kicker/menuext/system/systemmenu.cpp b/kicker/menuext/system/systemmenu.cpp new file mode 100644 index 000000000..68c3f5c66 --- /dev/null +++ b/kicker/menuext/system/systemmenu.cpp @@ -0,0 +1,91 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "systemmenu.h" + +#include <krun.h> +#include <kiconloader.h> +#include <qpixmap.h> + +#include "global.h" + +K_EXPORT_KICKER_MENUEXT(systemmenu, SystemMenu) + + +SystemMenu::SystemMenu(QWidget *parent, const char *name, + const QStringList &/*args*/) + : KPanelMenu( parent, name) +{ + connect( &m_dirLister, SIGNAL( completed() ), + this, SLOT( slotCompleted() ) ); + + m_dirLister.openURL(KURL("system:/")); +} + +SystemMenu::~SystemMenu() +{ +} + +void SystemMenu::append(const QString &icon, const KURL &url, + const QString &label) +{ + int id = insertItem(KickerLib::menuIconSet(icon), label); + m_urlMap.insert(id, url); +} + +void SystemMenu::initialize() +{ + if (isVisible()) return; + + clear(); + + if (m_entries.isEmpty()) + { + insertItem(i18n("Empty...")); + return; + } + + m_urlMap.clear(); + + KFileItemList::ConstIterator it = m_entries.begin(); + KFileItemList::ConstIterator end = m_entries.end(); + + for (; it!=end; ++it) + { + QString icon = (*it)->iconName(); + KURL url = (*it)->url(); + QString name = (*it)->name(); + append(icon, url, name); + } +} + +void SystemMenu::slotExec(int id) +{ + if(!m_urlMap.contains(id)) return; + + new KRun(m_urlMap[id]); // will delete itself +} + +void SystemMenu::slotCompleted() +{ + m_entries = m_dirLister.items(KDirLister::AllItems); + setInitialized(false); +} + +#include "systemmenu.moc" diff --git a/kicker/menuext/system/systemmenu.desktop b/kicker/menuext/system/systemmenu.desktop new file mode 100644 index 000000000..29156838c --- /dev/null +++ b/kicker/menuext/system/systemmenu.desktop @@ -0,0 +1,127 @@ +[Desktop Entry] +Name=System Menu +Name[af]=Stelsel Kieslys +Name[ar]=قائمة النظام +Name[be]=СіÑÑ‚Ñмнае меню +Name[bg]=СиÑтемно меню +Name[bn]=সিসà§à¦Ÿà§‡à¦® মেনৠ+Name[br]=Meuziad ar reizhiad +Name[bs]=Sistemski meni +Name[ca]=Menú de sistema +Name[cs]=Systémová nabÃdka +Name[csb]=Systema +Name[cy]=Dewislen y Cysawd +Name[da]=Systemmenu +Name[de]=System-Menü +Name[el]=ÎœÎµÎ½Î¿Ï ÏƒÏ…ÏƒÏ„Î®Î¼Î±Ï„Î¿Ï‚ +Name[eo]=SistemMenuo +Name[es]=Menú del sistema +Name[et]=Süsteemi menüü +Name[eu]=Sistemaren menua +Name[fa]=گزینگان سیستم +Name[fi]=Järjestelmävalikko +Name[fr]=Menu du système +Name[fy]=Systeemmenu +Name[ga]=Roghchlár an Chórais +Name[gl]=Sistema +Name[he]=תפריט מערכת +Name[hr]=Sistemski izbornik +Name[hu]=Rendszermenü +Name[is]=Kerfisvalmynd +Name[it]=Menu di Sistema +Name[ja]=システムメニュー +Name[ka]=სისტემის მენიუ +Name[kk]=Жүйе мәзірі +Name[km]=ប្រពáŸáž“្ធ​ម៉ឺនុយ +Name[lt]=Sistemos meniu +Name[mk]=СиÑтемÑко мени +Name[nb]=Systemmeny +Name[nds]=Systeem-Menü +Name[ne]=पà¥à¤°à¤£à¤¾à¤²à¥€ मेनॠ+Name[nl]=Systeemmenu +Name[nn]=Systemmeny +Name[pa]=ਸਿਸਟਮ ਮੇਨੂ +Name[pl]=System +Name[pt]=Menu do Sistema +Name[pt_BR]=Menu Sistema +Name[ro]=Meniu sistem +Name[ru]=СиÑтема +Name[se]=Vuogádatfállu +Name[sk]=Systémové menu +Name[sl]=Sistem +Name[sr]=СиÑтемÑки мени +Name[sr@Latn]=Sistemski meni +Name[sv]=Systemmeny +Name[te]=à°µà±à°¯à°µà°¸à±à°¥ పటà±à°Ÿà°¿ +Name[tg]=Менюи ÑиÑтема +Name[th]=เมนูระบบ +Name[tr]=Sistem Menüsü +Name[uk]=СиÑтемне меню +Name[uz]=Tizim menyusi +Name[uz@cyrillic]=Тизим менюÑи +Name[vi]=Thá»±c Ä‘Æ¡n Hệ thống +Name[wa]=Dressêye sistinme +Name[zh_CN]=系统èœå• +Name[zh_TW]=系統é¸å–® +Comment=Menu of important system places +Comment[af]=Kieslys vir belangrike stelsel plekke +Comment[ar]=قائمة أمكنة النظام الهامة +Comment[be]=Меню важных ÑÑ–ÑÑ‚Ñмных меÑцаў +Comment[bg]=Меню за доÑтъп до ÑиÑтемните директории +Comment[bn]=সিসà§à¦Ÿà§‡à¦®à§‡à¦° গà§à¦°à§à¦¤à§à¦¬à¦ªà§‚রà§à¦£ অবসà§à¦¥à¦¾à¦¨à¦—à§à¦²à¦¿à¦° তালিকা +Comment[bs]=Meni sa sistemskim lokacijama +Comment[ca]=Menú de llocs importants del sistema +Comment[cs]=NabÃdka důležitých systémových mÃst +Comment[csb]=Menu z wôżnëma placama systemë +Comment[da]=Menu med vigtige steder pÃ¥ systemet +Comment[de]=Einfacher Zugriff auf Systemordner +Comment[el]=ÎœÎµÎ½Î¿Ï ÏƒÎ·Î¼Î±Î½Ï„Î¹ÎºÏŽÎ½ τοποθεσιών του συστήματος +Comment[eo]=Menuo de gravaj sistemlokoj +Comment[es]=Menú de lugares importantes del sistema +Comment[et]=Olulisemate süsteemi osade menüü +Comment[eu]=Sistemaren leku garrantzitsuen menua +Comment[fa]=گزینگان جاهای مهم سیستم +Comment[fi]=Järjestelmän tärkeiden asetuksien valikko +Comment[fr]=Menu dirigeant vers les endroits importants du système +Comment[fy]=Menu mei wichtige systeemgebieden +Comment[gl]=Aceso doado a lugares de importáncia para o sistema +Comment[he]=תפריט של מקומות מערכת ×—×©×•×‘×™× +Comment[hr]=Izbornik važnih lokacija sustava +Comment[hu]=A rendszerkönyvtárak menüje +Comment[is]=Fljótleg leið að mikilvægum kerfishlutum +Comment[it]=Menu con gli oggetti importanti del sistema +Comment[ja]=システムã®é‡è¦ãªå ´æ‰€ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ +Comment[ka]=სისტემის მნიშვნელáƒáƒ•áƒáƒœ áƒáƒ“გილთრმენიუ +Comment[kk]=Маңызды жүйелік орындарының мәзірі +Comment[km]=ម៉ឺនុយ​កន្លែង​ប្រពáŸáž“្ធ​សំážáž¶áž“់ +Comment[lt]=Svarbių sistemos vietų meniu +Comment[mk]=Мени Ñо важни ÑиÑтемÑки реÑурÑи +Comment[nb]=Meny over viktige systemsteder +Comment[nds]=Menü vun wichtig Systeemornern +Comment[ne]=महतà¥à¤µà¤ªà¥‚रà¥à¤£ पà¥à¤°à¤£à¤¾à¤²à¥€ सà¥à¤¥à¤¾à¤¨à¤•à¥‹ मेनॠ+Comment[nl]=Menu met belangrijke systeemgebieden +Comment[nn]=Meny over viktige systemstader +Comment[pa]=ਸਿਸਟਮ ਥਾਵਾਂ ਲ਼ਈ ਮੇਨੂ +Comment[pl]=Menu z ważnymi miejscami systemu +Comment[pt]=Um menu com os locais importantes do sistema +Comment[pt_BR]=Acesso fácil a locais importantes do sistema +Comment[ro]=Meniu cu locaÈ›ii importante din sistem +Comment[ru]=БыÑтрый доÑтуп к ÑиÑтемным реÑурÑам +Comment[se]=Fállu mii Äájeha dehálaÅ¡ báikkiid vuogádagas +Comment[sk]=Menu dôležitých systémových miest +Comment[sl]=Meni s pomembnimi sistemskimi lokacijami +Comment[sr]=Мени важних меÑта на ÑиÑтему +Comment[sr@Latn]=Meni važnih mesta na sistemu +Comment[sv]=Meny med viktiga systemplatser +Comment[th]=เมนูสำหรับที่สำคัà¸à¹† ขà¸à¸‡à¸£à¸°à¸šà¸š +Comment[tr]=Önemli sistem yerlerinin menüsü +Comment[uk]=Меню важливих міÑць в ÑиÑтемі +Comment[uz]=Tizimda muhim boÊ»lgan joylarning menyusi +Comment[uz@cyrillic]=Тизимда муҳим бўлган жойларнинг менюÑи +Comment[vi]=Thá»±c Ä‘Æ¡n chứa các liên kết hệ thống quan trá»ng +Comment[wa]=Dressêye des impôrtantès plaeces do sistinmes +Comment[zh_CN]=é‡è¦ç³»ç»Ÿä½ç½®çš„èœå• +Comment[zh_TW]=é‡è¦ç³»çµ±ä½ç½®é¸å–® +Icon=system + +X-KDE-Library=kickermenu_systemmenu diff --git a/kicker/menuext/system/systemmenu.h b/kicker/menuext/system/systemmenu.h new file mode 100644 index 000000000..6f118d21c --- /dev/null +++ b/kicker/menuext/system/systemmenu.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (c) 2004 Kevin Ottens <ervin ipsquad net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SYSTEMMENU_H +#define SYSTEMMENU_H + +#include <kpanelmenu.h> +#include <kurl.h> +#include <kdirlister.h> +#include <kfileitem.h> + +class SystemMenu : public KPanelMenu +{ + Q_OBJECT + + public: + SystemMenu(QWidget *parent, const char *name, + const QStringList & /*args*/); + ~SystemMenu(); + + protected slots: + void initialize(); + void slotExec(int id); + + void slotCompleted(); + + private: + void append(const QString &icon, const KURL &url, const QString &label); + KDirLister m_dirLister; + KFileItemList m_entries; + QMap<int, KURL> m_urlMap; +}; + +#endif diff --git a/kicker/menuext/tom/Makefile.am b/kicker/menuext/tom/Makefile.am new file mode 100644 index 000000000..4947ef77b --- /dev/null +++ b/kicker/menuext/tom/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(srcdir)/../../libkicker -I$(srcdir)/../../ui -I$(srcdir)/../../core $(all_includes) + +kde_module_LTLIBRARIES = kickermenu_tom.la + +kickermenu_tom_la_SOURCES = tom.cc +kickermenu_tom_la_LDFLAGS = $(all_libraries) -module -avoid-version +kickermenu_tom_la_LIBADD = $(LIB_KDEUI) +#$(top_builddir)/kicker/ui/libkicker_ui.la + +kickermenu_tom_la_METASOURCES = AUTO + +desktopmenu_DATA = tom.desktop +desktopmenudir = $(kde_datadir)/kicker/menuext + +tomdata_DATA = destinations +tomdatadir = $(kde_datadir)/kicker/tom + +messages: + $(XGETTEXT) *.cc -o $(podir)/libkickermenu_tom.pot diff --git a/kicker/menuext/tom/README b/kicker/menuext/tom/README new file mode 100644 index 000000000..2616c76c5 --- /dev/null +++ b/kicker/menuext/tom/README @@ -0,0 +1,65 @@ +What is TOM? +============ +TOM stands for Task Oriented Menu and is a work in progress that will become a +viable alternative to the current KMenu. Its goals include: + + o Be task oriented + o Be simple and clear to use + o Create a smaller but usable menu + o Limited configurability through sensible defaults + o Have all configuration needs built right into the menu, including: + o Editor dialogs that can be called up from entries in the menu + o Context menus accessed by RMB clicking on a task for powerusers + o Allow locking down of menus through immutable settings + o Obeys Kicker and KDE Kiosk settings + o By making the TOM group of kickerrc immutable all config is removed + o By making a task group's rc file immutable, config options are removed + o Not require any modifications to the KDE menu system (applnk, etc) + + +What is a "Task Oriented Menu"? +================================ +A task oriented menu displays it's entries as "things to do" (or tasks) rather +than simply listing all items that are available. Each of these tasks has an +application or command associated with it, and this associated command can be +changed without changing the task name or placement within the menu. The tasks +are grouped by function and may map to programs, documents or actions. + + +Todo list +========= +Editor dialogs +Make the Destination entries work (only Run A Command is done) +Populate and track Recent Applications menu entries + o Application launching should be caught somewhere in the KDE libs, ala + Recent Documents +Writing out of config files to reflect runtime changes (deleted entries, etc) + o This requires keeping track of the config files used in creating the menu +KDEDIR merging + o KDEDIRS are already consulted for taskgroups, but groups of the same name + should be merged +Sane merging of menuext entries + o "Recent" items should go into the recent section + o Replace TOM's builin recent docs with the menuext version? + o Create a Recent Applications menuext? + o Add a way to quickly add/remove menuext items from TOM + (ala "Modify These Tasks") +Check for updates on launch and bring them down/install them if they exist + o this includes new apps installed on the local box showing up in the menu + o "Get cool stuff" integration? +Further refinement of wording / ordering in main menu (a perpetual TODO ;) +Creation of real-world task groups +Support plugins which can add arbitrary functionality to the menu + + +Debate list +=========== +What should be the default task entry format be: + a) Task Name + b) Task Name (App Name) + c) App Name (Task Name) <-- silly option =) +Should "Run A Command..." be replaced by an inline combobox? + Pros: It's more obvious and will work even if kdesktop is gone. The widget + is already written (in tom.cc) + Cons: It makes it stand out too much over other entries, takes up more room + and isn't as powerful as the full minicli diff --git a/kicker/menuext/tom/TASKGROUPS b/kicker/menuext/tom/TASKGROUPS new file mode 100644 index 000000000..c1aa1ed98 --- /dev/null +++ b/kicker/menuext/tom/TASKGROUPS @@ -0,0 +1,49 @@ +Task Groups +=========== +Tasks are grouped into common families of functionality. These groups are then +stored in a standard KDE configuration file. The General category in the +config file defines the icon (Icon), user visible name (Name), the number +of tasks in the group (NumTasks) and optionally whether or not it is hidden +(Hidden). + +For each task there is a numbered section in the file in the form TaskN. Each +section contains the user visible name for the task (Name), the associated +.desktop file and optionally whether or not it is hidden (Hidden). + +An example file can be found below. + +Alternatives +============ +Alternative formats are possible, including making it more like the servicemenu +.desktop format or the new virtual menu freedesktop.org draft standard. Here are +the pros and cons of each of these options: + +servicemenu style: + o CONS: no extra flexibility, still have to do most checking manually + o PROS: familiar format + +virtual menu style: + o CONS: it's XML and that's way more trouble that we need to go through, and it + isn't really designed with this sort of menu in mind + o PROS: it's becoming a standard for desktop menus + + +Example +======= +[General] +Icon=konqueror +Name=Internet +NumTasks=3 +Hidden=true + +[Task0] +Name=Browse the web +DesktopFile=applications/konqbrowser.desktop + +[Task1] +Name=EMail +DesktopFile=Internet/KMail.desktop + +[Task2] +Name=VNC +DesktopFile=Internet/keystone.desktop diff --git a/kicker/menuext/tom/destinations b/kicker/menuext/tom/destinations new file mode 100644 index 000000000..6e075237f --- /dev/null +++ b/kicker/menuext/tom/destinations @@ -0,0 +1,18 @@ +[General] +NumTasks=4 + +[Task0] +Name=Consult Manuals +DesktopFile=Help.desktop + +[Task1] +Name=Find Files +DesktopFile=Kfind.desktop + +[Task2] +Name=Adjust Settings +DesktopFile=KControl.desktop + +[Task3] +Name=Browse My Files +DesktopFile=Home.desktop diff --git a/kicker/menuext/tom/tom.cc b/kicker/menuext/tom/tom.cc new file mode 100644 index 000000000..80ea3e71d --- /dev/null +++ b/kicker/menuext/tom/tom.cc @@ -0,0 +1,855 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Aaron J. Seigo <aseigo@olympusproject.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <iostream> +using namespace std; + +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> + +#include <qdir.h> +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qregexp.h> +#include <qsettings.h> +#include <qstyle.h> +#include <qfile.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kcombobox.h> +#include <kdialog.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kiconeffect.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kmimetype.h> +#include <kpixmap.h> +#include <krecentdocument.h> +#include <kservice.h> +#include <kservicegroup.h> +#include <kstandarddirs.h> +#include <kstdaction.h> +#include <ksycocaentry.h> + +#include "menuinfo.h" +#include "service_mnu.h" +#include "kicker.h" +#include "tom.h" + +const int configureMenuID = 1000; +const int contextMenuTitleID = 10000; +const int destMenuTitleID = 10001; + +extern "C" +{ + KDE_EXPORT void* init_kickermenu_tom() + { + KGlobal::locale()->insertCatalogue("libkickermenu_tom"); + return new TOMFactory; + } +}; + +TOMFactory::TOMFactory(QObject *parent, const char *name) +: KLibFactory(parent, name) +{ +} + +QObject* TOMFactory::createObject(QObject *parent, const char *name, const char*, const QStringList&) +{ + return new TOM((QWidget*)parent, name); +} + +#include <qmenudata.h> +/* + * TODO: switch the backgroundmode when translucency turns on/off + * TODO: catch font changes too? + */ +class runMenuWidget : public QWidget, public QMenuItem +{ + public: + runMenuWidget(KPopupMenu* parent, int index) + : QWidget (parent), + m_menu(parent), + m_index(index) + { + setFocusPolicy(StrongFocus); + + QHBoxLayout* runLayout = new QHBoxLayout(this); + textRect = fontMetrics().boundingRect(i18n("Run:")); + runLayout->setSpacing(KDialog::spacingHint()); + runLayout->addSpacing((KDialog::spacingHint() * 3) + KIcon::SizeMedium + textRect.width()); + icon = DesktopIcon("run", KIcon::SizeMedium); + /*QLabel* l1 = new QLabel(this); + QPixmap foo = DesktopIcon("run", KIcon::SizeMedium); + cout << "foo is: " << foo.width() << " by " << foo.height() << endl; + l1->setPixmap(foo); + runLayout->addWidget(l1);*/ + /*QLabel* l2 = new QLabel(i18n("&Run: "), this); + l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + l2->setBuddy(this); + runLayout->addWidget(l2);*/ + m_runEdit = new KHistoryCombo(this); + m_runEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + runLayout->addWidget(m_runEdit, 10); + runLayout->addSpacing(KDialog::spacingHint()); + + QSettings settings; + if (settings.readEntry("/KStyle/Settings/MenuTransparencyEngine", "Disabled") != "Disabled") + { + setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //l1->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + m_runEdit->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + } + else + { + /*setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + l1->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + l2->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + m_runEdit->setBackgroundMode(Qt::NoBackground, Qt::NoBackground);*/ + //l1->setAutoMask(true); + //l1->setBackgroundMode(Qt::NoBackground, Qt::NoBackground); + //l2->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + //m_runEdit->setBackgroundMode(Qt::X11ParentRelative, Qt::X11ParentRelative); + } + + setMinimumHeight(KIcon::SizeMedium + 2); + } + ~runMenuWidget() {} + + + void paintEvent(QPaintEvent * /*e*/) + { + QPainter p(this); + QRect r(rect()); + // ew, nasty hack. may result in coredumps due to horrid C-style cast??? + kapp->style().drawControl(QStyle::CE_PopupMenuItem, &p, m_menu, r, palette().active(), QStyle::Style_Enabled, + QStyleOption(static_cast<QMenuItem*>(this), 0, KIcon::SizeMedium )); + p.drawPixmap(KDialog::spacingHint(), 1, icon); + p.drawText((KDialog::spacingHint() * 2) + KIcon::SizeMedium, textRect.height() + ((height() - textRect.height()) / 2), i18n("Run:")); + } + + void focusInEvent (QFocusEvent* e) + { + if (!e || e->gotFocus()) + { + m_menu->setActiveItem(m_index); + m_runEdit->setFocus(); + } + } + + void enterEvent(QEvent*) + { + focusInEvent(0); + } + + private: + KPopupMenu* m_menu; + KHistoryCombo* m_runEdit; + QPixmap icon; + QRect textRect; + int m_index; +}; + +TOM::TOM(QWidget *parent, const char *name) + : KPanelMenu(parent, name), + m_maxIndex(0) +{ + disableAutoClear(); + m_submenus.setAutoDelete(true); + setCaption(i18n("Task-Oriented Menu")); + + // KMenu legacy: support some menu config options + KConfig* config = KGlobal::config(); + config->setGroup("menus"); + m_detailedTaskEntries = config->readBoolEntry("DetailedMenuEntries", false); + if (m_detailedTaskEntries) + { + m_detailedNamesFirst = config->readBoolEntry("DetailedEntriesNamesFirst", false); + } + + m_isImmutable = Kicker::kicker()->isImmutable() || config->groupIsImmutable("TOM"); + config->setGroup("TOM"); + m_largerFont = font(); + m_largerFont = config->readFontEntry("Font", &m_largerFont); +} + +TOM::~TOM() +{ + slotClear(); +} + +void TOM::initializeRecentApps(QPopupMenu* menu) +{ + /* + * TODO: make this real + * add a KDE-wide "commands run" registry + */ + + if (!m_isImmutable) + { + menu->insertSeparator(); + menu->insertItem(i18n("Configure This Menu"), configureMenuID); + } +} + +void TOM::initializeRecentDocs() +{ + m_recentDocsMenu->clear(); + m_recentDocsMenu->insertItem(SmallIconSet("history_clear"), i18n("Clear History"), + this, SLOT(clearRecentDocHistory())); + m_recentDocsMenu->insertSeparator(); + + m_recentDocURLs = KRecentDocument::recentDocuments(); + + if (m_recentDocURLs.isEmpty()) + { + setItemEnabled(m_recentDocsMenu->insertItem(i18n("No Entries")), false); + return; + } + + int id = 0; + for (QStringList::ConstIterator it = m_recentDocURLs.begin(); + it != m_recentDocURLs.end(); + ++it) + { + /* + * TODO: make the number of visible items configurable? + */ + + KDesktopFile f(*it, true /* read only */); + m_recentDocsMenu->insertItem(DesktopIcon(f.readIcon(), KIcon::SizeMedium), + f.readName().replace('&', "&&"), id); + ++id; + } +} + +int TOM::appendTaskGroup(KConfig& config, bool inSubMenu) +{ + if (!config.hasGroup("General")) + { + return 0; + } + + config.setGroup("General"); + + if (config.readBoolEntry("Hidden", false)) + { + return 0; + } + + QString name = config.readEntry("Name", i18n("Unknown")); + QString icon = config.readEntry("Icon"); + int numTasks = config.readNumEntry("NumTasks", 0); + + if (numTasks < 1) + { + return 0; + } + + KPopupMenu* taskGroup; + if( inSubMenu ) + { + taskGroup = new KPopupMenu(this); + + if (icon != QString::null) + { + insertItem(DesktopIcon(icon, KIcon::SizeMedium), name, taskGroup); + } + else + { + insertItem(name, taskGroup); + } + } + else + { + taskGroup = this; + } + + int foundTasks = 0; + for (int i = 0; i < numTasks; ++i) + { + QString groupName = QString("Task%1").arg(i); + + if (config.hasGroup(groupName)) + { + config.setGroup(groupName); + + if (config.readBoolEntry("Hidden", false)) + { + continue; + } + + QString name = config.readEntry("Name"); + // in case the name contains an ampersand, double 'em up + name.replace("&", "&&"); + QString desktopfile = config.readPathEntry("DesktopFile"); + KService::Ptr pService = KService::serviceByDesktopPath(desktopfile); + + if (!pService) + { + pService = KService::serviceByDesktopName(desktopfile); + + if (!pService) + { + continue; + } + } + + QString execName = pService->name(); + QString icon = pService->icon(); + + if (m_detailedTaskEntries && !execName.isEmpty()) + { + QString tmp = i18n("%1 (%2)"); + + if (m_detailedNamesFirst) + { + name = tmp.arg(execName).arg(name); + } + else + { + name = tmp.arg(name).arg(execName); + } + } + + ++m_maxIndex; + if (icon.isEmpty()) + { + taskGroup->insertItem(name, m_maxIndex); + } + else + { + + QIconSet iconset = BarIconSet(icon, 22); + if (iconset.isNull()) + taskGroup->insertItem(name, m_maxIndex); + else + taskGroup->insertItem(iconset, name, m_maxIndex); + + } + + m_tasks.insert(m_maxIndex, pService); + ++foundTasks; + } + } + + // if we end up with an empty task group, get rid of the menu + if (foundTasks == 0) + { + if (inSubMenu) + { + delete taskGroup; + } + + return 0; + } + + connect(taskGroup, SIGNAL(activated(int)), this, SLOT(runTask(int))); + // so we have an actual task group menu with tasks, let's add it + + if (inSubMenu) + { + QObject::connect(taskGroup, SIGNAL(aboutToShowContextMenu(KPopupMenu*, int, QPopupMenu*)), + this, SLOT(contextualizeRMBmenu(KPopupMenu*, int, QPopupMenu*))); + + m_submenus.append(taskGroup); + + taskGroup->setFont(m_largerFont); + taskGroup->setKeyboardShortcutsEnabled(true); + + if (!m_isImmutable && !config.isImmutable()) + { + taskGroup->insertSeparator(); + taskGroup->insertItem("Modify These Tasks", configureMenuID); + QPopupMenu* rmbMenu = taskGroup->contextMenu(); + rmbMenu->setFont(m_largerFont); + KPopupTitle* title = new KPopupTitle(); + title->setText(i18n("%1 Menu Editor").arg(name)); + rmbMenu->insertItem(title, contextMenuTitleID); + rmbMenu->insertItem(i18n("Add This Task to Panel")); + rmbMenu->insertItem(i18n("Modify This Task...")); + rmbMenu->insertItem(i18n("Remove This Task..."), this, SLOT(removeTask())); + rmbMenu->insertItem(i18n("Insert New Task...")); + } + } + + return foundTasks; +} +/* + * TODO: track configuration file changes. +void TOM::configChanged() +{ + KPanelMenu::configChanged(); + setInitialized(false); + initialize(); +} +*/ +void TOM::initialize() +{ + if (initialized()) + { + return; + } + + setInitialized(true); + m_submenus.clear(); + m_tasks.clear(); + clear(); + + /* hack to make items larger. should use something better? + m_largerFont = font(); + if (m_largerFont.pointSize() < 18) + { + m_largerFont.setPointSize(18); + } + setFont(m_largerFont);*/ + + + /*if (!loadSidePixmap()) + { + m_sidePixmap = m_sideTilePixmap = QPixmap(); + } + else + { + connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged())); + }*/ + + // TASKS + insertTitle(i18n("Tasks"), contextMenuTitleID); + + QStringList dirs = KGlobal::dirs()->findDirs("data", "kicker/tom/"); + QStringList::ConstIterator dIt = dirs.begin(); + QStringList::ConstIterator dEnd = dirs.end(); + + for (; dIt != dEnd; ++dIt ) + { + QDir dir(*dIt); + + QStringList entries = dir.entryList("*rc", QDir::Files); + QStringList::ConstIterator eIt = entries.begin(); + QStringList::ConstIterator eEnd = entries.end(); + + for (; eIt != eEnd; ++eIt ) + { + KConfig config(*dIt + *eIt); + appendTaskGroup(config); + } + } + + PanelServiceMenu* moreApps = new PanelServiceMenu(QString::null, QString::null, this, "More Applications"); + moreApps->setFont(m_largerFont); + insertItem(DesktopIcon("misc", KIcon::SizeMedium), i18n("More Applications"), moreApps); + m_submenus.append(moreApps); + + if (!m_isImmutable) + { + insertSeparator(); + // TODO: connect to taskgroup edits + insertItem("Modify The Above Tasks"); + } + + // DESTINATIONS + insertTitle(i18n("Destinations"), destMenuTitleID); + int numDests = 0; + QString destinationsConfig = locate("appdata", "tom/destinations"); + + if (!destinationsConfig.isEmpty() && QFile::exists(destinationsConfig)) + { + KConfig config(destinationsConfig); + numDests = appendTaskGroup(config, false); + } + + if (numDests == 0) + { + removeItem(destMenuTitleID); + } + else if (kapp->authorize("run_command")) + { + insertItem(DesktopIcon("run", KIcon::SizeMedium), i18n("Run Command..."), this, SLOT(runCommand())); + } + + // RECENTLY USED ITEMS + insertTitle(i18n("Recently Used Items"), contextMenuTitleID); + + m_recentDocsMenu = new KPopupMenu(this, "recentDocs"); + m_recentDocsMenu->setFont(m_largerFont); + connect(m_recentDocsMenu, SIGNAL(aboutToShow()), this, SLOT(initializeRecentDocs())); + connect(m_recentDocsMenu, SIGNAL(activated(int)), this, SLOT(openRecentDocument(int))); + insertItem(DesktopIcon("document", KIcon::SizeMedium), i18n("Recent Documents"), m_recentDocsMenu); + m_submenus.append(m_recentDocsMenu); + + KPopupMenu* recentApps = new KPopupMenu(this, "recentApps"); + recentApps->setFont(m_largerFont); + recentApps->setKeyboardShortcutsEnabled(true); + initializeRecentApps(recentApps); + insertItem(i18n("Recent Applications"), recentApps); + m_submenus.append(recentApps); + + // SPECIAL ITEMS + insertTitle(i18n("Special Items"), contextMenuTitleID); + + // if we have no destinations, put the run command here + if (numDests == 0 && kapp->authorize("run_command")) + { + insertItem(DesktopIcon("run", KIcon::SizeMedium), i18n("Run Command..."), this, SLOT(runCommand())); + } + + + KConfig* config = KGlobal::config(); + QStringList menu_ext = config->readListEntry("Extensions"); + if (!menu_ext.isEmpty()) + { + bool needSeparator = false; + for (QStringList::ConstIterator it = menu_ext.begin(); it != menu_ext.end(); ++it) + { + MenuInfo info(*it); + if (!info.isValid()) + { + continue; + } + + KPanelMenu *menu = info.load(); + if (menu) + { + ++m_maxIndex; + insertItem(DesktopIcon(info.icon(), KIcon::SizeMedium), info.name(), menu, m_maxIndex); + m_submenus.append(menu); + needSeparator = true; + } + } + + if (needSeparator) + { + insertSeparator(); + } + } + + + QString username; + struct passwd *userInfo = getpwuid(getuid()); + if (userInfo) + { + username = QString::fromLocal8Bit(userInfo->pw_gecos); + if (username.find(',') != -1) + { + // Remove everything from and including first comma + username.truncate(username.find(',')); + } + + if (username.isEmpty()) + { + username = QString::fromLocal8Bit(userInfo->pw_name); + } + } + + insertItem(DesktopIcon("exit", KIcon::SizeMedium), + i18n("Logout %1").arg(username), this, SLOT(logout())); +} + +void TOM::reload() +{ + setInitialized(false); + initialize(); +} + +void TOM::contextualizeRMBmenu(KPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu) +{ + if (menuItem == configureMenuID) + { + menu->hideContextMenu(); + return; + } + + ctxMenu->removeItem(contextMenuTitleID); + QString text = menu->text(menuItem); + int parens = text.find('(') - 1; + if (parens > 0) + { + text = text.left(parens); + } + KPopupTitle* title = new KPopupTitle(); + title->setText(i18n("The \"%2\" Task").arg(text)); + ctxMenu->insertItem(title, contextMenuTitleID, 0); +} + +void TOM::slotClear() +{ + KPanelMenu::slotClear(); + m_submenus.clear(); + m_tasks.clear(); +} + +void TOM::slotExec(int /* id */) +{ + // Reimplemented because we have to +} + +void TOM::removeTask() +{ + // TODO: write this change out to the appropriate config file + QString task = KPopupMenu::contextMenuFocus()->text(KPopupMenu::contextMenuFocusItem()); + if (KMessageBox::warningContinueCancel(this, + i18n("<qt>Are you sure you want to remove the <strong>%1</strong> task?<p>" + "<em>Tip: You can restore the task after it has been removed by selecting the "Modify These Tasks" entry</em></qt>").arg(task), + i18n("Remove Task?"),KStdGuiItem::del()) == KMessageBox::Continue) + { + m_tasks.remove(KPopupMenu::contextMenuFocusItem()); + KPopupMenu::contextMenuFocus()->removeItem(KPopupMenu::contextMenuFocusItem()); + } +} + +// TODO: should we have a side graphic like the K Menu? personally, i don't +// think it helps usability. it's nice for branding, but that's it. perhaps a +// top image, or something blended with the actual menu background? deffinitely +// a job for a graphic artist. +/* + * if this goes in, it should be shared w/the kmenu + * +bool TOM::loadSidePixmap() +{ + KConfig *config = KGlobal::config(); + QColor color = palette().active().highlight(); + QImage image; + + config->setGroup("WM"); + QColor activeTitle = config->readColorEntry("activeBackground", &color); + QColor inactiveTitle = config->readColorEntry("inactiveBackground", &color); + + config->setGroup("KMenu"); + if (!config->readBoolEntry("Usem_sidePixmap", true)) + return false; + + // figure out which color is most suitable for recoloring to + int h1, s1, v1, h2, s2, v2, h3, s3, v3; + activeTitle.hsv(&h1, &s1, &v1); + inactiveTitle.hsv(&h2, &s2, &v2); + palette().active().background().hsv(&h3, &s3, &v3); + + if ( (abs(h1-h3)+abs(s1-s3)+abs(v1-v3) < abs(h2-h3)+abs(s2-s3)+abs(v2-v3)) && + ((abs(h1-h3)+abs(s1-s3)+abs(v1-v3) < 32) || (s1 < 32)) && (s2 > s1)) + color = inactiveTitle; + else + color = activeTitle; + + // limit max/min brightness + int r, g, b; + color.rgb(&r, &g, &b); + int gray = qGray(r, g, b); + if (gray > 180) { + r = (r - (gray - 180) < 0 ? 0 : r - (gray - 180)); + g = (g - (gray - 180) < 0 ? 0 : g - (gray - 180)); + b = (b - (gray - 180) < 0 ? 0 : b - (gray - 180)); + } else if (gray < 76) { + r = (r + (76 - gray) > 255 ? 255 : r + (76 - gray)); + g = (g + (76 - gray) > 255 ? 255 : g + (76 - gray)); + b = (b + (76 - gray) > 255 ? 255 : b + (76 - gray)); + } + color.setRgb(r, g, b); + + QString sideName = config->readEntry("SideName", "kside.png"); + QString sideTileName = config->readEntry("SideTileName", "kside_tile.png"); + + image.load(locate("data", "kicker/pics/" + sideName)); + + if (image.isNull()) + { + return false; + } + + KIconEffect::colorize(image, color, 1.0); + m_sidePixmap.convertFromImage(image); + + image.load(locate("data", "kicker/pics/" + sideTileName)); + + if (image.isNull()) + { + return false; + } + + KIconEffect::colorize(image, color, 1.0); + m_sideTilePixmap.convertFromImage(image); + + if (m_sidePixmap.width() != m_sideTilePixmap.width()) + { + return false; + } + + // pretile the pixmap to a height of at least 100 pixels + if (m_sideTilePixmap.height() < 100) + { + int tiles = (int)(100 / m_sideTilePixmap.height()) + 1; + QPixmap preTiledPixmap(m_sideTilePixmap.width(), m_sideTilePixmap.height() * tiles); + QPainter p(&preTiledPixmap); + p.drawTiledPixmap(preTiledPixmap.rect(), m_sideTilePixmap); + m_sideTilePixmap = preTiledPixmap; + } + + return true; +} + +void TOM::paletteChanged() +{ + if (!loadSidePixmap()) + m_sidePixmap = m_sideTilePixmap = QPixmap(); +} + +void TOM::setMinimumSize(const QSize & s) +{ + KPanelMenu::setMinimumSize(s.width() + m_sidePixmap.width(), s.height()); +} + +void TOM::setMaximumSize(const QSize & s) +{ + KPanelMenu::setMaximumSize(s.width() + m_sidePixmap.width(), s.height()); +} + +void TOM::setMinimumSize(int w, int h) +{ + KPanelMenu::setMinimumSize(w + m_sidePixmap.width(), h); +} + +void TOM::setMaximumSize(int w, int h) +{ + KPanelMenu::setMaximumSize(w + m_sidePixmap.width(), h); +} + +QRect TOM::sideImageRect() +{ + return QStyle::visualRect( QRect( frameWidth(), frameWidth(), m_sidePixmap.width(), + height() - 2*frameWidth() ), this ); +} + +void TOM::resizeEvent(QResizeEvent * e) +{ + setFrameRect( QStyle::visualRect( QRect( m_sidePixmap.width(), 0, + width() - m_sidePixmap.width(), height() ), this ) ); +} + +void TOM::paintEvent(QPaintEvent * e) +{ + if (m_sidePixmap.isNull()) { + KPanelMenu::paintEvent(e); + return; + } + + QPainter p(this); + + style().drawPrimitive( QStyle::PE_PanelPopup, &p, + QRect( 0, 0, width(), height() ), + colorGroup(), QStyle::Style_Default, + QStyleOption( frameWidth(), 0 ) ); + + QRect r = sideImageRect(); + r.setBottom( r.bottom() - m_sidePixmap.height() ); + p.drawTiledPixmap( r, m_sideTilePixmap ); + + r = sideImageRect(); + r.setTop( r.bottom() - m_sidePixmap.height() ); + p.drawPixmap( r, m_sidePixmap ); + + drawContents( &p ); +} + +QMouseEvent TOM::translateMouseEvent( QMouseEvent* e ) +{ + QRect side = sideImageRect(); + + if ( !side.contains( e->pos() ) ) + return *e; + + QPoint newpos( e->pos() ); + QApplication::reverseLayout() ? + newpos.setX( newpos.x() - side.width() ) : + newpos.setX( newpos.x() + side.width() ); + QPoint newglobal( e->globalPos() ); + QApplication::reverseLayout() ? + newglobal.setX( newpos.x() - side.width() ) : + newglobal.setX( newpos.x() + side.width() ); + + return QMouseEvent( e->type(), newpos, newglobal, e->button(), e->state() ); +} + +void TOM::mousePressEvent(QMouseEvent * e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mousePressEvent( &newEvent ); +} + +void TOM::mouseReleaseEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mouseReleaseEvent( &newEvent ); +} + +void TOM::mouseMoveEvent(QMouseEvent *e) +{ + QMouseEvent newEvent = translateMouseEvent(e); + KPanelMenu::mouseMoveEvent( &newEvent ); +}*/ + +extern int kicker_screen_number; + +void TOM::runCommand() +{ + QByteArray data; + QCString appname( "kdesktop" ); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + + kapp->updateRemoteUserTimestamp( appname ); + kapp->dcopClient()->send( appname, "KDesktopIface", + "popupExecuteCommand()", data ); +} + +void TOM::runTask(int id) +{ + if (!m_tasks.contains(id)) return; + + kapp->propagateSessionManager(); + KApplication::startServiceByDesktopPath(m_tasks[id]->desktopEntryPath(), + QStringList(), 0, 0, 0, "", true); +} + +void TOM::clearRecentDocHistory() +{ + KRecentDocument::clear(); +} + +void TOM::openRecentDocument(int id) +{ + if (id >= 0) + { + kapp->propagateSessionManager(); + KURL u; + u.setPath(m_recentDocURLs[id]); + KDEDesktopMimeType::run(u, true); + } +} + +void TOM::logout() +{ + kapp->requestShutDown(); +} + +#include "tom.moc" diff --git a/kicker/menuext/tom/tom.desktop b/kicker/menuext/tom/tom.desktop new file mode 100644 index 000000000..f59a4beab --- /dev/null +++ b/kicker/menuext/tom/tom.desktop @@ -0,0 +1,75 @@ +[Desktop Entry] +Name=TOM +Name[bg]=Задачно меню +Name[eo]=PTMS +Name[hi]=टीओà¤à¤® +Name[te]=టామౠ+Name[zh_CN]=任务èœå• +Comment=A task oriented menu system +Comment[af]='n Taak geörienteerde kieslys stelsel +Comment[ar]=نظام قوائم وظيÙيّ المنØÙ‰ +Comment[be]=СіÑÑ‚Ñма меню, Ð°Ñ€Ñ‹ÐµÐ½Ñ‚Ð°Ð²Ð°Ð½Ð°Ñ Ð½Ð° выкананне шматлікіх задачаў +Comment[bg]=Меню, ориентирано към изпълнение на задачи +Comment[bn]=টাসà§à¦• ওরিয়েনà§à¦Ÿà§‡à¦¡ মেনৠসিসà§à¦Ÿà§‡à¦® +Comment[bs]=Sistem menija orjentisan na zadatke +Comment[ca]=Una tasca orientada al menú del sistema +Comment[cs]=ÚkolovÄ› orientovaný systém nabÃdek +Comment[csb]=Systema menu skòncentrowónô na dzejaniô +Comment[cy]=Cysawd dewislenni a gyfeirir at dasgau +Comment[da]=Et opgaveorienteret menusystem +Comment[de]=Aufgabenorientiertes Menüsystem +Comment[el]=Ένα σÏστημα Î¼ÎµÎ½Î¿Ï Ï€ÏοσανατολισμÎνο στην εÏγασία +Comment[eo]=Pertaska menusistemo +Comment[es]=Sistema de menú orientado a tareas +Comment[et]=Ãœlesandele orienteeritud menüüsüsteem +Comment[eu]=Atazetara zuzendutako menu sistema +Comment[fa]=یک سیستم گزینگان جهت‌دار تکلی٠+Comment[fi]=Tehtäväpohjainen valikkojärjestelmä +Comment[fr]=Un menu système par tâches +Comment[fy]=In taakoriïntearre menusysteem +Comment[ga]=Córas roghchláir dÃrithe ar thascanna +Comment[gl]=Un menu do sistema orientado a tarefas +Comment[he]=מערכת ×ª×¤×¨×™×˜×™× ×ž×•× ×—×ª משימות +Comment[hi]=कारà¥à¤¯ अनà¥à¤•à¥‚ल मेनà¥à¤¯à¥‚ तंतà¥à¤° +Comment[hr]=Sustav izbornika orijentiran zadacima +Comment[hu]=Feladatorientált menürendszer +Comment[is]=Verkefnabyggt valmyndakerfi +Comment[it]=Un sistema di menu organizzato per funzione +Comment[ja]=作æ¥ã‚¿ã‚¹ã‚¯ãƒ™ãƒ¼ã‚¹ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚·ã‚¹ãƒ†ãƒ +Comment[ka]=áƒáƒ›áƒáƒªáƒáƒœáƒáƒ–ე áƒáƒ იენტირებული მენიუს სისტემრ+Comment[kk]=ТапÑырмаларға арналған мәзір жүйеÑÑ– +Comment[km]=ប្រពáŸáž“្ធ​ម៉ឺនុយ​ដែល​សម្រប​ážáž¶áž˜â€‹áž—ារកិច្ច +Comment[lt]=Ä® užduotis orientuota meniu sistema +Comment[lv]=Uz darbÄ«bÄm orientÄ“ta izvÄ“lņu sistÄ“ma +Comment[mk]=СиÑтем од менија ориентиран кон задачи +Comment[mn]=ҮйлдÑлд чиглÑÑÑн цÑÑийн ÑиÑтем +Comment[ms]=Sistem menu berorientasikan tugas +Comment[mt]=Menu imqassam skond ix-xogħol li trid tagħmel +Comment[nb]=Et oppgaveorientert menysystem +Comment[nds]=Menüsysteem, dat an Opgaven utricht is +Comment[ne]=कारà¥à¤¯ उनà¥à¤®à¥à¤– मेनॠपà¥à¤°à¤£à¤¾à¤²à¥€ +Comment[nl]=Een taakgeörienteerd menusysteem +Comment[nn]=Eit oppgÃ¥veorientert menysystem +Comment[pa]=ਇੱਕ ਕੰਮ ਆਧਾਰਿਤ ਮੇਨੂ ਸਿਸਟਮ +Comment[pl]=System menu zorientowany na zadania +Comment[pt]=Um sistema de menus orientado por tarefas +Comment[pt_BR]=Um sistema de menu orientado a tarefa +Comment[ro]=Un meniu orientat pe probleme de rezolvat +Comment[ru]=СиÑтема меню, Ð¾Ñ€Ð¸ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð½Ð° задачи +Comment[rw]=Ibikubiyemo Sisitemu bijyanye n'Igikorwa +Comment[sk]=Systém menu podľa Äinnosti +Comment[sl]=Opravilno narejen menijski sistem +Comment[sr]=СиÑтем менија оријентиÑан према задацима +Comment[sr@Latn]=Sistem menija orijentisan prema zadacima +Comment[sv]=Uppgiftsrelaterat menysystem +Comment[ta]=பணி சாரà¯à®¨à¯à®¤ படà¯à®Ÿà®¿à®¯à®²à¯ அமைபà¯à®ªà¯ +Comment[th]=ระบบเมนูที่ใช้à¹à¸™à¸§à¸—างขà¸à¸‡à¸‡à¸²à¸™ +Comment[tr]=Görev yönelimli bir menü sistemi +Comment[tt]=Yökkä yünälgän saylaq sisteme +Comment[uk]=СиÑтема меню орієнтована на Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ +Comment[vi]=Hệ thá»±c Ä‘Æ¡n hÆ°á»›ng tác vụ +Comment[wa]=Ene dressêye sistinme fwaite po les bouyes +Comment[zh_CN]=é¢å‘任务的èœå•ç³»ç»Ÿ +Comment[zh_TW]=一個工作導å‘çš„é¸å–®ç³»çµ± +Icon=kmenu +X-KDE-Library=kickermenu_tom diff --git a/kicker/menuext/tom/tom.h b/kicker/menuext/tom/tom.h new file mode 100644 index 000000000..663cb05d6 --- /dev/null +++ b/kicker/menuext/tom/tom.h @@ -0,0 +1,110 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Aaron J. Seigo <aseigo@olympusproject.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __tom_h_ +#define __tom_h_ + +#include <qpixmap.h> + +#include <kpanelmenu.h> +#include <klibloader.h> + +class KPopupMenu; +class QPopupMenu; + +typedef QPtrList<QPopupMenu> PopupMenuList; +typedef QMap<int, KService::Ptr> TaskMap; + +class TOM : public KPanelMenu +{ + Q_OBJECT + + public: + TOM(QWidget *parent = 0, const char *name = 0); + ~TOM(); + + // for the side image + /*void setMinimumSize(const QSize &); + void setMaximumSize(const QSize &); + void setMinimumSize(int, int); + void setMaximumSize(int, int); */ + + protected slots: + void slotClear(); + void slotExec(int); + //void configChanged(); + void initialize(); + void contextualizeRMBmenu(KPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu); + //void paletteChanged(); + void clearRecentDocHistory(); + void runCommand(); + void runTask(int id); + void initializeRecentDocs(); + void openRecentDocument(int id); + void logout(); + + /* + * slots for the RMB menu on task group + */ + void removeTask(); + + protected: + void reload(); + + int appendTaskGroup(KConfig& config, bool inSubMenu = true ); + void initializeRecentApps(QPopupMenu* menu); + //int insertTOMTitle(QPopupMenu* menu, const QString &text, int id = -1, int index = -1); + + /* + * this stuff should be shared w/the kmenu + + QRect sideImageRect(); + QMouseEvent translateMouseEvent( QMouseEvent* e ); + void resizeEvent(QResizeEvent *); + void paintEvent(QPaintEvent *); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + bool loadSidePixmap(); + + QPixmap m_sidePixmap; + QPixmap m_sideTilePixmap;*/ + PopupMenuList m_submenus; + QFont m_largerFont; + int m_maxIndex; + bool m_isImmutable; + bool m_detailedTaskEntries; + bool m_detailedNamesFirst; + TaskMap m_tasks; + KPopupMenu* m_recentDocsMenu; + QStringList m_recentDocURLs; +}; + +class TOMFactory : public KLibFactory +{ + public: + TOMFactory(QObject *parent = 0, const char *name = 0); + + protected: + QObject* createObject(QObject *parent = 0, const char *name = 0, + const char *classname = "QObject", + const QStringList& args = QStringList()); +}; + + +#endif diff --git a/kicker/proxy/Makefile.am b/kicker/proxy/Makefile.am new file mode 100644 index 000000000..b63535490 --- /dev/null +++ b/kicker/proxy/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I$(srcdir)/../libkicker $(all_includes) + +bin_PROGRAMS = +noinst_PROGRAMS = extensiondebugger +lib_LTLIBRARIES = +kdeinit_LTLIBRARIES = appletproxy.la extensionproxy.la + +METASOURCES = AUTO + +appletproxy_la_LIBADD = $(LIB_KDEUI) ../libkicker/libkickermain.la +appletproxy_la_SOURCES = appletproxy.cpp +appletproxy_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version + +extensionproxy_la_LIBADD = $(LIB_KDEUI) ../libkicker/libkickermain.la +extensionproxy_la_SOURCES = extensionproxy.cpp +extensionproxy_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version + +extensiondebugger_SOURCES = extensiondebugger.cpp +extensiondebugger_LDADD = ../libkicker/libkickermain.la +extensiondebugger_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +messages: + $(XGETTEXT) appletproxy.cpp -o $(podir)/appletproxy.pot + $(XGETTEXT) extensionproxy.cpp -o $(podir)/extensionproxy.pot diff --git a/kicker/proxy/appletproxy.cpp b/kicker/proxy/appletproxy.cpp new file mode 100644 index 000000000..d9ac588d5 --- /dev/null +++ b/kicker/proxy/appletproxy.cpp @@ -0,0 +1,516 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTDHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> + +#include <qstring.h> +#include <qfile.h> +#include <qobjectlist.h> +#include <qxembed.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klibloader.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kpanelapplet.h> +#include <kaboutdata.h> +#include <qfileinfo.h> +#include <dcopclient.h> +#include <kwin.h> + +#include "appletinfo.h" + +#include "appletproxy.h" +#include "appletproxy.moc" + +#include <X11/Xlib.h> + +KPanelApplet::Position directionToPosition( int d ) +{ + switch( d ) { + case 1: return KPanelApplet::pTop; + case 2: return KPanelApplet::pRight; + case 3: return KPanelApplet::pLeft; + default: + case 0: return KPanelApplet::pBottom; + } +} + +static KCmdLineOptions options[] = +{ + { "+desktopfile", I18N_NOOP("The applet's desktop file"), 0 }, + { "configfile <file>", I18N_NOOP("The config file to be used"), 0 }, + { "callbackid <id>", I18N_NOOP("DCOP callback id of the applet container"), 0 }, + KCmdLineLastOption +}; + +extern "C" KDE_EXPORT int kdemain( int argc, char ** argv ) +{ + KAboutData aboutData( "kicker", I18N_NOOP("Panel applet proxy.") + , "v0.1.0" + ,I18N_NOOP("Panel applet proxy.") + , KAboutData::License_BSD + , "(c) 2000, The KDE Developers"); + KCmdLineArgs::init(argc, argv, &aboutData ); + aboutData.addAuthor("Matthias Elter",0, "elter@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + KApplication::addCmdLineOptions(); + KCmdLineArgs::addCmdLineOptions(options); // Add our own options. + + KApplication a; + a.disableSessionManagement(); + + KGlobal::dirs()->addResourceType("applets", KStandardDirs::kde_default("data") + + "kicker/applets"); + + // setup proxy object + AppletProxy proxy(0, "appletproxywidget"); + + // parse cmdline args + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->count() == 0 ) + KCmdLineArgs::usage(i18n("No desktop file specified") ); + + // Perhaps we should use a konsole-like solution here (shell, list of args...) + QString desktopfile( args->arg(0) ); + + // load applet DSO + if ( !QFile::exists( desktopfile ) && + !desktopfile.endsWith( ".desktop" ) ) + desktopfile.append( ".desktop" ); + + if ( !QFile::exists( desktopfile ) ) + desktopfile = locate( "applets", desktopfile ).latin1(); + + proxy.loadApplet( desktopfile, args->getOption("configfile")); + + // dock into our applet container + QCString callbackid = args->getOption( "callbackid"); + if ( callbackid.isEmpty() ) + proxy.showStandalone(); + else + proxy.dock(args->getOption("callbackid")); + + return a.exec(); +} + +AppletProxy::AppletProxy(QObject* parent, const char* name) + : QObject(parent, name) + , DCOPObject("AppletProxy") + , _info(0) + , _applet(0) +{ + // try to attach to DCOP server + if (!kapp->dcopClient()->attach()) { + kdError() << "Failed to attach to DCOP server." << endl; + KMessageBox::error(0, + i18n("The applet proxy could not be started due to DCOP communication problems."), + i18n("Applet Loading Error")); + exit(0); + } + + if (!kapp->dcopClient()->registerAs("applet_proxy", true)) { + kdError() << "Failed to register at DCOP server." << endl; + KMessageBox::error(0, + i18n("The applet proxy could not be started due to DCOP registration problems."), + i18n("Applet Loading Error")); + exit(0); + } + + _bg = QPixmap(); +} + +AppletProxy::~AppletProxy() +{ + kapp->dcopClient()->detach(); + delete _info; + delete _applet; +} + +void AppletProxy::loadApplet(const QString& desktopFile, const QString& configFile) +{ + QString df; + + // try simple path first + QFileInfo finfo( desktopFile ); + if ( finfo.exists() ) { + df = finfo.absFilePath(); + } else { + // locate desktop file + df = KGlobal::dirs()->findResource("applets", desktopFile); + } + + QFile file(df); + // does the config file exist? + if (df.isNull() || !file.exists()) { + kdError() << "Failed to locate applet desktop file: " << desktopFile << endl; + KMessageBox::error(0, + i18n("The applet proxy could not load the applet information from %1.").arg(desktopFile), + i18n("Applet Loading Error")); + exit(0); + } + + // create AppletInfo instance + delete _info; + _info = new AppletInfo(df); + + // set the config file + if (!configFile.isNull()) + _info->setConfigFile(configFile); + + // load applet DSO + _applet = loadApplet(*_info); + + // sanity check + if (!_applet) + { + kdError() << "Failed to load applet: " << _info->library() << endl; + KMessageBox::error(0, + i18n("The applet %1 could not be loaded via the applet proxy.").arg(_info->name()), + i18n("Applet Loading Error")); + exit(0); + } + + // connect updateLayout signal + connect(_applet, SIGNAL(updateLayout()), SLOT(slotUpdateLayout())); + // connect requestFocus signal + connect(_applet, SIGNAL(requestFocus()), SLOT(slotRequestFocus())); +} + +KPanelApplet* AppletProxy::loadApplet(const AppletInfo& info) +{ + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->library(QFile::encodeName(info.library())); + + if (!lib) + { + kdWarning() << "cannot open applet: " << info.library() + << " because of " << loader->lastErrorMessage() << endl; + return 0; + } + + KPanelApplet* (*init_ptr)(QWidget *, const QString&); + init_ptr = (KPanelApplet* (*)(QWidget *, const QString&))lib->symbol( "init" ); + + if (!init_ptr) + { + kdWarning() << info.library() << " is not a kicker plugin!" << endl; + return 0; + } + + return init_ptr(0, info.configFile()); +} + +void AppletProxy::repaintApplet(QWidget* widget) +{ + widget->repaint(); + + const QObjectList* children = widget->children(); + + if (!children) + { + return; + } + + QObjectList::iterator it = children->begin(); + for (; it != children->end(); ++it) + { + QWidget *w = dynamic_cast<QWidget*>(*it); + if (w) + { + repaintApplet(w); + } + } +} + +void AppletProxy::dock(const QCString& callbackID) +{ + kdDebug(1210) << "Callback ID: " << callbackID << endl; + + _callbackID = callbackID; + + // try to attach to DCOP server + DCOPClient* dcop = kapp->dcopClient(); + + dcop->setNotifications(true); + connect(dcop, SIGNAL(applicationRemoved(const QCString&)), + SLOT(slotApplicationRemoved(const QCString&))); + + WId win; + + // get docked + { + QCString replyType; + QByteArray data, replyData; + QDataStream dataStream( data, IO_WriteOnly ); + + int actions = 0; + if (_applet) actions = _applet->actions(); + dataStream << actions; + + int type = 0; + if (_applet) type = static_cast<int>(_applet->type()); + dataStream << type; + + // we use "call" to know whether it was sucessful + + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + if ( !dcop->call(appname, _callbackID, "dockRequest(int,int)", + data, replyType, replyData ) ) + { + kdError() << "Failed to dock into the panel." << endl; + KMessageBox::error(0, + i18n("The applet proxy could not dock into the panel due to DCOP communication problems."), + i18n("Applet Loading Error")); + exit(0); + } + + QDataStream reply( replyData, IO_ReadOnly ); + reply >> win; + + // request background + dcop->send(appname, _callbackID, "getBackground()", data); + } + + if (win) + { + if (_applet) + { + _applet->hide(); + } + QXEmbed::initialize(); + QXEmbed::embedClientIntoWindow(_applet, win); + } + else + { + kdError() << "Failed to dock into the panel." << endl; + KMessageBox::error(0, + i18n("The applet proxy could not dock into the panel."), + i18n("Applet Loading Error")); + delete _applet; + _applet = 0; + + exit(0); + } + +} + +bool AppletProxy::process(const QCString &fun, const QByteArray &data, + QCString& replyType, QByteArray &replyData) +{ + if ( fun == "widthForHeight(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int height; + dataStream >> height; + QDataStream reply( replyData, IO_WriteOnly ); + replyType = "int"; + + if (!_applet) + reply << height; + else + reply << _applet->widthForHeight(height); + + return true; + } + else if ( fun == "heightForWidth(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int width; + dataStream >> width; + QDataStream reply( replyData, IO_WriteOnly ); + replyType = "int"; + + if(!_applet) + reply << width; + else + reply << _applet->heightForWidth(width); + + return true; + } + else if ( fun == "setDirection(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int dir; + dataStream >> dir; + + if(_applet) { + _applet->setPosition(directionToPosition(dir)); + } + return true; + } + else if ( fun == "setAlignment(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int alignment; + dataStream >> alignment; + + if(_applet) { + _applet->setAlignment( (KPanelApplet::Alignment)alignment ); + } + return true; + } + else if ( fun == "removedFromPanel()" ) + { + delete _applet; + _applet = 0; + exit(0); + return true; + } + else if ( fun == "about()" ) + { + if(_applet) _applet->action( KPanelApplet::About ); + return true; + } + else if ( fun == "help()" ) + { + if(_applet) _applet->action( KPanelApplet::Help ); + return true; + } + else if ( fun == "preferences()" ) + { + if(_applet) _applet->action( KPanelApplet::Preferences ); + return true; + } + else if (fun == "reportBug()" ) + { + if(_applet) _applet->action( KPanelApplet::ReportBug ); + return true; + } + else if ( fun == "actions()" ) + { + QDataStream reply( replyData, IO_WriteOnly ); + int actions = 0; + if(_applet) actions = _applet->actions(); + reply << actions; + replyType = "int"; + return true; + } + else if ( fun == "type()" ) + { + QDataStream reply( replyData, IO_WriteOnly ); + int type = 0; + if (_applet) type = static_cast<int>(_applet->type()); + reply << type; + replyType = "int"; + return true; + } + else if ( fun == "setBackground(QPixmap)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + dataStream >> _bg; + if(_applet) + if ( _bg.isNull() ) { // no transparency + _applet->unsetPalette(); + _applet->repaint(); + } + else { //transparency + _applet->blockSignals(true); + _applet->setBackgroundMode(Qt::FixedPixmap); + _applet->setPaletteBackgroundPixmap(_bg); + repaintApplet(_applet); + _applet->blockSignals(false); + } + return true; + } + return false; +} + +void AppletProxy::slotUpdateLayout() +{ + if(_callbackID.isNull()) return; + + QByteArray data; + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + kapp->dcopClient()->send(appname, _callbackID, "updateLayout()", data); +} + +void AppletProxy::slotRequestFocus() +{ + if(_callbackID.isNull()) return; + + QByteArray data; + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + kapp->dcopClient()->send(appname, _callbackID, "requestFocus()", data); +} + +void AppletProxy::slotApplicationRemoved(const QCString& appId) +{ + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + if(appId == appname) { + kdDebug(1210) << "Connection to kicker lost, shutting down" << endl; + kapp->quit(); + } +} + +void AppletProxy::showStandalone() +{ + if (!_applet) + { + return; + } + + _applet->resize( _applet->widthForHeight( 48 ), 48 ); + _applet->setMinimumSize( _applet->size() ); + _applet->setCaption( _info->name() ); + kapp->setMainWidget( _applet ); + _applet->show(); +} + diff --git a/kicker/proxy/appletproxy.h b/kicker/proxy/appletproxy.h new file mode 100644 index 000000000..182280193 --- /dev/null +++ b/kicker/proxy/appletproxy.h @@ -0,0 +1,67 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __appletproxy_h__ +#define __appletproxy_h__ + +#include <qcstring.h> +#include <qobject.h> + +#include <dcopobject.h> + +#include "appletinfo.h" + +class KPanelApplet; +class KickerPluginManager; + +class AppletProxy : public QObject, DCOPObject +{ + Q_OBJECT + +public: + AppletProxy(QObject* parent, const char* name = 0); + ~AppletProxy(); + + void loadApplet(const QString& desktopFile, const QString& configFile); + KPanelApplet* loadApplet(const AppletInfo& info); + void dock(const QCString& callbackID); + void showStandalone(); + + bool process(const QCString &fun, const QByteArray &data, + QCString& replyType, QByteArray &replyData); + +protected slots: + void slotUpdateLayout(); + void slotRequestFocus(); + void slotApplicationRemoved(const QCString&); + +private: + void repaintApplet(QWidget* widget); + + AppletInfo *_info; + KPanelApplet *_applet; + QCString _callbackID; + QPixmap _bg; +}; + +#endif diff --git a/kicker/proxy/extensiondebugger.cpp b/kicker/proxy/extensiondebugger.cpp new file mode 100644 index 000000000..f7c3309c4 --- /dev/null +++ b/kicker/proxy/extensiondebugger.cpp @@ -0,0 +1,160 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTDHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qfile.h> +#include <qlayout.h> +#include <qpushbutton.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klibloader.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kpanelextension.h> +#include <kaboutdata.h> +#include <qfileinfo.h> + +#include "appletinfo.h" +#include "extensiondebugger.h" +#include "extensiondebugger.moc" + + + +static KCmdLineOptions options[] = +{ + { "+desktopfile", I18N_NOOP("The extensions desktop file"), 0 }, + KCmdLineLastOption +}; + +KPanelExtension* loadExtension(const AppletInfo& info) +{ + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->library(QFile::encodeName(info.library())); + + if (!lib) + { + kdWarning() << "cannot open extension: " << info.library() + << " because of " << loader->lastErrorMessage() << endl; + return 0; + } + + KPanelExtension* (*init_ptr)(QWidget *, const QString&); + init_ptr = (KPanelExtension* (*)(QWidget *, const QString&))lib->symbol( "init" ); + + if (!init_ptr) + { + kdWarning() << info.library() << " is not a kicker extension!" << endl; + return 0; + } + + return init_ptr(0, info.configFile()); +} + +int main( int argc, char ** argv ) +{ + KAboutData aboutData( "extensionproxy", I18N_NOOP("Panel extension proxy.") + , "v0.1.0" + ,I18N_NOOP("Panel extension proxy.") + , KAboutData::License_BSD + , "(c) 2000, The KDE Developers"); + KCmdLineArgs::init(argc, argv, &aboutData ); + aboutData.addAuthor("Matthias Elter",0, "elter@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + KApplication::addCmdLineOptions(); + KCmdLineArgs::addCmdLineOptions(options); // Add our own options. + + KApplication a; + a.disableSessionManagement(); + + KGlobal::dirs()->addResourceType("extensions", KStandardDirs::kde_default("data") + + "kicker/extensions"); + + QString df; + + // parse cmdline args + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + // sanity check + if ( args->count() == 0 ) + KCmdLineArgs::usage(i18n("No desktop file specified") ); + + + QCString desktopFile = QCString( args->arg(0) ); + + // try simple path first + QFileInfo finfo( desktopFile ); + if ( finfo.exists() ) { + df = finfo.absFilePath(); + } else { + // locate desktop file + df = KGlobal::dirs()->findResource("extensions", QString(desktopFile)); + } + + // does the config file exist? + if (!QFile::exists(df)) { + kdError() << "Failed to locate extension desktop file: " << desktopFile << endl; + return 1; + } + + AppletInfo info( df ); + + KPanelExtension *extension = loadExtension(info); + if ( !extension ) { + kdError() << "Failed to load extension: " << info.library() << endl; + return 1; + } + + ExtensionContainer *container = new ExtensionContainer( extension ); + container->show(); + + QObject::connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + + int result = a.exec(); + + delete extension; + return result; +} + +ExtensionContainer::ExtensionContainer( KPanelExtension *extension, QWidget *parent, const char *name ) + : QWidget( parent, name ), m_extension( extension ) +{ + ( new QVBoxLayout( this ) )->setAutoAdd( true ); + + QPushButton *configButton = new QPushButton( i18n( "Configure..." ), this ); + connect( configButton, SIGNAL( clicked() ), + this, SLOT( showPreferences() ) ); + + m_extension->reparent( this, QPoint( 0, 0 ) ); +} + +void ExtensionContainer::resizeEvent( QResizeEvent * ) +{ + m_extension->setGeometry( 0, 0, width(), height() ); +} + +void ExtensionContainer::showPreferences() +{ + m_extension->action( KPanelExtension::Preferences ); +} diff --git a/kicker/proxy/extensiondebugger.h b/kicker/proxy/extensiondebugger.h new file mode 100644 index 000000000..36745ae90 --- /dev/null +++ b/kicker/proxy/extensiondebugger.h @@ -0,0 +1,47 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __extensiondebugger_h__ +#define __extensiondebugger_h__ + +class AppletInfo; +class KPanelExtension; + +class ExtensionContainer : public QWidget +{ + Q_OBJECT + +public: + ExtensionContainer(KPanelExtension *extension, QWidget* parent = 0, const char* name = 0); + +protected: + void resizeEvent( QResizeEvent *ev ); + +private slots: + void showPreferences(); + +private: + KPanelExtension *m_extension; +}; + +#endif diff --git a/kicker/proxy/extensionproxy.cpp b/kicker/proxy/extensionproxy.cpp new file mode 100644 index 000000000..0fbb341e5 --- /dev/null +++ b/kicker/proxy/extensionproxy.cpp @@ -0,0 +1,401 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTDHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> + +#include <qstring.h> +#include <qfile.h> +#include <qxembed.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klibloader.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kpanelextension.h> +#include <kaboutdata.h> +#include <qfileinfo.h> +#include <dcopclient.h> + +#include "appletinfo.h" +#include "extensionproxy.h" +#include "extensionproxy.moc" + +#include <X11/Xlib.h> + + +static KCmdLineOptions options[] = +{ + { "+desktopfile", I18N_NOOP("The extension's desktop file"), 0 }, + { "configfile <file>", I18N_NOOP("The config file to be used"), 0 }, + { "callbackid <id>", I18N_NOOP("DCOP callback id of the extension container"), 0 }, + KCmdLineLastOption +}; + +extern "C" KDE_EXPORT int kdemain( int argc, char ** argv ) +{ + KAboutData aboutData( "extensionproxy", I18N_NOOP("Panel Extension Proxy") + , "v0.1.0" + ,I18N_NOOP("Panel extension proxy") + , KAboutData::License_BSD + , "(c) 2000, The KDE Developers"); + KCmdLineArgs::init(argc, argv, &aboutData ); + aboutData.addAuthor("Matthias Elter",0, "elter@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + KApplication::addCmdLineOptions(); + KCmdLineArgs::addCmdLineOptions(options); // Add our own options. + + KApplication a; + a.disableSessionManagement(); + + KGlobal::dirs()->addResourceType("extensions", KStandardDirs::kde_default("data") + + "kicker/extensions"); + + // setup proxy object + ExtensionProxy proxy(0, "extensionproxywidget"); + + // parse cmdline args + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + // sanity check + if ( args->count() == 0 ) + KCmdLineArgs::usage(i18n("No desktop file specified") ); + + // do we have a callback id? + if (args->getOption("callbackid").isNull()) { + kdError() << "Callback ID is null. " << endl; + exit(0); + } + + // Perhaps we should use a konsole-like solution here (shell, list of args...) + QCString desktopfile = QCString( args->arg(0) ); + + // load extension DSO + proxy.loadExtension( desktopfile, args->getOption("configfile")); + + // dock into our extension container + proxy.dock(args->getOption("callbackid")); + + return a.exec(); +} + +ExtensionProxy::ExtensionProxy(QObject* parent, const char* name) + : QObject(parent, name) + , DCOPObject("ExtensionProxy") + , _info(0) + , _extension(0) +{ + // try to attach to DCOP server + if (!kapp->dcopClient()->attach()) { + kdError() << "Failed to attach to DCOP server." << endl; + exit(0); + } + + if (!kapp->dcopClient()->registerAs("extension_proxy", true)) { + kdError() << "Failed to register at DCOP server." << endl; + exit(0); + } +} + +ExtensionProxy::~ExtensionProxy() +{ + kapp->dcopClient()->detach(); +} + +void ExtensionProxy::loadExtension(const QCString& desktopFile, const QCString& configFile) +{ + QString df; + + // try simple path first + QFileInfo finfo( desktopFile ); + if ( finfo.exists() ) { + df = finfo.absFilePath(); + } else { + // locate desktop file + df = KGlobal::dirs()->findResource("extensions", QString(desktopFile)); + } + + QFile file(df); + // does the config file exist? + if (df.isNull() || !file.exists()) { + kdError() << "Failed to locate extension desktop file: " << desktopFile << endl; + exit(0); + } + + // create AppletInfo instance + _info = new AppletInfo(df); + + // set the config file + if (!configFile.isNull()) + _info->setConfigFile(configFile); + + // load extension DSO + _extension = loadExtension(*_info); + + // sanity check + if (!_extension) { + kdError() << "Failed to load extension: " << _info->library() << endl; + exit(0); + } + + // connect updateLayout signal + connect(_extension, SIGNAL(updateLayout()), SLOT(slotUpdateLayout())); +} + +KPanelExtension* ExtensionProxy::loadExtension(const AppletInfo& info) +{ + KLibLoader* loader = KLibLoader::self(); + KLibrary* lib = loader->library(QFile::encodeName(info.library())); + + if (!lib) + { + kdWarning() << "cannot open extension: " << info.library() + << " because of " << loader->lastErrorMessage() << endl; + return 0; + } + + KPanelExtension* (*init_ptr)(QWidget *, const QString&); + init_ptr = (KPanelExtension* (*)(QWidget *, const QString&))lib->symbol( "init" ); + + if (!init_ptr) + { + kdWarning() << info.library() << " is not a kicker extension!" << endl; + return 0; + } + + return init_ptr(0, info.configFile()); +} + +void ExtensionProxy::dock(const QCString& callbackID) +{ + kdDebug(1210) << "Callback ID: " << callbackID << endl; + + _callbackID = callbackID; + + // try to attach to DCOP server + DCOPClient* dcop = kapp->dcopClient(); + + dcop->setNotifications(true); + connect(dcop, SIGNAL(applicationRemoved(const QCString&)), + SLOT(slotApplicationRemoved(const QCString&))); + + WId win; + + // get docked + { + QCString replyType; + QByteArray data, replyData; + QDataStream dataStream( data, IO_WriteOnly ); + + int actions = 0; + if(_extension) actions = _extension->actions(); + dataStream << actions; + + int type = 0; + if (_extension) type = static_cast<int>(_extension->type()); + dataStream << type; + + // we use "call" to know whether it was sucessful + + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + if ( !dcop->call(appname, _callbackID, "dockRequest(int,int)", + data, replyType, replyData ) ) + { + kdError() << "Failed to dock into the panel." << endl; + exit(0); + } + + QDataStream reply( replyData, IO_ReadOnly ); + reply >> win; + + } + + if (win) { + if (_extension) + { + _extension->hide(); + } + QXEmbed::initialize(); + QXEmbed::embedClientIntoWindow( _extension, win ); + } + else { + kdError() << "Failed to dock into the panel." << endl; + if(_extension) delete _extension; + exit(0); + } +} + +bool ExtensionProxy::process(const QCString &fun, const QByteArray &data, + QCString& replyType, QByteArray &replyData) +{ + if ( fun == "sizeHint(int,QSize)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int pos; + QSize maxSize; + dataStream >> pos; + dataStream >> maxSize; + + QDataStream reply( replyData, IO_WriteOnly ); + replyType = "QSize"; + + if(!_extension) + reply << maxSize; + else + reply << _extension->sizeHint((KPanelExtension::Position)pos, maxSize); + + return true; + } + else if ( fun == "setPosition(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int pos; + dataStream >> pos; + + if(_extension) { + _extension->setPosition( (KPanelExtension::Position)pos ); + } + return true; + } + else if ( fun == "setAlignment(int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int alignment; + dataStream >> alignment; + + if(_extension) { + _extension->setAlignment( (KPanelExtension::Alignment)alignment ); + } + return true; + } + else if ( fun == "setSize(int,int)" ) + { + QDataStream dataStream( data, IO_ReadOnly ); + int serializedSize; + int custom; + dataStream >> serializedSize; + dataStream >> custom; + + if (_extension) + _extension->setSize(KPanelExtension::Size(serializedSize), custom); + return true; + } + else if ( fun == "removedFromPanel()" ) + { + if(_extension) delete _extension; + exit(0); + return true; + } + else if ( fun == "about()" ) + { + if(_extension) _extension->action( KPanelExtension::About ); + return true; + } + else if ( fun == "help()" ) + { + if(_extension) _extension->action( KPanelExtension::Help ); + return true; + } + else if ( fun == "preferences()" ) + { + if(_extension) _extension->action( KPanelExtension::Preferences ); + return true; + } + else if ( fun == "reportBug()" ) + { + if(_extension) _extension->action( KPanelExtension::ReportBug ); + return true; + } + else if ( fun == "actions()" ) + { + QDataStream reply( replyData, IO_WriteOnly ); + int actions = 0; + if(_extension) actions = _extension->actions(); + reply << actions; + replyType = "int"; + return true; + } + else if ( fun == "preferedPosition()" ) + { + QDataStream reply( replyData, IO_WriteOnly ); + int pos = static_cast<int>(KPanelExtension::Bottom); + if(_extension) pos = static_cast<int>(_extension->preferedPosition()); + reply << pos; + replyType = "int"; + return true; + } + else if ( fun == "type()" ) + { + QDataStream reply( replyData, IO_WriteOnly ); + int type = 0; + if (_extension) type = static_cast<int>(_extension->type()); + reply << type; + replyType = "int"; + return true; + } + return false; +} + +void ExtensionProxy::slotUpdateLayout() +{ + if(_callbackID.isNull()) return; + + QByteArray data; + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + kapp->dcopClient()->send(appname, _callbackID, "updateLayout()", data); +} + +void ExtensionProxy::slotApplicationRemoved(const QCString& appId) +{ + int screen_number = 0; + if (qt_xdisplay()) + screen_number = DefaultScreen(qt_xdisplay()); + QCString appname; + if (screen_number == 0) + appname = "kicker"; + else + appname.sprintf("kicker-screen-%d", screen_number); + + if(appId == appname) { + kdDebug(1210) << "Connection to kicker lost, shutting down" << endl; + kapp->quit(); + } +} diff --git a/kicker/proxy/extensionproxy.h b/kicker/proxy/extensionproxy.h new file mode 100644 index 000000000..e5b8ca96d --- /dev/null +++ b/kicker/proxy/extensionproxy.h @@ -0,0 +1,61 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __extensionproxy_h__ +#define __extensionproxy_h__ + +#include <qcstring.h> +#include <qobject.h> + +#include <dcopobject.h> + +#include "appletinfo.h" + +class KPanelExtension; + +class ExtensionProxy : public QObject, DCOPObject +{ + Q_OBJECT + +public: + ExtensionProxy(QObject* parent, const char* name = 0); + ~ExtensionProxy(); + + void loadExtension(const QCString& desktopFile, const QCString& configFile); + KPanelExtension* loadExtension(const AppletInfo& info); + void dock(const QCString& callbackID); + + bool process(const QCString &fun, const QByteArray &data, + QCString& replyType, QByteArray &replyData); + +protected slots: + void slotUpdateLayout(); + void slotApplicationRemoved(const QCString&); + +private: + AppletInfo *_info; + KPanelExtension *_extension; + QCString _callbackID; +}; + +#endif diff --git a/kicker/rich-ideas.txt b/kicker/rich-ideas.txt new file mode 100644 index 000000000..afe55f33a --- /dev/null +++ b/kicker/rich-ideas.txt @@ -0,0 +1,62 @@ + +Positioning of extensions +========================= + +How about using the alignment flags (or similar) for position, and the +direction flags for how to fill? + + + --------------- + |a b c| + | | + | | + | | + |e d| + --------------- + +a = Left | Top +b = Middle | Top +c = Right | Top +d = Right | Bottom + +Now here's the filling + +12345 LeftToRight +54321 RightToLeft (eg. for a right aligned thing) +5 +4 +3 BottomToTop +2 +1 + + +etc. etc. + +Essentially, this splits the concept of positioning and layout. Now, lets get +crazy: + +Imagine we're in position a and want to have a triangular corner layout: + +1247 +35 +6 + +So, maybe we need some sort of concept of (one of): + 1) multiple linked rectangular blocks + 2) extensions/bars with a mask + 3) each item being considered independently (maybe some sort of magnetic + blocks so they can be draggable?) + +Finally, let's get really insane: + +positions a AND c + +12 65 +34 7 + +This perhaps indicates that the details of placement should be passed off to +the extensions, but also that extensions might be 'linked'. eg. removing the +extension in position a should also remove c (and the configurations are also +linked). + + diff --git a/kicker/taskbar/Makefile.am b/kicker/taskbar/Makefile.am new file mode 100644 index 000000000..01b3af162 --- /dev/null +++ b/kicker/taskbar/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(srcdir)/../taskmanager -I$(srcdir)/../libkicker -I$(top_builddir)/kicker/libkicker $(all_includes) + +# KDE 4: rename to libkickertaskbar.la! + +lib_LTLIBRARIES = libtaskbar.la +libtaskbar_la_SOURCES = taskbarsettings.kcfgc taskcontainer.cpp taskbar.cpp \ + taskbarcontainer.cpp taskbarcontainer.skel + +libtaskbar_la_METASOURCES = AUTO + +libtaskbar_la_LDFLAGS = -version-info 3:0:2 $(all_libraries) -no-undefined +libtaskbar_la_LIBADD = $(LIB_KDEUI) $(LIB_KUTILS) ../libkicker/libkickermain.la ../taskmanager/libtaskmanager.la + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/libtaskbar.pot + +taskbar.lo: ../libkicker/kickerSettings.h +taskbarcontainer.lo: ../libkicker/kickerSettings.h + +kde_kcfg_DATA = taskbar.kcfg diff --git a/kicker/taskbar/taskbar.cpp b/kicker/taskbar/taskbar.cpp new file mode 100644 index 000000000..8c5bb73c1 --- /dev/null +++ b/kicker/taskbar/taskbar.cpp @@ -0,0 +1,1231 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2004 Sebastian Wolff +Copyright (c) 2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <math.h> + +#include <qapplication.h> +#include <qbitmap.h> +#include <qdesktopwidget.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qstringlist.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalaccel.h> +#include <kimageeffect.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include "kickerSettings.h" +#include "taskbarsettings.h" +#include "taskcontainer.h" +#include "taskmanager.h" + +#include "taskbar.h" +#include "taskbar.moc" + + +TaskBar::TaskBar( QWidget *parent, const char *name ) + : Panner( parent, name ), + m_showAllWindows(false), + m_currentScreen(-1), + m_showOnlyCurrentScreen(false), + m_sortByDesktop(false), + m_showIcon(false), + m_showOnlyIconified(false), + m_textShadowEngine(0), + m_ignoreUpdates(false) +{ + arrowType = LeftArrow; + blocklayout = true; + + // init + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + + // setup animation frames + for (int i = 1; i < 11; i++) + { + frames.append(new QPixmap(locate("data", "kicker/pics/disk" + QString::number(i) + ".png"))); + } + + // configure + configure(); + + connect(&m_relayoutTimer, SIGNAL(timeout()), + this, SLOT(reLayout())); + + connect(this, SIGNAL(contentsMoving(int, int)), SLOT(setBackground())); + + // connect manager + connect(TaskManager::the(), SIGNAL(taskAdded(Task::Ptr)), + this, SLOT(add(Task::Ptr))); + connect(TaskManager::the(), SIGNAL(taskRemoved(Task::Ptr)), + this, SLOT(remove(Task::Ptr))); + connect(TaskManager::the(), SIGNAL(startupAdded(Startup::Ptr)), + this, SLOT(add(Startup::Ptr))); + connect(TaskManager::the(), SIGNAL(startupRemoved(Startup::Ptr)), + this, SLOT(remove(Startup::Ptr))); + connect(TaskManager::the(), SIGNAL(desktopChanged(int)), + this, SLOT(desktopChanged(int))); + connect(TaskManager::the(), SIGNAL(windowChanged(Task::Ptr)), + this, SLOT(windowChanged(Task::Ptr))); + + isGrouping = shouldGroup(); + + // register existant tasks + Task::Dict tasks = TaskManager::the()->tasks(); + Task::Dict::iterator taskEnd = tasks.end(); + for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it) + { + add(it.data()); + } + + // register existant startups + Startup::List startups = TaskManager::the()->startups(); + Startup::List::iterator startupEnd = startups.end(); + for (Startup::List::iterator sIt = startups.begin(); sIt != startupEnd; ++sIt) + { + add((*sIt)); + } + + blocklayout = false; + + connect(kapp, SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int))); + keys = new KGlobalAccel( this ); +#include "taskbarbindings.cpp" + keys->readSettings(); + keys->updateConnections(); + + reLayout(); +} + +TaskBar::~TaskBar() +{ + for (TaskContainer::Iterator it = m_hiddenContainers.begin(); + it != m_hiddenContainers.end(); + ++it) + { + (*it)->deleteLater(); + } + + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + (*it)->deleteLater(); + } + + for (PixmapList::const_iterator it = frames.constBegin(); + it != frames.constEnd(); + ++it) + { + delete *it; + } + + delete m_textShadowEngine; +} + +KTextShadowEngine *TaskBar::textShadowEngine() +{ + if (!m_textShadowEngine) + m_textShadowEngine = new KTextShadowEngine(); + + return m_textShadowEngine; +} + + +QSize TaskBar::sizeHint() const +{ + // get our minimum height based on the minimum button height or the + // height of the font in use, which is largest + QFontMetrics fm(KGlobalSettings::taskbarFont()); + int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ? + fm.height() : TaskBarSettings::minimumButtonHeight(); + + return QSize(BUTTON_MIN_WIDTH, minButtonHeight); +} + +QSize TaskBar::sizeHint( KPanelExtension::Position p, QSize maxSize) const +{ + // get our minimum height based on the minimum button height or the + // height of the font in use, which is largest + QFontMetrics fm(KGlobalSettings::taskbarFont()); + int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ? + fm.height() : TaskBarSettings::minimumButtonHeight(); + + if ( p == KPanelExtension::Left || p == KPanelExtension::Right ) + { + int actualMax = minButtonHeight * containerCount(); + + if (containerCount() == 0) + { + actualMax = minButtonHeight; + } + + if (actualMax > maxSize.height()) + { + return maxSize; + } + return QSize( maxSize.width(), actualMax ); + } + else + { + int rows = KickerSettings::conserveSpace() ? + contentsRect().height() / minButtonHeight : + 1; + if ( rows < 1 ) + { + rows = 1; + } + + int maxWidth = TaskBarSettings::maximumButtonWidth(); + if (maxWidth == 0) + { + maxWidth = BUTTON_MAX_WIDTH; + } + + int actualMax = maxWidth * (containerCount() / rows); + + if (containerCount() % rows > 0) + { + actualMax += maxWidth; + } + if (containerCount() == 0) + { + actualMax = maxWidth; + } + + if (actualMax > maxSize.width()) + { + return maxSize; + } + return QSize( actualMax, maxSize.height() ); + } +} + +void TaskBar::configure() +{ + bool wasShowWindows = m_showAllWindows; + bool wasSortByDesktop = m_sortByDesktop; + bool wasShowIcon = m_showIcon; + bool wasShowOnlyIconified = m_showOnlyIconified; + + m_showAllWindows = TaskBarSettings::showAllWindows(); + m_sortByDesktop = m_showAllWindows && TaskBarSettings::sortByDesktop(); + m_showIcon = TaskBarSettings::showIcon(); + m_showOnlyIconified = TaskBarSettings::showOnlyIconified(); + + m_currentScreen = -1; // Show all screens or re-get our screen + m_showOnlyCurrentScreen = TaskBarSettings::showCurrentScreenOnly() && + QApplication::desktop()->isVirtualDesktop() && + QApplication::desktop()->numScreens() > 1; + + // we need to watch geometry issues if we aren't showing windows when we + // are paying attention to the current Xinerama screen + if (m_showOnlyCurrentScreen) + { + // disconnect first in case we've been here before + // to avoid multiple connections + disconnect(TaskManager::the(), SIGNAL(windowChangedGeometry(Task::Ptr)), + this, SLOT(windowChangedGeometry(Task::Ptr))); + connect(TaskManager::the(), SIGNAL(windowChangedGeometry(Task::Ptr)), + this, SLOT(windowChangedGeometry(Task::Ptr))); + } + TaskManager::the()->trackGeometry(m_showOnlyCurrentScreen); + + if (wasShowWindows != m_showAllWindows || + wasSortByDesktop != m_sortByDesktop || + wasShowIcon != m_showIcon || + wasShowOnlyIconified != m_showOnlyIconified) + { + // relevant settings changed, update our task containers + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + (*it)->settingsChanged(); + } + } + + TaskManager::the()->setXCompositeEnabled(TaskBarSettings::showThumbnails()); + + reLayoutEventually(); +} + +void TaskBar::setOrientation( Orientation o ) +{ + Panner::setOrientation( o ); + reLayoutEventually(); +} + +void TaskBar::moveEvent( QMoveEvent* e ) +{ + Panner::moveEvent(e); + setViewportBackground(); +} + +void TaskBar::resizeEvent( QResizeEvent* e ) +{ + if (m_showOnlyCurrentScreen) + { + QPoint topLeft = mapToGlobal(this->geometry().topLeft()); + if (m_currentScreen != QApplication::desktop()->screenNumber(topLeft)) + { + // we have been moved to another screen! + m_currentScreen = -1; + reGroup(); + } + } + + Panner::resizeEvent(e); + reLayoutEventually(); + setViewportBackground(); +} + +void TaskBar::add(Task::Ptr task) +{ + if (!task || + (m_showOnlyCurrentScreen && + !TaskManager::isOnScreen(showScreen(), task->window()))) + { + return; + } + + // try to group + if (isGrouping) + { + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + TaskContainer* c = *it; + + if (idMatch(task->classClass(), c->id())) + { + c->add(task); + reLayoutEventually(); + return; + } + } + } + + // create new container + TaskContainer *container = new TaskContainer(task, this, viewport()); + m_hiddenContainers.append(container); + + // even though there is a signal to listen to, we have to add this + // immediately to ensure grouping doesn't break (primarily on startup) + // we still add the container to m_hiddenContainers in case the event + // loop gets re-entered here and something bizarre happens. call it + // insurance =) + showTaskContainer(container); +} + +void TaskBar::add(Startup::Ptr startup) +{ + if (!startup) + { + return; + } + + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + if ((*it)->contains(startup)) + { + return; + } + } + + // create new container + TaskContainer *container = new TaskContainer(startup, frames, this, viewport()); + m_hiddenContainers.append(container); + connect(container, SIGNAL(showMe(TaskContainer*)), this, SLOT(showTaskContainer(TaskContainer*))); +} + +void TaskBar::showTaskContainer(TaskContainer* container) +{ + TaskContainer::List::iterator it = m_hiddenContainers.find(container); + if (it != m_hiddenContainers.end()) + { + m_hiddenContainers.erase(it); + } + + if (container->isEmpty()) + { + return; + } + + // try to place the container after one of the same app + if (TaskBarSettings::sortByApp()) + { + TaskContainer::Iterator it = containers.begin(); + for (; it != containers.end(); ++it) + { + TaskContainer* c = *it; + + if (container->id().lower() == c->id().lower()) + { + // search for the last occurrence of this app + for (; it != containers.end(); ++it) + { + c = *it; + + if (container->id().lower() != c->id().lower()) + { + break; + } + } + break; + } + } + + if (it != containers.end()) + { + containers.insert(it, container); + } + else + { + containers.append(container); + } + } + else + { + containers.append(container); + } + + addChild(container); + reLayoutEventually(); + emit containerCountChanged(); +} + +void TaskBar::remove(Task::Ptr task, TaskContainer* container) +{ + for (TaskContainer::Iterator it = m_hiddenContainers.begin(); + it != m_hiddenContainers.end(); + ++it) + { + if ((*it)->contains(task)) + { + (*it)->finish(); + m_deletableContainers.append(*it); + m_hiddenContainers.erase(it); + break; + } + } + + if (!container) + { + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + if ((*it)->contains(task)) + { + container = *it; + break; + } + } + + if (!container) + { + return; + } + } + + container->remove(task); + + if (container->isEmpty()) + { + TaskContainer::List::iterator it = containers.find(container); + if (it != containers.end()) + { + containers.erase(it); + } + + removeChild(container); + container->finish(); + m_deletableContainers.append(container); + + reLayoutEventually(); + emit containerCountChanged(); + } + else if (container->filteredTaskCount() < 1) + { + reLayoutEventually(); + emit containerCountChanged(); + } +} + +void TaskBar::remove(Startup::Ptr startup, TaskContainer* container) +{ + for (TaskContainer::Iterator it = m_hiddenContainers.begin(); + it != m_hiddenContainers.end(); + ++it) + { + if ((*it)->contains(startup)) + { + (*it)->remove(startup); + + if ((*it)->isEmpty()) + { + (*it)->finish(); + m_deletableContainers.append(*it); + m_hiddenContainers.erase(it); + } + + break; + } + } + + if (!container) + { + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + if ((*it)->contains(startup)) + { + container = *it; + break; + } + } + + if (!container) + { + return; + } + } + + container->remove(startup); + if (!container->isEmpty()) + { + return; + } + + TaskContainer::List::iterator it = containers.find(container); + if (it != containers.end()) + { + containers.erase(it); + } + + // startup containers only ever contain that one item. so + // just delete the poor bastard. + container->finish(); + m_deletableContainers.append(container); + reLayoutEventually(); + emit containerCountChanged(); +} + +void TaskBar::desktopChanged(int desktop) +{ + if (m_showAllWindows) + { + return; + } + + m_relayoutTimer.stop(); + m_ignoreUpdates = true; + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + (*it)->desktopChanged(desktop); + } + + m_ignoreUpdates = false; + reLayout(); + emit containerCountChanged(); +} + +void TaskBar::windowChanged(Task::Ptr task) +{ + if (m_showOnlyCurrentScreen && + !TaskManager::isOnScreen(showScreen(), task->window())) + { + return; // we don't care about this window + } + + TaskContainer* container = 0; + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + TaskContainer* c = *it; + + if (c->contains(task)) + { + container = c; + break; + } + } + + // if we don't have a container or we're showing only windows on this + // desktop and the container is neither on the desktop nor currently visible + // just skip it + if (!container || + (!m_showAllWindows && + !container->onCurrentDesktop() && + !container->isVisibleTo(this))) + { + return; + } + + container->windowChanged(task); + + if (!m_showAllWindows || m_showOnlyIconified) + { + emit containerCountChanged(); + } + + reLayoutEventually(); +} + +void TaskBar::windowChangedGeometry(Task::Ptr task) +{ + //TODO: this gets called every time a window's geom changes + // when we are in "show only on the same Xinerama screen" + // mode it would be Good(tm) to compress these events so this + // gets run less often, but always when needed + TaskContainer* container = 0; + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + TaskContainer* c = *it; + if (c->contains(task)) + { + container = c; + break; + } + } + + if ((!!container) == TaskManager::isOnScreen(showScreen(), task->window())) + { + // we have this window covered, so we don't need to do anything + return; + } + + if (container) + { + remove(task, container); + } + else + { + add(task); + } +} + +void TaskBar::reLayoutEventually() +{ + m_relayoutTimer.stop(); + + if (!blocklayout && !m_ignoreUpdates) + { + m_relayoutTimer.start(25, true); + } +} + +void TaskBar::reLayout() +{ + // Because QPopupMenu::exec() creates its own event loop, deferred deletes + // via QObject::deleteLater() may be prematurely executed when a container's + // popup menu is visible. + // + // To get around this, we collect the containers and delete them manually + // when doing a relayout. (kling) + if (!m_deletableContainers.isEmpty()) { + TaskContainer::List::iterator it = m_deletableContainers.begin(); + for (; it != m_deletableContainers.end(); ++it) + delete *it; + m_deletableContainers.clear(); + } + + // filter task container list + TaskContainer::List list = filteredContainers(); + + if (list.count() < 1) + { + resizeContents(contentsRect().width(), contentsRect().height()); + return; + } + + if (isGrouping != shouldGroup()) + { + reGroup(); + return; + } + + // sort container list by desktop + if (m_sortByDesktop) + { + sortContainersByDesktop(list); + } + + // needed because Panner doesn't know how big it's contents are so it's + // up to use to initialize it. =( + resizeContents(contentsRect().width(), contentsRect().height()); + + // number of rows simply depends on our height which is either the + // minimum button height or the height of the font in use, whichever is + // largest + QFontMetrics fm(KGlobalSettings::taskbarFont()); + int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ? + fm.height() : TaskBarSettings::minimumButtonHeight(); + + // horizontal layout + if (orientation() == Horizontal) + { + int bwidth = BUTTON_MIN_WIDTH; + int rows = contentsRect().height() / minButtonHeight; + + if ( rows < 1 ) + { + rows = 1; + } + + // actual button height + int bheight = contentsRect().height() / rows; + + // avoid zero devision later + if (bheight < 1) + { + bheight = 1; + } + + // buttons per row + int bpr = (int)ceil( (double)list.count() / rows); + + // adjust content size + if ( contentsRect().width() < bpr * BUTTON_MIN_WIDTH ) + { + resizeContents( bpr * BUTTON_MIN_WIDTH, contentsRect().height() ); + } + + // maximum number of buttons per row + int mbpr = contentsRect().width() / BUTTON_MIN_WIDTH; + + // expand button width if space permits + if (mbpr > bpr) + { + bwidth = contentsRect().width() / bpr; + int maxWidth = TaskBarSettings::maximumButtonWidth(); + if (maxWidth > 0 && bwidth > maxWidth) + { + bwidth = maxWidth; + } + } + + // layout containers + + // for taskbars at the bottom, we need to ensure that the bottom + // buttons touch the bottom of the screen. since we layout from + // top to bottom this means seeing if we have any padding and + // popping it on the top. this preserves Fitt's Law behaviour + // for taskbars on the bottom + int topPadding = 0; + if (arrowType == UpArrow) + { + topPadding = contentsRect().height() % (rows * bheight); + } + + int i = 0; + bool reverseLayout = QApplication::reverseLayout(); + for (TaskContainer::Iterator it = list.begin(); + it != list.end(); + ++it, i++) + { + TaskContainer* c = *it; + + int row = i % rows; + + int x = ( i / rows ) * bwidth; + if (reverseLayout) + { + x = contentsRect().width() - x - bwidth; + } + int y = (row * bheight) + topPadding; + + c->setArrowType(arrowType); + + if (childX(c) != x || childY(c) != y) + moveChild(c, x, y); + + if (c->width() != bwidth || c->height() != bheight) + c->resize( bwidth, bheight ); + + c->setBackground(); + } + } + else // vertical layout + { + // adjust content size + if (contentsRect().height() < (int)list.count() * minButtonHeight) + { + resizeContents(contentsRect().width(), list.count() * minButtonHeight); + } + + // layout containers + int i = 0; + for (TaskContainer::Iterator it = list.begin(); + it != list.end(); + ++it) + { + TaskContainer* c = *it; + + c->setArrowType(arrowType); + + if (c->width() != contentsRect().width() || c->height() != minButtonHeight) + c->resize(contentsRect().width(), minButtonHeight); + + if (childX(c) != 0 || childY(c) != (i * minButtonHeight)) + moveChild(c, 0, i * minButtonHeight); + + c->setBackground(); + i++; + } + } + + QTimer::singleShot(100, this, SLOT(publishIconGeometry())); +} + +void TaskBar::setViewportBackground() +{ + const QPixmap *bg = parentWidget()->backgroundPixmap(); + + if (bg) + { + QPixmap pm(parentWidget()->size()); + pm.fill(parentWidget(), pos() + viewport()->pos()); + viewport()->setPaletteBackgroundPixmap(pm); + viewport()->setBackgroundOrigin(WidgetOrigin); + } + else + viewport()->setPaletteBackgroundColor(paletteBackgroundColor()); +} + +void TaskBar::setBackground() +{ + setViewportBackground(); + + TaskContainer::List list = filteredContainers(); + + for (TaskContainer::Iterator it = list.begin(); + it != list.end(); + ++it) + { + TaskContainer* c = *it; + c->setBackground(); + } +} + +void TaskBar::setArrowType(Qt::ArrowType at) +{ + if (arrowType == at) + { + return; + } + + arrowType = at; + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + (*it)->setArrowType(arrowType); + } +} + +void TaskBar::publishIconGeometry() +{ + QPoint p = mapToGlobal(QPoint(0,0)); // roundtrip, don't do that too often + + for (TaskContainer::Iterator it = containers.begin(); + it != containers.end(); + ++it) + { + (*it)->publishIconGeometry(p); + } +} + +void TaskBar::viewportMousePressEvent( QMouseEvent* e ) +{ + propagateMouseEvent( e ); +} + +void TaskBar::viewportMouseReleaseEvent( QMouseEvent* e ) +{ + propagateMouseEvent( e ); +} + +void TaskBar::viewportMouseDoubleClickEvent( QMouseEvent* e ) +{ + propagateMouseEvent( e ); +} + +void TaskBar::viewportMouseMoveEvent( QMouseEvent* e ) +{ + propagateMouseEvent( e ); +} + +void TaskBar::propagateMouseEvent( QMouseEvent* e ) +{ + if ( !isTopLevel() ) + { + QMouseEvent me( e->type(), mapTo( topLevelWidget(), e->pos() ), + e->globalPos(), e->button(), e->state() ); + QApplication::sendEvent( topLevelWidget(), &me ); + } +} + +bool TaskBar::idMatch( const QString& id1, const QString& id2 ) +{ + if ( id1.isEmpty() || id2.isEmpty() ) + return false; + + return id1.lower() == id2.lower(); +} + +int TaskBar::containerCount() const +{ + int i = 0; + + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + if ((m_showAllWindows || (*it)->onCurrentDesktop()) && + ((showScreen() == -1) || ((*it)->isOnScreen()))) + { + i++; + } + } + + return i; +} + +int TaskBar::taskCount() const +{ + int i = 0; + + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + if ((m_showAllWindows || (*it)->onCurrentDesktop()) && + ((showScreen() == -1) || ((*it)->isOnScreen()))) + { + i += (*it)->filteredTaskCount(); + } + } + + return i; +} + +int TaskBar::maximumButtonsWithoutShrinking() const +{ + QFontMetrics fm(KGlobalSettings::taskbarFont()); + int minButtonHeight = fm.height() > TaskBarSettings::minimumButtonHeight() ? + fm.height() : TaskBarSettings::minimumButtonHeight(); + int rows = contentsRect().height() / minButtonHeight; + + if (rows < 1) + { + rows = 1; + } + + if ( orientation() == Horizontal ) { + // maxWidth of 0 means no max width, drop back to default + int maxWidth = TaskBarSettings::maximumButtonWidth(); + if (maxWidth == 0) + { + maxWidth = BUTTON_MAX_WIDTH; + } + + // They squash a bit before they pop, hence the 2 + return rows * (contentsRect().width() / maxWidth) + 2; + } + else + { + // Overlap slightly and ugly arrows appear, hence -1 + return rows - 1; + } +} + +bool TaskBar::shouldGroup() const +{ + return TaskBarSettings::groupTasks() == TaskBarSettings::GroupAlways || + (TaskBarSettings::groupTasks() == TaskBarSettings::GroupWhenFull && + taskCount() > maximumButtonsWithoutShrinking()); +} + +void TaskBar::reGroup() +{ + isGrouping = shouldGroup(); + blocklayout = true; + + TaskContainer::Iterator lastContainer = m_hiddenContainers.end(); + for (TaskContainer::Iterator it = m_hiddenContainers.begin(); + it != lastContainer; + ++it) + { + (*it)->finish(); + m_deletableContainers.append(*it); + } + m_hiddenContainers.clear(); + + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + (*it)->finish(); + m_deletableContainers.append(*it); + } + containers.clear(); + + Task::Dict tasks = TaskManager::the()->tasks(); + Task::Dict::iterator lastTask = tasks.end(); + for (Task::Dict::iterator it = tasks.begin(); it != lastTask; ++it) + { + Task::Ptr task = it.data(); + if (showScreen() == -1 || task->isOnScreen(showScreen())) + { + add(task); + } + } + + Startup::List startups = TaskManager::the()->startups(); + Startup::List::iterator itEnd = startups.end(); + for (Startup::List::iterator sIt = startups.begin(); sIt != itEnd; ++sIt) + { + add(*sIt); + } + + blocklayout = false; + reLayoutEventually(); +} + + +TaskContainer::List TaskBar::filteredContainers() +{ + // filter task container list + TaskContainer::List list; + + for (TaskContainer::List::const_iterator it = containers.constBegin(); + it != containers.constEnd(); + ++it) + { + TaskContainer* c = *it; + if ((m_showAllWindows || c->onCurrentDesktop()) && + (!m_showOnlyIconified || c->isIconified()) && + ((showScreen() == -1) || c->isOnScreen())) + { + list.append(c); + c->show(); + } + else + { + c->hide(); + } + } + + return list; +} + +void TaskBar::activateNextTask(bool forward) +{ + bool forcenext = false; + TaskContainer::List list = filteredContainers(); + + // this is necessary here, because 'containers' is unsorted and + // we want to iterate over the _shown_ task containers in a linear way + if (m_sortByDesktop) + { + sortContainersByDesktop(list); + } + + int numContainers = list.count(); + TaskContainer::List::iterator it; + for (int i = 0; i < numContainers; ++i) + { + it = forward ? list.at(i) : list.at(numContainers - i - 1); + + if (it != list.end() && (*it)->activateNextTask(forward, forcenext)) + { + return; + } + } + + if (forcenext) + { + // moving forward from the last, or backward from the first, loop around + for (int i = 0; i < numContainers; ++i) + { + it = forward ? list.at(i) : list.at(numContainers - i - 1); + + if (it != list.end() && (*it)->activateNextTask(forward, forcenext)) + { + return; + } + } + + return; + } + + forcenext = true; // select first + for (int i = 0; i < numContainers; ++i) + { + it = forward ? list.at(i) : list.at(numContainers - i - 1); + + if (it == list.end()) + { + break; + } + + TaskContainer* c = *it; + if (m_sortByDesktop) + { + if (forward ? c->desktop() < TaskManager::the()->currentDesktop() + : c->desktop() > TaskManager::the()->currentDesktop()) + { + continue; + } + } + + if (c->activateNextTask(forward, forcenext)) + { + return; + } + } +} + +void TaskBar::wheelEvent(QWheelEvent* e) +{ + if (e->delta() > 0) + { + // scroll away from user, previous task + activateNextTask(false); + } + else + { + // scroll towards user, next task + activateNextTask(true); + } +} + +void TaskBar::slotActivateNextTask() +{ + activateNextTask( true ); +} + +void TaskBar::slotActivatePreviousTask() +{ + activateNextTask( false ); +} + +void TaskBar::slotSettingsChanged( int category ) +{ + if( category == (int) KApplication::SETTINGS_SHORTCUTS ) + { + keys->readSettings(); + keys->updateConnections(); + } +} + +int TaskBar::showScreen() const +{ + if (m_showOnlyCurrentScreen && m_currentScreen == -1) + { + const_cast<TaskBar*>(this)->m_currentScreen = + QApplication::desktop()->screenNumber(mapToGlobal(this->geometry().topLeft())); + } + + return m_currentScreen; +} + +QImage* TaskBar::blendGradient(const QSize& size) +{ + if (m_blendGradient.isNull() || m_blendGradient.size() != size) + { + QPixmap bgpm(size); + QPainter bgp(&bgpm); + bgpm.fill(black); + + if (QApplication::reverseLayout()) + { + QImage gradient = KImageEffect::gradient( + QSize(30, size.height()), + QColor(255,255,255), + QColor(0,0,0), + KImageEffect::HorizontalGradient); + bgp.drawImage(0, 0, gradient); + } + else + { + QImage gradient = KImageEffect::gradient( + QSize(30, size.height()), + QColor(0,0,0), + QColor(255,255,255), + KImageEffect::HorizontalGradient); + bgp.drawImage(size.width() - 30, 0, gradient); + } + + m_blendGradient = bgpm.convertToImage(); + } + + return &m_blendGradient; +} + +void TaskBar::sortContainersByDesktop(TaskContainer::List& list) +{ + typedef QValueVector<QPair<int, QPair<int, TaskContainer*> > > SortVector; + SortVector sorted; + sorted.resize(list.count()); + int i = 0; + + TaskContainer::List::ConstIterator lastUnsorted(list.constEnd()); + for (TaskContainer::List::ConstIterator it = list.constBegin(); + it != lastUnsorted; + ++it) + { + sorted[i] = qMakePair((*it)->desktop(), qMakePair(i, *it)); + ++i; + } + + qHeapSort(sorted); + + list.clear(); + SortVector::const_iterator lastSorted(sorted.constEnd()); + for (SortVector::const_iterator it = sorted.constBegin(); + it != lastSorted; + ++it) + { + list.append((*it).second.second); + } +} + diff --git a/kicker/taskbar/taskbar.h b/kicker/taskbar/taskbar.h new file mode 100644 index 000000000..73c397670 --- /dev/null +++ b/kicker/taskbar/taskbar.h @@ -0,0 +1,135 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskbar_h__ +#define __taskbar_h__ + +#include <kpanelextension.h> +#include <taskmanager.h> + +#include "taskcontainer.h" +#include "panner.h" +#include "kshadowengine.h" + +#define WINDOWLISTBUTTON_SIZE 15 +#define BUTTON_MAX_WIDTH 200 +#define BUTTON_MIN_WIDTH 20 + +class Startup; +class Task; +class KGlobalAccel; + +class TaskBar : public Panner +{ + Q_OBJECT + +public: + TaskBar( QWidget *parent = 0, const char *name = 0 ); + ~TaskBar(); + + QSize sizeHint() const; + QSize sizeHint( KPanelExtension::Position, QSize maxSize ) const; + + void setOrientation( Orientation ); + void setArrowType( Qt::ArrowType at ); + + int containerCount() const; + int taskCount() const; + int showScreen() const; + + bool showIcon() const { return m_showIcon; } + bool sortByDesktop() const { return m_sortByDesktop; } + bool showAllWindows() const { return m_showAllWindows; } + + QImage* blendGradient(const QSize& size); + + KTextShadowEngine *textShadowEngine(); + +public slots: + void configure(); + void setBackground(); + +signals: + void containerCountChanged(); + +protected slots: + void add(Task::Ptr); + void add(Startup::Ptr); + void showTaskContainer(TaskContainer*); + void remove(Task::Ptr task, TaskContainer *container = 0); + void remove(Startup::Ptr startup, TaskContainer *container = 0); + + void desktopChanged( int ); + void windowChanged(Task::Ptr); + void windowChangedGeometry(Task::Ptr); + + void publishIconGeometry(); + + void activateNextTask( bool forward ); + void slotActivateNextTask(); + void slotActivatePreviousTask(); + void slotSettingsChanged(int); + void reLayout(); + +protected: + void reLayoutEventually(); + void viewportMousePressEvent( QMouseEvent* ); + void viewportMouseReleaseEvent( QMouseEvent* ); + void viewportMouseDoubleClickEvent( QMouseEvent* ); + void viewportMouseMoveEvent( QMouseEvent* ); + void wheelEvent(QWheelEvent*); + void propagateMouseEvent( QMouseEvent* ); + void resizeEvent( QResizeEvent* ); + void moveEvent( QMoveEvent* ); + bool idMatch( const QString& id1, const QString& id2 ); + TaskContainer::List filteredContainers(); + +private: + void sortContainersByDesktop(TaskContainer::List& list); + void setViewportBackground(); + + bool blocklayout; + bool m_showAllWindows; + // The screen to show, -1 for all screens + int m_currentScreen; + bool m_showOnlyCurrentScreen; + bool m_sortByDesktop; + bool m_showIcon; + bool m_showOnlyIconified; + ArrowType arrowType; + TaskContainer::List containers; + TaskContainer::List m_hiddenContainers; + TaskContainer::List m_deletableContainers; + PixmapList frames; + int maximumButtonsWithoutShrinking() const; + bool shouldGroup() const; + bool isGrouping; + void reGroup(); + KGlobalAccel* keys; + KTextShadowEngine* m_textShadowEngine; + QTimer m_relayoutTimer; + bool m_ignoreUpdates; + QImage m_blendGradient; +}; + +#endif diff --git a/kicker/taskbar/taskbar.kcfg b/kicker/taskbar/taskbar.kcfg new file mode 100644 index 000000000..173e5b8ec --- /dev/null +++ b/kicker/taskbar/taskbar.kcfg @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="ktaskbarrc"/> + + <group name="General"> + <entry key="ShowAllWindows" type="Bool" > + <default>true</default> + <label>Show windows from all desktops</label> + <whatsthis>Turning this option off will cause the taskbar to display <b>only</b> the windows on the current desktop. \n\nBy default, this option is selected and all windows are shown.</whatsthis> + </entry> + <entry key="ShowOnlyIconified" type="Bool" > + <default>false</default> + <label>Show only minimized windows</label> + <whatsthis>Select this option if you want the taskbar to display <b>only</b> minimized windows. \n\nBy default, this option is not selected and the taskbar will show all windows.</whatsthis> + </entry> + <entry key="GroupTasks" type="Enum" > + <choices> + <choice name="GroupNever"> + <label>Never</label> + </choice> + <choice name="GroupWhenFull"> + <label>When Taskbar Full</label> + </choice> + <choice name="GroupAlways"> + <label>Always</label> + </choice> + </choices> + <default>GroupWhenFull</default> + <label>Group similar tasks:</label> + <whatsthis>The taskbar can group similar windows into single buttons. When one of these window group buttons are clicked on a menu appears showing all the windows in that group. This can be especially useful with the <em>Show all windows</em> option.\n\nYou can set the taskbar to <strong>Never</strong> group windows, to <strong>Always</strong> group windows or to group windows only <strong>When the Taskbar is Full</strong>.\n\nBy default the taskbar groups windows when it is full.</whatsthis> + </entry> + <entry key="SortByDesktop" type="Bool" > + <default>true</default> + <label>Sort windows by desktop</label> + <whatsthis>Selecting this option causes the taskbar to show windows in order of the desktop they appear on.\n\nBy default this option is selected.</whatsthis> + </entry> + <entry key="SortByApp" type="Bool" > + <default>true</default> + <label>Sort windows by application</label> + <whatsthis>Selecting this option causes the taskbar to show windows ordered by application.\n\nBy default this option is selected.</whatsthis> + </entry> + <entry key="ShowIcon" type="Bool" > + <default>true</default> + <label>Show application icons</label> + <whatsthis>Select this option if you want window icons to appear along with their titles in the taskbar.\n\nBy default this option is selected.</whatsthis> + </entry> + <entry key="MaximumButtonWidth" type="Int" > + <default>200</default> + <min>0</min> + <label></label> + <whatsthis></whatsthis> + </entry> + <entry key="MinimumButtonHeight" type="Int" > + <default>18</default> + <label></label> + <min>1</min> + <whatsthis></whatsthis> + </entry> + <entry key="ShowCurrentScreenOnly" type="Bool" > + <default>false</default> + <label>Show windows from all screens</label> + <whatsthis>Turning this option off will cause the taskbar to display <b>only</b> windows which are on the same Xinerama screen as the taskbar.\n\nBy default, this option is selected and all windows are shown.</whatsthis> + </entry> + <entry key="taskbarFont" type="Font" > + <default></default> + <label></label> + <whatsthis></whatsthis> + </entry> + <entry key="ShowWindowListBtn" type="Bool" > + <default>false</default> + <label>Show window list button</label> + <whatsthis>Selecting this option causes the taskbar to display a button that, when clicked, shows a list of all windows in a popup menu.</whatsthis> + </entry> + <entry key="$(Button)Action" type="Enum" > + <parameter name="Button" type="Enum"> + <values> + <value>LeftButton</value> + <value>MiddleButton</value> + <value>RightButton</value> + </values> + </parameter> + <choices> + <choice name="ShowTaskList"> + <label>Show Task List</label> + </choice> + <choice name="ShowOperationsMenu"> + <label>Show Operations Menu</label> + </choice> + <choice name="ActivateRaiseOrMinimize"> + <label>Activate, Raise or Minimize Task</label> + </choice> + <choice name="Activate"> + <label>Activate Task</label> + </choice> + <choice name="Raise"> + <label>Raise Task</label> + </choice> + <choice name="Lower"> + <label>Lower Task</label> + </choice> + <choice name="Minimize"> + <label>Minimize Task</label> + </choice> + <choice name="ToCurrentDesktop"> + <label>Move To Current Desktop</label> + </choice> + <choice name="Close"> + <label>Close Task</label> + </choice> + </choices> + <default param="LeftButton">ShowTaskList</default> + <default param="MiddleButton">ActivateRaiseOrMinimize</default> + <default param="RightButton">ShowOperationsMenu</default> + <label>Mouse button actions</label> + <whatsthis></whatsthis> + </entry> + </group> + + <group name="Appearance"> + <entry key="AttentionBlinkIterations" type="Int"> + <default>4</default> + <label>The number of times to blink a taskbar button when a window asks for attention. Setting this to 1000 or greater causes the button to blink forever.</label> + <min>0</min> + </entry> + <entry key="DrawButtons" type="Bool" > + <default>false</default> + <label>Draw taskbar entries "flat" and not as a button</label> + <whatsthis>Turning this option on will cause the taskbar to draw visible button frames for each entry in the taskbar. \n\nBy default, this option is off.</whatsthis> + </entry> + <entry key="HaloText" type="Bool" > + <default>false</default> + <label>Draw taskbar text with a halo around it</label> + <whatsthis>Turning this option on will cause the taskbar to draw fancier text that has an outline around it. While this is useful for transparent panels or particularly dark panel backgrounds, it is slower.</whatsthis> + </entry> + <entry key="ShowButtonOnHover" type="Bool" > + <default>true</default> + <label>Show a visible button frame on the task the cursor is positioned over</label> + </entry> + <entry key="ShowThumbnails" type="Bool" > + <default>false</default> + <label>Show thumbnails instead of icons in the mouse-over effects</label> + <whatsthis>Enabling this option will draw a thumbnail of the window in its mouse-over effect.<p>If a window is minimized or resides on a different desktop while the taskbar is starting, an icon is shown until the window is restored or the appropriate desktop is activated, respectively.</p></whatsthis> + </entry> + <entry key="ThumbnailMaxDimension" type="UInt" > + <default>100</default> + <label>Maximum width/height of the thumbnail in pixels</label> + <whatsthis>A thumbnail is created by resizing the window. The scaling factor is determined by its largest dimension and this value. In doing so, the thumbnail's size will not exceed this value in any dimension.</whatsthis> + </entry> + <entry key="UseCustomColors" type="Bool" > + <default>false</default> + <label>Use custom colors for taskbar buttons text and background</label> + <whatsthis>Turning this option on will allow choosing your own colors for taskbar buttons text and background.</whatsthis> + </entry> + <entry name="ActiveTaskTextColor" type="Color" > + <label>Color to use for active task button text</label> + <default code="true">QColor()</default> + <whatsthis>This color is used for displaying text on taskbar button for task which is active at the moment.</whatsthis> + </entry> + <entry name="InactiveTaskTextColor" type="Color" > + <label>Color to use for inactive tasks button text</label> + <default code="true">QColor()</default> + <whatsthis>This color is used for displaying text on taskbar button for tasks other than active.</whatsthis> + </entry> + <entry name="TaskBackgroundColor" type="Color" > + <label>Color to use for taskbar buttons background</label> + <default code="true">QColor()</default> + <whatsthis>This color is used for displaying background of taskbar buttons.</whatsthis> + </entry> + </group> +</kcfg> diff --git a/kicker/taskbar/taskbarbindings.cpp b/kicker/taskbar/taskbarbindings.cpp new file mode 100644 index 000000000..63accd854 --- /dev/null +++ b/kicker/taskbar/taskbarbindings.cpp @@ -0,0 +1,37 @@ +/***************************************************************** + +Copyright (c) 2001-2004 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef NOSLOTS +# define DEF( name, key3, key4, fnSlot ) \ + keys->insert( name, i18n(name), QString::null, key3, key4, this, SLOT(fnSlot) ) +#else +# define DEF( name, key3, key4, fnSlot ) \ + keys->insert( name, i18n(name), QString::null, key3, key4 ) +#endif +#define WIN KKey::QtWIN + + DEF( I18N_NOOP( "Next Taskbar Entry" ), 0, 0, slotActivateNextTask() ); + DEF( I18N_NOOP( "Previous Taskbar Entry" ), 0, 0, slotActivatePreviousTask() ); + +#undef DEF +#undef WIN diff --git a/kicker/taskbar/taskbarcontainer.cpp b/kicker/taskbar/taskbarcontainer.cpp new file mode 100644 index 000000000..a548b7837 --- /dev/null +++ b/kicker/taskbar/taskbarcontainer.cpp @@ -0,0 +1,292 @@ +/***************************************************************** + +Copyright (c) 2001 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlayout.h> +#include <qtimer.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kwindowlistmenu.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "simplebutton.h" + +#include "taskbar.h" +#include "taskbarsettings.h" + +#include "taskbarcontainer.h" +#include "taskbarcontainer.moc" + +TaskBarContainer::TaskBarContainer( bool enableFrame, QWidget *parent, const char *name ) + : QFrame(parent, name), + direction( KPanelApplet::Up ), + showWindowListButton( true ), + windowListButton(0), + windowListMenu(0) +{ + setBackgroundOrigin( AncestorOrigin ); + + uint margin; + if ( enableFrame ) + { + setFrameStyle( Sunken | StyledPanel ); + margin = frameWidth(); + } + else + { + setFrameStyle( NoFrame ); + margin = 0; + } + + layout = new QBoxLayout( this, QApplication::reverseLayout() ? + QBoxLayout::RightToLeft : + QBoxLayout::LeftToRight ); + layout->setMargin( margin ); + + // scrollable taskbar + taskBar = new TaskBar(this); + layout->addWidget( taskBar ); + + connect( taskBar, SIGNAL( containerCountChanged() ), SIGNAL( containerCountChanged() ) ); + + setBackground(); + + // read settings and setup layout + configure(); + + connectDCOPSignal("", "", "kdeTaskBarConfigChanged()", + "configChanged()", false); +} + +TaskBarContainer::~TaskBarContainer() +{ + delete windowListMenu; +} + +void TaskBarContainer::configure() +{ + setFont(TaskBarSettings::taskbarFont()); + showWindowListButton = TaskBarSettings::showWindowListBtn(); + + if (!showWindowListButton) + { + delete windowListButton; + windowListButton = 0; + delete windowListMenu; + windowListMenu = 0; + } + else if (windowListButton == 0) + { + // window list button + windowListButton = new SimpleButton(this); + windowListMenu= new KWindowListMenu; + connect(windowListButton, SIGNAL(pressed()), + SLOT(showWindowListMenu())); + connect(windowListMenu, SIGNAL(aboutToHide()), + SLOT(windowListMenuAboutToHide())); + + // geometry + QString icon; + switch (direction) + { + case KPanelApplet::Up: + icon = "1uparrow"; + windowListButton->setMaximumHeight(BUTTON_MAX_WIDTH); + break; + case KPanelApplet::Down: + icon = "1downarrow"; + windowListButton->setMaximumHeight(BUTTON_MAX_WIDTH); + break; + case KPanelApplet::Left: + icon = "1leftarrow"; + windowListButton->setMaximumWidth(BUTTON_MAX_WIDTH); + break; + case KPanelApplet::Right: + icon = "1rightarrow"; + windowListButton->setMaximumWidth(BUTTON_MAX_WIDTH); + break; + } + + windowListButton->setPixmap(kapp->iconLoader()->loadIcon(icon, + KIcon::Panel, + 16)); + windowListButton->setMinimumSize(windowListButton->sizeHint()); + layout->insertWidget(0, windowListButton); + windowListButton->show(); + } +} + +void TaskBarContainer::configChanged() +{ + // we have a separate method here to connect to the DCOP signal + // instead of connecting direclty to taskbar so that Taskbar + // doesn't have to also connect to the DCOP signal (less places + // to change/fix it if/when it changes) without calling + // configure() twice on taskbar on start up + TaskBarSettings::self()->readConfig(); + + configure(); + taskBar->configure(); +} + +void TaskBarContainer::preferences() +{ + QByteArray data; + + if (!kapp->dcopClient()->isAttached()) + { + kapp->dcopClient()->attach(); + } + + kapp->dcopClient()->send("kicker", "kicker", "showTaskBarConfig()", data); +} + +void TaskBarContainer::orientationChange(Orientation o) +{ + if (o == Horizontal) + { + if (windowListButton) + { + windowListButton->setFixedWidth(WINDOWLISTBUTTON_SIZE); + windowListButton->setMaximumHeight(BUTTON_MAX_WIDTH); + } + layout->setDirection(QApplication::reverseLayout() ? + QBoxLayout::RightToLeft : + QBoxLayout::LeftToRight); + } + else + { + if (windowListButton) + { + windowListButton->setMaximumWidth(BUTTON_MAX_WIDTH); + windowListButton->setFixedHeight(WINDOWLISTBUTTON_SIZE); + } + layout->setDirection(QBoxLayout::TopToBottom); + } + + taskBar->setOrientation(o); + if (windowListButton) + { + windowListButton->setOrientation(o); + } + layout->activate(); +} + +void TaskBarContainer::popupDirectionChange(KPanelApplet::Direction d) +{ + direction = d; + ArrowType at = UpArrow; + + QString icon; + switch (d) + { + case KPanelApplet::Up: + icon = "1uparrow"; + at = UpArrow; + break; + case KPanelApplet::Down: + icon = "1downarrow"; + at = DownArrow; + break; + case KPanelApplet::Left: + icon = "1leftarrow"; + at = LeftArrow; + break; + case KPanelApplet::Right: + icon = "1rightarrow"; + at = RightArrow; + break; + } + + taskBar->setArrowType(at); + + if (windowListButton) + { + windowListButton->setPixmap(kapp->iconLoader()->loadIcon(icon, + KIcon::Panel, + 16)); + windowListButton->setMinimumSize(windowListButton->sizeHint()); + } +} + +void TaskBarContainer::showWindowListMenu() +{ + if (!windowListMenu) + return; + + windowListMenu->init(); + + // calc popup menu position + QPoint pos( mapToGlobal( QPoint(0,0) ) ); + + switch( direction ) { + case KPanelApplet::Right: + pos.setX( pos.x() + width() ); + break; + case KPanelApplet::Left: + pos.setX( pos.x() - windowListMenu->sizeHint().width() ); + break; + case KPanelApplet::Down: + pos.setY( pos.y() + height() ); + break; + case KPanelApplet::Up: + pos.setY( pos.y() - windowListMenu->sizeHint().height() ); + default: + break; + } + + disconnect( windowListButton, SIGNAL( pressed() ), this, SLOT( showWindowListMenu() ) ); + windowListMenu->exec( pos ); + QTimer::singleShot(100, this, SLOT(reconnectWindowListButton())); +} + +void TaskBarContainer::windowListMenuAboutToHide() +{ + // this ensures that when clicked AGAIN, the window list button doesn't cause the + // window list menu to show again. usability, you see. hoorah. + windowListButton->setDown( false ); +} + +void TaskBarContainer::reconnectWindowListButton() +{ + connect( windowListButton, SIGNAL( pressed() ), SLOT( showWindowListMenu() ) ); +} + +QSize TaskBarContainer::sizeHint( KPanelExtension::Position p, QSize maxSize) const +{ + QSize size = taskBar->sizeHint( p, maxSize ); + if ( (p == KPanelExtension::Left || p == KPanelExtension::Right) && showWindowListButton ) { + return QSize( size.width(), size.height() + WINDOWLISTBUTTON_SIZE ); + } + return size; +} + +void TaskBarContainer::setBackground() +{ + taskBar->setBackground(); +} diff --git a/kicker/taskbar/taskbarcontainer.h b/kicker/taskbar/taskbarcontainer.h new file mode 100644 index 000000000..c265036b6 --- /dev/null +++ b/kicker/taskbar/taskbarcontainer.h @@ -0,0 +1,75 @@ +/***************************************************************** + +Copyright (c) 2001 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskbarcontainer_h__ +#define __taskbarcontainer_h__ + +#include <qframe.h> + +#include <dcopobject.h> +#include <kpanelapplet.h> +#include <kpanelextension.h> + +class QBoxLayout; +class SimpleButton; +class KWindowListMenu; +class TaskBar; + +class KDE_EXPORT TaskBarContainer : public QFrame, public DCOPObject +{ + Q_OBJECT + K_DCOP + +public: + TaskBarContainer( bool enableFrame, QWidget* parent = 0, const char* name = 0 ); + ~TaskBarContainer(); + + void orientationChange( Orientation ); + void popupDirectionChange( KPanelApplet::Direction ); + void preferences(); + //FIXME: don't use Position, use Orientation + QSize sizeHint( KPanelExtension::Position, QSize maxSize ) const; + void setBackground(); + +k_dcop: + void configChanged(); + +signals: + void containerCountChanged(); + +protected slots: + void configure(); + void showWindowListMenu(); + void windowListMenuAboutToHide(); + void reconnectWindowListButton(); + +private: + KPanelApplet::Direction direction; + bool showWindowListButton; + QBoxLayout * layout; + TaskBar * taskBar; + SimpleButton * windowListButton; + KWindowListMenu * windowListMenu; +}; + +#endif diff --git a/kicker/taskbar/taskbarsettings.kcfgc b/kicker/taskbar/taskbarsettings.kcfgc new file mode 100644 index 000000000..45c0da407 --- /dev/null +++ b/kicker/taskbar/taskbarsettings.kcfgc @@ -0,0 +1,7 @@ +File=taskbar.kcfg +Singleton=true +ClassName=TaskBarSettings +Mutators=true +Visibility=KDE_EXPORT +SetUserTexts=true +GlobalEnums=true diff --git a/kicker/taskbar/taskcontainer.cpp b/kicker/taskbar/taskcontainer.cpp new file mode 100644 index 000000000..7025d643a --- /dev/null +++ b/kicker/taskbar/taskcontainer.cpp @@ -0,0 +1,1643 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> +Copyright (c) 2005 Aaron Seigo <aseigo@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.# + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <assert.h> + +#include <qbitmap.h> +#include <qcolor.h> +#include <qcursor.h> +#include <qimage.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qstyle.h> +#include <qstylesheet.h> +#include <qtooltip.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kiconeffect.h> +#include <kiconloader.h> +#include <kimageeffect.h> + +#include "global.h" +#include "kickerSettings.h" +#include "paneldrag.h" +#include "taskbar.h" +#include "taskbarsettings.h" +#include "tasklmbmenu.h" +#include "taskrmbmenu.h" + +#include "taskcontainer.h" +#include "taskcontainer.moc" + +TaskContainer::TaskContainer(Task::Ptr task, TaskBar* bar, + QWidget *parent, const char *name) + : QToolButton(parent, name), + currentFrame(0), + attentionState(-1), + lastActivated(0), + m_menu(0), + m_startup(0), + arrowType(Qt::UpArrow), + taskBar(bar), + discardNextMouseEvent(false), + aboutToActivate(false), + m_mouseOver(false), + m_paintEventCompression(false) +{ + init(); + setAcceptDrops(true); // Always enabled to activate task during drag&drop. + + add(task); + + // we abuse this timer once to get shown + // no point in having another timer just for this, and + // a single shot won't do because we need to stop the timer + // in case our task is deleted out from under us + dragSwitchTimer.start(0, true); +} + +TaskContainer::TaskContainer(Startup::Ptr startup, PixmapList& startupFrames, + TaskBar* bar, QWidget *parent, const char *name) + : QToolButton(parent, name), + currentFrame(0), + frames(startupFrames), + attentionState(-1), + lastActivated(0), + m_menu(0), + m_startup(startup), + arrowType(Qt::LeftArrow), + taskBar(bar), + discardNextMouseEvent(false), + aboutToActivate(false), + m_mouseOver(false), + m_paintEventCompression(false) +{ + init(); + setEnabled(false); + + sid = m_startup->bin(); + + connect(m_startup, SIGNAL(changed()), SLOT(update())); + + dragSwitchTimer.start(333, true); +} + +void TaskContainer::init() +{ + setWFlags(WNoAutoErase); + setBackgroundMode(NoBackground); + animBg = QPixmap(16, 16); + + installEventFilter(KickerTip::the()); + + connect(&animationTimer, SIGNAL(timeout()), SLOT(animationTimerFired())); + connect(&dragSwitchTimer, SIGNAL(timeout()), SLOT(showMe())); + connect(&attentionTimer, SIGNAL(timeout()), SLOT(attentionTimerFired())); + connect(&m_paintEventCompressionTimer, SIGNAL(timeout()), SLOT(updateNow())); +} + +TaskContainer::~TaskContainer() +{ + if (m_menu) + { + delete m_menu; + m_menu = 0; + } + + stopTimers(); +} + +void TaskContainer::showMe() +{ + if(!frames.isEmpty() && taskBar->showIcon()) + animationTimer.start(100); + + emit showMe(this); + disconnect(&dragSwitchTimer, SIGNAL(timeout()), this, SLOT(showMe())); + connect(&dragSwitchTimer, SIGNAL(timeout()), SLOT(dragSwitch())); +} + +void TaskContainer::stopTimers() +{ + animationTimer.stop(); + dragSwitchTimer.stop(); + attentionTimer.stop(); +} + +void TaskContainer::taskChanged(bool geometryOnlyChange) +{ + if (geometryOnlyChange) + { + // we really don't care about those changes, which we may be getting + // thanks to the pager, for instance, turning it on in taskmanager. + // // let's ignore them so we don't end up with tons of processing going on + return; + } + + const QObject* source = sender(); + Task::Ptr task = 0; + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + if (*it == source) + { + task = *it; + break; + } + } + + if (task) + { + checkAttention(task); + } + + KickerTip::Client::updateKickerTip(); + update(); +} + +void TaskContainer::iconChanged() +{ + const QObject* source = sender(); + Task::Ptr task = 0; + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + if (*it == source) + { + task = *it; + break; + } + } + + if (task && !m_filteredTasks.empty() && task != m_filteredTasks.first()) + { + if (m_menu) + { + m_menu->update(); + } + return; + } + + KickerTip::Client::updateKickerTip(); + QToolButton::update(); +} + +void TaskContainer::setLastActivated() +{ + Task::List::const_iterator itEnd = m_filteredTasks.constEnd(); + for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + if ( t->isActive() ) + { + lastActivated = t; + return; + } + } + lastActivated = 0L; +} + + +void TaskContainer::animationTimerFired() +{ + if (!frames.isEmpty() && taskBar->showIcon() && frames.at(currentFrame) != frames.end()) + { + QPixmap *pm = *frames.at(currentFrame); + + // draw pixmap + if ( pm && !pm->isNull() ) { + // we only have to redraw the background for frames 0, 8 and 9 + if ( currentFrame == 0 || currentFrame > 7 ) { + // double buffered painting + QPixmap composite( animBg ); + bitBlt( &composite, 0, 0, pm ); + bitBlt( this, iconRect.x(), iconRect.y(), &composite ); + } + else + bitBlt( this, iconRect.x(), iconRect.y(), pm ); + } + + // increment frame counter + if ( currentFrame >= 9) + currentFrame = 0; + else + currentFrame++; + } +} + +void TaskContainer::checkAttention(const Task::Ptr t) +{ + bool attention = t ? t->demandsAttention() : false; + if (attention && attentionState == -1) // was activated + { + attentionState = 0; + attentionTimer.start(500); + } + else if(!attention && attentionState >= 0) + { // need to check all + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if ((*it)->demandsAttention()) + { + attention = true; + break; + } + } + + if (!attention) + { + attentionTimer.stop(); + attentionState = -1; + } + } +} + +void TaskContainer::attentionTimerFired() +{ + assert( attentionState != -1 ); + if (attentionState < TaskBarSettings::attentionBlinkIterations()*2) + { + ++attentionState; + } + else if (TaskBarSettings::attentionBlinkIterations() < 1000) + { + attentionTimer.stop(); + } + else + { + // we have a "forever" blinker (attentionBlinkIterations > 999) and have reached + // the upper limit. so we need to decrement the attentionState to make it blink + --attentionState; + } + update(); +} + +QSizePolicy TaskContainer::sizePolicy() const +{ + return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); +} + +void TaskContainer::resizeEvent( QResizeEvent * ) +{ + // calculate the icon rect + QRect br( style().subRect( QStyle::SR_PushButtonContents, this ) ); + iconRect = QStyle::visualRect( QRect(br.x() + 2, (height() - 16) / 2, 16, 16), this ); +} + +void TaskContainer::add(Task::Ptr task) +{ + if (!task) + { + return; + } + + tasks.append(task); + + if (sid.isEmpty()) + { + sid = task->classClass(); + } + + updateFilteredTaskList(); + checkAttention(task); + + KickerTip::Client::updateKickerTip(); + update(); + + connect(task, SIGNAL(changed(bool)), SLOT(taskChanged(bool))); + connect(task, SIGNAL(iconChanged()), SLOT(iconChanged())); + connect(task, SIGNAL(activated()), SLOT(setLastActivated())); +} + +void TaskContainer::remove(Task::Ptr task) +{ + if (!task) + { + return; + } + + task->publishIconGeometry(QRect()); + for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it) + { + if ((*it) == task) + { + tasks.erase(it); + break; + } + } + + updateFilteredTaskList(); + + if (isEmpty()) + { + stopTimers(); + return; + } + + checkAttention(); + KickerTip::Client::updateKickerTip(); + update(); +} + +void TaskContainer::remove(Startup::Ptr startup) +{ + if (!startup || startup != m_startup) + { + return; + } + + m_startup = 0; + animationTimer.stop(); + frames.clear(); + + if (!tasks.isEmpty()) + { + setEnabled(true); + } +} + +bool TaskContainer::contains(Task::Ptr task) +{ + if (!task) + { + return false; + } + + for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it) + { + if ((*it) == task) + { + return true; + } + } + + return false; +} + +bool TaskContainer::contains(Startup::Ptr startup) +{ + return startup && (m_startup == startup); +} + +bool TaskContainer::contains(WId win) +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if ((*it)->window() == win) + { + return true; + } + } + + return false; +} + +bool TaskContainer::isEmpty() +{ + return (tasks.isEmpty() && !m_startup); +} + +QString TaskContainer::id() +{ + return sid; +} + +void TaskContainer::updateNow() +{ + m_paintEventCompression = true; + update(); +} + +void TaskContainer::setBackground() +{ + updateNow(); +} + +void TaskContainer::paintEvent( QPaintEvent* ) +{ + if (!m_paintEventCompression) + { + if (!m_paintEventCompressionTimer.isActive()) + { + m_paintEventCompressionTimer.start(30, true); + } + return; + } + + m_paintEventCompression = false; + QPixmap* pm = new QPixmap(size()); + + const QPixmap* background = taskBar->backgroundPixmap(); + + if (background) + { + QPoint pt = mapTo(taskBar, QPoint(0, 0)) + taskBar->backgroundOffset(); + QPainter p(pm); + p.drawTiledPixmap(0, 0, width(), height(), *background, pt.x(), pt.y()); + p.end(); + } + else + { + pm->fill(taskBar->paletteBackgroundColor()); + } + + QPainter p; + p.begin(pm ,this); + drawButton(&p); + p.end(); + + bitBlt(this, 0, 0, pm); + delete pm; +} + +void TaskContainer::drawButton(QPainter *p) +{ + if (isEmpty()) + { + return; + } + + // get a pointer to the pixmap we're drawing on + QPixmap *pm((QPixmap*)p->device()); + QPixmap pixmap; // icon + Task::Ptr task = 0; + bool iconified = !TaskBarSettings::showOnlyIconified(); + bool halo = TaskBarSettings::haloText(); + bool alwaysDrawButtons = TaskBarSettings::drawButtons(); + bool drawButton = alwaysDrawButtons || + (m_mouseOver && !halo && isEnabled() && + TaskBarSettings::showButtonOnHover()); + QFont font(KGlobalSettings::taskbarFont()); + + // draw sunken if we contain the active task + bool active = false; + bool demandsAttention = false; + Task::List::iterator itEnd = m_filteredTasks.end(); + for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it) + { + task = *it; + if (iconified && !task->isIconified()) + { + iconified = false; + } + + if (task->isActive()) + { + active = true; + } + + if (task->demandsAttention()) + { + demandsAttention = attentionState == TaskBarSettings::attentionBlinkIterations() || + attentionState % 2 == 0; + } + } + + font.setBold(active); + + QColorGroup colors = palette().active(); + + if (TaskBarSettings::useCustomColors()) + { + colors.setColor( QColorGroup::Button, TaskBarSettings::taskBackgroundColor()); + colors.setColor( QColorGroup::Background, TaskBarSettings::taskBackgroundColor() ); + colors.setColor( QColorGroup::ButtonText, TaskBarSettings::inactiveTaskTextColor() ); + colors.setColor( QColorGroup::Text, TaskBarSettings::inactiveTaskTextColor() ); + } + + if (demandsAttention) + { + if (!drawButton) + { + halo = true; + + QRect r = rect(); + QColor line = colors.highlight(); + r.addCoords(2, 2, -2, -2); + p->fillRect(r, line); + for (int i = 0; i < 2; ++i) + { + line = KickerLib::blendColors(line, colors.background()); + p->setPen(QPen(line, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + r.addCoords(-1, -1, 1, 1); + p->drawRect(r); + } + } + + // blink until blink timeout, then display differently without blinking + colors.setColor( QColorGroup::Button, colors.highlight() ); + colors.setColor( QColorGroup::Background, colors.highlight() ); + colors.setColor( QColorGroup::ButtonText, colors.highlightedText() ); + colors.setColor( QColorGroup::Text, colors.highlightedText() ); + } + + if (active || aboutToActivate) + { + colors.setColor(QColorGroup::Button, colors.button().dark(110)); + } + + // get the task icon + if (task) + { + pixmap = task->pixmap(); + } + + bool sunken = isDown() || (alwaysDrawButtons && (active || aboutToActivate)); + bool reverse = QApplication::reverseLayout(); + QRect br(style().subRect(QStyle::SR_PushButtonContents, this)); + QPoint shift = QPoint(style().pixelMetric(QStyle::PM_ButtonShiftHorizontal), + style().pixelMetric(QStyle::PM_ButtonShiftVertical)); + + // draw button background + if (drawButton) + { + style().drawPrimitive(QStyle::PE_HeaderSection, p, + QRect(0, 0, width(), height()), + colors); + } + + // shift button label on sunken buttons + if (sunken) + { + p->translate(shift.x(), shift.y()); + } + + if (taskBar->showIcon()) + { + if (pixmap.isNull() && m_startup) + { + pixmap = SmallIcon(m_startup->icon()); + } + + if ( !pixmap.isNull() ) + { + // make sure it is no larger than 16x16 + if ( pixmap.width() > 16 || pixmap.height() > 16 ) + { + QImage tmp = pixmap.convertToImage(); + pixmap.convertFromImage( tmp.smoothScale( 16, 16 ) ); + } + + // fade out the icon when minimized + if (iconified) + { + KIconEffect::semiTransparent( pixmap ); + } + + // draw icon + QRect pmr(0, 0, pixmap.width(), pixmap.height()); + pmr.moveCenter(iconRect.center()); + p->drawPixmap(pmr, pixmap); + } + } + + // find text + QString text = name(); + + // modified overlay + static QString modStr = "[" + i18n( "modified" ) + "]"; + int modStrPos = text.find( modStr ); + int textPos = ( taskBar->showIcon() && (!pixmap.isNull() || m_startup)) ? 2 + 16 + 2 : 0; + + if (modStrPos >= 0) + { + // +1 because we include a space after the closing brace. + text.remove(modStrPos, modStr.length() + 1); + QPixmap modPixmap = SmallIcon("modified"); + + // draw modified overlay + if (!modPixmap.isNull()) + { + QRect r = QStyle::visualRect(QRect(br.x() + textPos, + (height() - 16) / 2, 16, 16), + this); + + if (iconified) + { + KIconEffect::semiTransparent(modPixmap); + } + + p->drawPixmap(r, modPixmap); + textPos += 16 + 2; + } + } + + // draw text + if (!text.isEmpty()) + { + QRect tr = QStyle::visualRect(QRect(br.x() + textPos + 1, 0, + width() - textPos, height()), + this); + int textFlags = AlignVCenter | SingleLine; + textFlags |= reverse ? AlignRight : AlignLeft; + QPen textPen; + + // get the color for the text label + if (iconified) + { + textPen = QPen(KickerLib::blendColors(colors.button(), colors.buttonText())); + } + else if (!active) + { + textPen = QPen(colors.buttonText()); + } + else // hack for the dotNET style and others + { + if (TaskBarSettings::useCustomColors()) + { + textPen = QPen(TaskBarSettings::activeTaskTextColor()); + } + else + { + textPen = p->pen(); + } + } + + int availableWidth = width() - (br.x() * 2) - textPos; + if (m_filteredTasks.count() > 1) + { + availableWidth -= 8; + } + + if (QFontMetrics(font).width(text) > availableWidth) + { + // draw text into overlay pixmap + QPixmap tpm(*pm); + QPainter tp(&tpm); + + if (sunken) + { + tp.translate(shift.x(), shift.y()); + } + + tp.setFont(font); + tp.setPen(textPen); + + if (halo) + { + taskBar->textShadowEngine()->drawText(tp, tr, textFlags, text, size()); + } + else + { + tp.drawText(tr, textFlags, text); + } + + // blend text into background image + QImage img = pm->convertToImage(); + QImage timg = tpm.convertToImage(); + KImageEffect::blend(img, timg, *taskBar->blendGradient(size()), KImageEffect::Red); + pm->convertFromImage(img); + } + else + { + p->setFont(font); + p->setPen(textPen); + + if (halo) + { + taskBar->textShadowEngine()->drawText(*p, tr, textFlags, text, size()); + } + else + { + p->drawText(tr, textFlags, text); + } + } + } + + if (!frames.isEmpty() && m_startup && frames.at(currentFrame) != frames.end()) + { + QPixmap *anim = *frames.at(currentFrame); + + if (anim && !anim->isNull()) + { + // save the background for the other frames + bitBlt(&animBg, QPoint(0,0), pm, iconRect); + // draw the animation frame + bitBlt(pm, iconRect.x(), iconRect.y(), anim); + } + } + + if (sunken) + { + // Change the painter back so the arrow, etc gets drawn in the right location + p->translate(-shift.x(), -shift.y()); + } + + // draw popup arrow + if (m_filteredTasks.count() > 1) + { + QStyle::PrimitiveElement e = QStyle::PE_ArrowLeft; + + switch (arrowType) + { + case Qt::LeftArrow: e = QStyle::PE_ArrowLeft; break; + case Qt::RightArrow: e = QStyle::PE_ArrowRight; break; + case Qt::UpArrow: e = QStyle::PE_ArrowUp; break; + case Qt::DownArrow: e = QStyle::PE_ArrowDown; break; + } + + int flags = QStyle::Style_Enabled; + QRect ar = QStyle::visualRect(QRect(br.x() + br.width() - 8 - 2, + br.y(), 8, br.height()), this); + if (sunken) + { + flags |= QStyle::Style_Down; + } + + style().drawPrimitive(e, p, ar, colors, flags); + } + + // draw mouse over frame in transparent mode + if (m_mouseOver && halo) + KickerLib::drawBlendedRect(p, QRect(0, 0, width(), height()), colorGroup().foreground()); + + if (aboutToActivate) + { + aboutToActivate = false; + } +} + +QString TaskContainer::name() +{ + // default to container id + QString text; + + // single task -> use mainwindow caption + if (m_filteredTasks.count() == 1) + { + text = m_filteredTasks.first()->visibleName(); + } + else if (m_filteredTasks.count() > 1) + { + // multiple tasks -> use the common part of all captions + // if it is more descriptive than the class name + const QString match = m_filteredTasks.first()->visibleName(); + unsigned int maxLength = match.length(); + unsigned int i = 0; + bool stop = false; + + // what we do is find the right-most letter than the names do NOT have + // in common, and then use everything UP TO that as the name in the button + while (i < maxLength) + { + QChar check = match.at(i).lower(); + Task::List::iterator itEnd = m_filteredTasks.end(); + for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it) + { + // we're doing a lot of Utf8 -> QString conversions here + // by repeatedly calling visibleIconicName() =/ + if (check != (*it)->visibleName().at(i).lower()) + { + if (i > 0) + { + --i; + } + stop = true; + break; + } + } + + if (stop) + { + break; + } + + ++i; + } + + // strip trailing crap + while (i > 0 && !match.at(i).isLetterOrNumber()) + { + --i; + } + + // more descriptive than id()? + if (i > 0 && (i + 1) >= id().length()) + { + text = match.left(i + 1); + } + } + else if (m_startup && !m_startup->text().isEmpty()) + { + // fall back to startup name + text = m_startup->text(); + } + + if (text.isEmpty()) + { + text = id(); + + // Upper case first letter: seems to be the right thing to do for most cases + text[0] = text[0].upper(); + } + + if (m_filteredTasks.count() > 1) + { + // this is faster than (" [%1]").arg() or + + // and it's as fast as using append, but cleaner looking + text += " ["; + text += QString::number(m_filteredTasks.count()); + text += "]"; + } + + return text; +} + +void TaskContainer::mousePressEvent( QMouseEvent* e ) +{ + if (discardNextMouseEvent) + { + discardNextMouseEvent = false; + return; + } + + if (e->button() == LeftButton) + { + m_dragStartPos = e->pos(); + } + else + { + m_dragStartPos = QPoint(); + } + + int buttonAction = 0; + + // On left button, only do actions that invoke a menu. + // Other actions will be handled in mouseReleaseEvent + switch (e->button()) + { + case LeftButton: + buttonAction = TaskBarSettings::action(TaskBarSettings::LeftButton); + break; + case MidButton: + buttonAction = TaskBarSettings::action(TaskBarSettings::MiddleButton); + break; + case RightButton: + default: + buttonAction = TaskBarSettings::action(TaskBarSettings::RightButton); + break; + } + + if ((buttonAction == TaskBarSettings::ShowTaskList && + m_filteredTasks.count() > 1) || + buttonAction == TaskBarSettings::ShowOperationsMenu) + { + performAction(buttonAction); + } +} + +void TaskContainer::mouseReleaseEvent(QMouseEvent *e) +{ + m_dragStartPos = QPoint(); + + if (!TaskBarSettings::drawButtons()) + { + setDown(false); + } + + // This is to avoid the flicker caused by redrawing the + // button as unpressed just before it's activated. + if (!rect().contains(e->pos())) + { + QToolButton::mouseReleaseEvent(e); + return; + } + + int buttonAction = 0; + + switch (e->button()) + { + case LeftButton: + buttonAction = TaskBarSettings::action(TaskBarSettings::LeftButton); + break; + case MidButton: + buttonAction = TaskBarSettings::action(TaskBarSettings::MiddleButton); + break; + case RightButton: + default: + buttonAction = TaskBarSettings::action(TaskBarSettings::RightButton); + break; + } + + if ((buttonAction == TaskBarSettings::ShowTaskList && + m_filteredTasks.count() > 1) || + buttonAction == TaskBarSettings::ShowOperationsMenu) + { + return; + } + + if (buttonAction == TaskBarSettings::ActivateRaiseOrMinimize || + buttonAction == TaskBarSettings::Activate) + { + aboutToActivate = true; + } + + performAction( buttonAction ); + QTimer::singleShot(0, this, SLOT(update())); +} + +void TaskContainer::performAction(int action) +{ + if (m_filteredTasks.isEmpty()) + { + return; + } + + switch( action ) { + case TaskBarSettings::ShowTaskList: + // If there is only one task, the correct behavior is + // to activate, raise, or iconify it, not show the task menu. + if( m_filteredTasks.count() > 1 ) { + popupMenu( TaskBarSettings::ShowTaskList ); + } else { + performAction( TaskBarSettings::ActivateRaiseOrMinimize ); + } + break; + case TaskBarSettings::ShowOperationsMenu: + popupMenu( TaskBarSettings::ShowOperationsMenu ); + break; + case TaskBarSettings::ActivateRaiseOrMinimize: + if (m_filteredTasks.isEmpty()) + { + break; + } + if (m_filteredTasks.count() == 1) + { + m_filteredTasks.first()->activateRaiseOrIconify(); + } + else + { + // multiple tasks -> cycle list + bool hasLastActivated = false; + Task::List::iterator itEnd = m_filteredTasks.end(); + for (Task::List::iterator it = m_filteredTasks.begin(); it != itEnd; ++it) + { + if ((*it) == lastActivated) + { + hasLastActivated = true; + } + + if ((*it)->isActive()) + { + // activate next + ++it; + if (it == itEnd) + { + it = m_filteredTasks.begin(); + } + (*it)->activateRaiseOrIconify(); + return; + } + } + + if (hasLastActivated) + { + lastActivated->activateRaiseOrIconify(); + } + else + { + m_filteredTasks[0]->activateRaiseOrIconify(); + } + } + break; + case TaskBarSettings::Activate: + m_filteredTasks.first()->activate(); + break; + case TaskBarSettings::Raise: + m_filteredTasks.first()->raise(); + break; + case TaskBarSettings::Lower: + m_filteredTasks.first()->lower(); + break; + case TaskBarSettings::Minimize: + m_filteredTasks.first()->toggleIconified(); + break; + case TaskBarSettings::Close: + m_filteredTasks.first()->close(); + break; + case TaskBarSettings::ToCurrentDesktop: + m_filteredTasks.first()->toCurrentDesktop(); + break; + default: + kdWarning(1210) << "Unknown taskbar action!" << endl; + break; + } +} + +// forcenext == true means the last entry in the previous +// taskcontainer was active -> activate first +bool TaskContainer::activateNextTask(bool forward, bool& forcenext) +{ + if (forcenext) + { + if (m_filteredTasks.isEmpty()) + { + return false; + } + + if (forward) + { + m_filteredTasks.first()->activate(); + } + else + { + m_filteredTasks.last()->activate(); + } + + forcenext = false; + return true; + } + + Task::List::iterator itEnd = m_filteredTasks.end(); + for (Task::List::iterator it = m_filteredTasks.begin(); + it != itEnd; + ++it) + { + if ((*it)->isActive()) + { + if (forward) + { + ++it; + if (it == itEnd) + { + forcenext = true; + return false; + } + + (*it)->activate(); + return true; + } + else if (it == m_filteredTasks.begin()) + { + forcenext = true; + return false; + } + + --it; + (*it)->activate(); + return true; + } + } + + return false; +} + +void TaskContainer::popupMenu(int action) +{ + if (action == TaskBarSettings::ShowTaskList ) + { + m_menu = new TaskLMBMenu(m_filteredTasks); + } + else if (action == TaskBarSettings::ShowOperationsMenu) + { + if (!kapp->authorizeKAction("kwin_rmb")) + { + return; + } + + m_menu = new TaskRMBMenu(m_filteredTasks, taskBar->showAllWindows()); + } + else + { + return; + } + + // calc popup menu position + QPoint pos(mapToGlobal(QPoint(0, 0))); + + switch( arrowType ) + { + case RightArrow: + pos.setX(pos.x() + width()); + break; + case LeftArrow: + pos.setX(pos.x() - m_menu->sizeHint().width()); + break; + case DownArrow: + if ( QApplication::reverseLayout() ) + pos.setX( pos.x() + width() - m_menu->sizeHint().width() ); + pos.setY( pos.y() + height() ); + break; + case UpArrow: + if ( QApplication::reverseLayout() ) + pos.setX( pos.x() + width() - m_menu->sizeHint().width() ); + pos.setY(pos.y() - m_menu->sizeHint().height()); + break; + default: + break; + } + m_menu->installEventFilter( this ); + m_menu->exec( pos ); + + delete m_menu; + m_menu = 0; +} + +void TaskContainer::mouseMoveEvent( QMouseEvent* e ) +{ + kdDebug() << "regular move" << endl; + if (!m_dragStartPos.isNull()) + { + startDrag(e->pos()); + } + + QToolButton::mouseMoveEvent(e); +} + +bool TaskContainer::startDrag(const QPoint& pos) +{ + if (m_filteredTasks.count() != 1) + { + return false; + } + + int delay = KGlobalSettings::dndEventDelay(); + + if ((m_dragStartPos - pos).manhattanLength() > delay) + { + if (!m_filteredTasks.first()->isActive()) + { + setDown(false); + } + + TaskDrag* drag = new TaskDrag(m_filteredTasks, this); + + if (!m_filteredTasks.isEmpty()) + { + kdDebug() << m_filteredTasks.first()->name() << endl; + drag->setPixmap(m_filteredTasks.first()->pixmap()); + } + + drag->dragMove(); + return true; + } + + return false; +} + +// This is the code that gives us the proper behavior +// when a popup menu is displayed and we are clicked: +// close the menu, and don't reopen it immediately. +// It's copied from QToolButton. Unfortunately Qt is lame +// as usual and makes interesting stuff private or +// non-virtual, so we have to copy code. +bool TaskContainer::eventFilter(QObject *o, QEvent *e) +{ + switch ( e->type() ) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + { + QMouseEvent *me = (QMouseEvent*)e; + QPoint p = me->globalPos(); + if ( QApplication::widgetAt( p, true ) == this ) + { + if (me->type() == QEvent::MouseButtonPress && + me->button() == LeftButton) + { + m_dragStartPos = mapFromGlobal(p); + } + + discardNextMouseEvent = true; + } + break; + } + case QEvent::MouseButtonRelease: + { + m_dragStartPos = QPoint(); + break; + } + case QEvent::MouseMove: + { + if (!m_dragStartPos.isNull()) + { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + QPoint p(me->globalPos()); + + if (me->state() & LeftButton && + QApplication::widgetAt(p, true) == this) + { + kdDebug() << "event move" << endl; + if (startDrag(mapFromGlobal(p))) + { + QPopupMenu* menu = dynamic_cast<QPopupMenu*>(o); + + if (menu) + { + menu->hide(); + } + } + } + } + break; + } + + default: + break; + } + + return QToolButton::eventFilter( o, e ); +} + +void TaskContainer::setArrowType( Qt::ArrowType at ) +{ + if (arrowType == at) + { + return; + } + + arrowType = at; + update(); +} + +void TaskContainer::publishIconGeometry( QPoint global ) +{ + QPoint p = global + geometry().topLeft(); + + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + t->publishIconGeometry(QRect(p.x(), p.y(), width(), height())); + } +} + +void TaskContainer::dragEnterEvent( QDragEnterEvent* e ) +{ + // ignore task drags and applet drags + if (TaskDrag::canDecode(e) || PanelDrag::canDecode(e)) + { + return; + } + + // if a dragitem is held for over a taskbutton for two seconds, + // activate corresponding window + if (m_filteredTasks.isEmpty()) + { + return; + } + + if (!m_filteredTasks.first()->isActive() || + m_filteredTasks.count() > 1) + { + dragSwitchTimer.start(1000, true); + } + + QToolButton::dragEnterEvent( e ); +} + +void TaskContainer::dragLeaveEvent( QDragLeaveEvent* e ) +{ + dragSwitchTimer.stop(); + + QToolButton::dragLeaveEvent( e ); +} + +void TaskContainer::enterEvent(QEvent* e) +{ + QToolTip::remove(this); + m_mouseOver = true; + updateNow(); + + if (tasks.isEmpty()) + { + QToolButton::enterEvent(e); + return; + } + + if (!KickerSettings::showMouseOverEffects()) + { + QString tooltip = "<qt>" + QStyleSheet::escape(name()) + "</qt>"; + QToolTip::add(this, tooltip); + return; + } +} + +void TaskContainer::leaveEvent(QEvent*) +{ + m_mouseOver = false; + updateNow(); +} + +void TaskContainer::dragSwitch() +{ + if (m_filteredTasks.isEmpty()) + { + return; + } + + if (m_filteredTasks.count() == 1) + { + m_filteredTasks.first()->activate(); + } + else + { + popupMenu(TaskBarSettings::ShowTaskList); + } +} + +int TaskContainer::desktop() +{ + if ( tasks.isEmpty() ) + return TaskManager::the()->currentDesktop(); + + if ( tasks.count() > 1 ) + return TaskManager::the()->numberOfDesktops(); + + return tasks.first()->desktop(); +} + +bool TaskContainer::onCurrentDesktop() +{ + if (m_startup) + { + return true; + } + + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + if (t->isOnCurrentDesktop()) + { + return true; + } + } + + return false; +} + +bool TaskContainer::isOnScreen() +{ + if (isEmpty()) + { + return false; + } + + int screen = taskBar->showScreen(); + if ((tasks.isEmpty() && m_startup) || screen == -1) + { + return true; + } + + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if ((*it)->isOnScreen( screen )) + { + return true; + } + } + + return false; +} + +bool TaskContainer::isIconified() +{ + if (isEmpty()) + { + return false; + } + + if (tasks.isEmpty() && m_startup) + { + return true; + } + + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + if ((*it)->isIconified()) + { + return true; + } + } + + return false; +} + +void TaskContainer::updateFilteredTaskList() +{ + m_filteredTasks.clear(); + + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + if ((taskBar->showAllWindows() || t->isOnCurrentDesktop()) && + (!TaskBarSettings::showOnlyIconified() || t->isIconified())) + { + m_filteredTasks.append(t); + } + else + { + t->publishIconGeometry( QRect()); + } + } + + // sort container list by desktop + if (taskBar->sortByDesktop() && m_filteredTasks.count() > 1) + { + QValueVector<QPair<int, Task::Ptr> > sorted; + sorted.resize(m_filteredTasks.count()); + int i = 0; + + Task::List::const_iterator itEnd = m_filteredTasks.constEnd(); + for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + sorted[i] = (qMakePair(t->desktop(), t)); + ++i; + } + + qHeapSort(sorted); + + m_filteredTasks.clear(); + for (QValueVector<QPair<int, Task::Ptr> >::iterator it = sorted.begin(); + it != sorted.end(); + ++it) + { + m_filteredTasks.append((*it).second); + } + } +} + +void TaskContainer::desktopChanged(int) +{ + updateFilteredTaskList(); + KickerTip::Client::updateKickerTip(); + update(); +} + +void TaskContainer::windowChanged(Task::Ptr) +{ + updateFilteredTaskList(); + KickerTip::Client::updateKickerTip(); + update(); +} + +void TaskContainer::settingsChanged() +{ + updateFilteredTaskList(); + KickerTip::Client::updateKickerTip(); + update(); +} + +void TaskContainer::updateKickerTip(KickerTip::Data& data) +{ + if (m_startup) + { + data.message = m_startup->text(); + data.duration = 4000; + data.subtext = i18n("Loading application ..."); + data.icon = KGlobal::iconLoader()->loadIcon(m_startup->icon(), + KIcon::Small, + KIcon::SizeMedium, + KIcon::DefaultState, + 0, true); + return; + } + + QPixmap pixmap; + QString name; + QString details; + + if (m_filteredTasks.count() > 0) + { + if (TaskBarSettings::showThumbnails() && + m_filteredTasks.count() == 1) + { + Task::Ptr t = m_filteredTasks.first(); + + pixmap = t->thumbnail(TaskBarSettings::thumbnailMaxDimension()); + } + + if (pixmap.isNull() && tasks.count()) + { + // try to load icon via net_wm + pixmap = KWin::icon(tasks.last()->window(), + KIcon::SizeMedium, + KIcon::SizeMedium, + true); + } + + // Collect all desktops the tasks are on. Sort naturally. + QMap<int, QString> desktopMap; + bool demandsAttention = false; + bool modified = false; + bool allDesktops = false; + Task::List::const_iterator itEnd = m_filteredTasks.constEnd(); + for (Task::List::const_iterator it = m_filteredTasks.constBegin(); it != itEnd; ++it) + { + Task::Ptr t = *it; + if (t->demandsAttention()) + { + demandsAttention = true; + } + + if (t->isModified()) + { + modified = true; + } + + if (t->isOnAllDesktops()) + { + allDesktops = true; + desktopMap.clear(); + } + else if (!allDesktops) + { + desktopMap.insert(t->desktop(), + TaskManager::the()->desktopName(t->desktop())); + } + } + + if (TaskBarSettings::showAllWindows() && KWin::numberOfDesktops() > 1) + { + if (desktopMap.isEmpty()) + { + details.append(i18n("On all desktops")); + } + else + { + QStringList desktopNames = desktopMap.values(); + details.append(i18n("On %1").arg(QStyleSheet::escape(desktopNames.join(", "))) + "<br>"); + } + } + + if (demandsAttention) + { + details.append(i18n("Requesting attention") + "<br>"); + } + + name = this->name(); + if (modified) + { + details.append(i18n("Has unsaved changes")); + + static QString modStr = "[" + i18n( "modified" ) + "]"; + int modStrPos = name.find(modStr); + + if (modStrPos >= 0) + { + // +1 because we include a space after the closing brace. + name.remove(modStrPos, modStr.length() + 1); + } + } + } + + data.message = QStyleSheet::escape(name); + data.subtext = details; + data.icon = pixmap; + data.direction = KickerLib::arrowToDirection(arrowType); +} + +void TaskContainer::finish() +{ + // Disconnect all signal/slot connections to avoid triggering a popupMenu() call, + // whose event loop is the root of all (or at least much) evil. + // Unfortunately, we can't just do "disconnect()", because that gets us a bunch + // of dangling QGuardedPtr objects (most notably in QTipManager.) (kling) + + animationTimer.disconnect(); + dragSwitchTimer.disconnect(); + attentionTimer.disconnect(); + + if (m_startup) + m_startup->disconnect(this); + + for (Task::List::Iterator it = tasks.begin(); it != tasks.end(); ++it) + { + (*it)->disconnect(this); + } + + if (m_menu) + m_menu->close(); +} diff --git a/kicker/taskbar/taskcontainer.h b/kicker/taskbar/taskcontainer.h new file mode 100644 index 000000000..4328c36d4 --- /dev/null +++ b/kicker/taskbar/taskcontainer.h @@ -0,0 +1,153 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskcontainer_h__ +#define __taskcontainer_h__ + +#include <qpixmap.h> +#include <qtimer.h> +#include <qtoolbutton.h> + +#include "kickertip.h" +#include "taskmanager.h" + +class TaskBar; + +typedef QValueList<QPixmap*> PixmapList; + +class TaskContainer : public QToolButton, public KickerTip::Client +{ + Q_OBJECT + +public: + typedef QValueList<TaskContainer*> List; + typedef QValueList<TaskContainer*>::iterator Iterator; + + TaskContainer(Task::Ptr, TaskBar*, QWidget *parent = 0, const char *name = 0); + TaskContainer(Startup::Ptr, PixmapList&, TaskBar*, + QWidget *parent = 0, const char *name = 0); + virtual ~TaskContainer(); + + void setArrowType( Qt::ArrowType at ); + + void init(); + + void add(Task::Ptr); + void remove(Task::Ptr); + void remove(Startup::Ptr); + + bool contains(Task::Ptr); + bool contains(Startup::Ptr); + bool contains(WId); + + bool isEmpty(); + bool onCurrentDesktop(); + bool isIconified(); + bool isOnScreen(); + + QString id(); + int desktop(); + QString name(); + + virtual QSizePolicy sizePolicy () const; + + void publishIconGeometry( QPoint ); + void desktopChanged( int ); + void windowChanged(Task::Ptr); + void settingsChanged(); + bool eventFilter( QObject *o, QEvent *e ); + + int taskCount() const { return tasks.count(); } + int filteredTaskCount() const { return m_filteredTasks.count(); } + + bool activateNextTask( bool forward, bool& forcenext ); + + void updateKickerTip(KickerTip::Data&); + + void finish(); + + void setBackground(); + +public slots: + void updateNow(); + +signals: + void showMe(TaskContainer*); + +protected: + void paintEvent(QPaintEvent*); + void drawButton(QPainter*); + void resizeEvent(QResizeEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void dragEnterEvent(QDragEnterEvent*); + void dragLeaveEvent(QDragLeaveEvent*); + void enterEvent(QEvent*); + void leaveEvent(QEvent*); + bool startDrag(const QPoint& pos); + void stopTimers(); + + void performAction(int); + void popupMenu(int); + + void updateFilteredTaskList(); + +protected slots: + void animationTimerFired(); + void attentionTimerFired(); + void dragSwitch(); + void iconChanged(); + void setLastActivated(); + void taskChanged(bool geometryChangeOnly); + void showMe(); + +private: + void checkAttention(const Task::Ptr changed_task = NULL); + QString sid; + QTimer animationTimer; + QTimer dragSwitchTimer; + QTimer attentionTimer; + QTimer m_paintEventCompressionTimer; + int currentFrame; + PixmapList frames; + int attentionState; + QRect iconRect; + QPixmap animBg; + Task::List tasks; + Task::List m_filteredTasks; + Task::Ptr lastActivated; + QPopupMenu* m_menu; + Startup::Ptr m_startup; + ArrowType arrowType; + TaskBar* taskBar; + bool discardNextMouseEvent; + bool aboutToActivate; + bool m_mouseOver; + bool m_paintEventCompression; + enum { ATTENTION_BLINK_TIMEOUT = 4 }; + QPoint m_dragStartPos; +}; + +#endif diff --git a/kicker/taskmanager/Makefile.am b/kicker/taskmanager/Makefile.am new file mode 100644 index 000000000..ffe7912e7 --- /dev/null +++ b/kicker/taskmanager/Makefile.am @@ -0,0 +1,11 @@ +INCLUDES = $(all_includes) -I$(srcdir)/../libkicker + +lib_LTLIBRARIES = libtaskmanager.la +libtaskmanager_la_SOURCES = tasklmbmenu.cpp taskrmbmenu.cpp taskmanager.cpp +libtaskmanager_la_METASOURCES = AUTO + +libtaskmanager_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined +libtaskmanager_la_LIBADD = $(LIB_KDECORE) $(LIB_XFIXES) $(LIB_XRENDER) $(LIB_XCOMPOSITE) ../libkicker/libkickermain.la + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/libtaskmanager.pot diff --git a/kicker/taskmanager/configure.in.in b/kicker/taskmanager/configure.in.in new file mode 100644 index 000000000..0ee479dde --- /dev/null +++ b/kicker/taskmanager/configure.in.in @@ -0,0 +1,25 @@ +if test "x$with_composite" != "xno"; then + dnl XComposite check + KDE_CHECK_HEADER(X11/extensions/Xcomposite.h, [xcomposite_h=yes], [xcomposite_h=no], [#include <X11/Xlib.h>]) + if test "$xcomposite_h" = yes; then + KDE_CHECK_LIB(Xcomposite, XCompositeQueryExtension, [ + LIB_XCOMPOSITE=-lXcomposite + AC_DEFINE_UNQUOTED(HAVE_XCOMPOSITE, 1, [Define if you have the XComposite extension]) + ], [], -lXext -lX11 $X_EXTRA_LIBS) + else + LIB_XCOMPOSITE= + fi + AC_SUBST(LIB_XCOMPOSITE) +fi + +dnl XFixes check +KDE_CHECK_HEADER(X11/extensions/Xfixes.h, [xfixes_h=yes], [xfixes_h=no], [#include <X11/Xlib.h>]) +if test "$xfixes_h" = yes; then + KDE_CHECK_LIB(Xfixes, XFixesQueryExtension, [ + LIB_XFIXES=-lXfixes + AC_DEFINE_UNQUOTED(HAVE_XFIXES, 1, [Define if you have the XFixes extension]) + ], [], -lXext -lX11 $X_EXTRA_LIBS) +else + LIB_XFIXES= +fi +AC_SUBST(LIB_XFIXES) diff --git a/kicker/taskmanager/tasklmbmenu.cpp b/kicker/taskmanager/tasklmbmenu.cpp new file mode 100644 index 000000000..03278c0fe --- /dev/null +++ b/kicker/taskmanager/tasklmbmenu.cpp @@ -0,0 +1,281 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "tasklmbmenu.h" +#include "tasklmbmenu.moc" + +#include <qpainter.h> +#include <qstyle.h> + +#include <kdebug.h> +#include <kglobalsettings.h> + +#include "global.h" + +TaskMenuItem::TaskMenuItem(const QString &text, + bool active, bool minimized, bool attention) + : QCustomMenuItem(), + m_text(text), + m_isActive(active), + m_isMinimized(minimized), + m_demandsAttention(attention), + m_attentionState(true) +{ +} + +TaskMenuItem::~TaskMenuItem() +{ +} + +void TaskMenuItem::paint(QPainter *p, const QColorGroup &cg, + bool highlighted, bool /*enabled*/, + int x, int y, int w, int h ) +{ + if (m_isActive) + { + QFont font = p->font(); + font.setBold(true); + p->setFont(font); + } + + if (highlighted) + { + p->setPen(cg.highlightedText()); + } + else if (m_isMinimized) + { + p->setPen(QPen(KickerLib::blendColors(cg.background(), cg.text()))); + } + else if (m_demandsAttention && !m_attentionState) + { + p->setPen(cg.mid()); + } + + p->drawText(x, y, w, h, AlignAuto|AlignVCenter|DontClip|ShowPrefix, m_text); +} + +QSize TaskMenuItem::sizeHint() +{ + QFont font = QFont(); + if (m_isActive) + { + font.setBold(true); + } + return QFontMetrics(font).size(AlignAuto|AlignVCenter|DontClip|ShowPrefix, + m_text); +} + +/*****************************************************************************/ + +TaskLMBMenu::TaskLMBMenu(const Task::List& tasks, QWidget *parent, const char *name) + : QPopupMenu(parent, name), + m_tasks(tasks), + m_lastDragId(-1), + m_attentionState(false) +{ + fillMenu(); + + setAcceptDrops(true); // Always enabled to activate task during drag&drop. + + m_dragSwitchTimer = new QTimer(this, "DragSwitchTimer"); + connect(m_dragSwitchTimer, SIGNAL(timeout()), SLOT(dragSwitch())); +} + +void TaskLMBMenu::fillMenu() +{ + setCheckable(true); + + Task::List::iterator itEnd = m_tasks.end(); + for (Task::List::iterator it = m_tasks.begin(); it != itEnd; ++it) + { + Task::Ptr t = (*it); + + QString text = t->visibleName().replace("&", "&&"); + + TaskMenuItem *menuItem = new TaskMenuItem(text, + t->isActive(), + t->isIconified(), + t->demandsAttention()); + int id = insertItem(QIconSet(t->pixmap()), menuItem); + connectItem(id, t, SLOT(activateRaiseOrIconify())); + setItemChecked(id, t->isActive()); + + if (t->demandsAttention()) + { + m_attentionState = true; + m_attentionMap.append(menuItem); + } + } + + if (m_attentionState) + { + m_attentionTimer = new QTimer(this, "AttentionTimer"); + connect(m_attentionTimer, SIGNAL(timeout()), SLOT(attentionTimeout())); + m_attentionTimer->start(500, true); + } +} + +void TaskLMBMenu::attentionTimeout() +{ + m_attentionState = !m_attentionState; + + for (QValueList<TaskMenuItem*>::const_iterator it = m_attentionMap.constBegin(); + it != m_attentionMap.constEnd(); + ++it) + { + (*it)->setAttentionState(m_attentionState); + } + + update(); + + m_attentionTimer->start(500, true); +} + +void TaskLMBMenu::dragEnterEvent( QDragEnterEvent* e ) +{ + // ignore task drags + if (TaskDrag::canDecode(e)) + { + return; + } + + int id = idAt(e->pos()); + + if (id == -1) + { + m_dragSwitchTimer->stop(); + m_lastDragId = -1; + } + else if (id != m_lastDragId) + { + m_lastDragId = id; + m_dragSwitchTimer->start(1000, true); + } + + QPopupMenu::dragEnterEvent( e ); +} + +void TaskLMBMenu::dragLeaveEvent( QDragLeaveEvent* e ) +{ + m_dragSwitchTimer->stop(); + m_lastDragId = -1; + + QPopupMenu::dragLeaveEvent(e); + + hide(); +} + +void TaskLMBMenu::dragMoveEvent( QDragMoveEvent* e ) +{ + // ignore task drags + if (TaskDrag::canDecode(e)) + { + return; + } + + int id = idAt(e->pos()); + + if (id == -1) + { + m_dragSwitchTimer->stop(); + m_lastDragId = -1; + } + else if (id != m_lastDragId) + { + m_lastDragId = id; + m_dragSwitchTimer->start(1000, true); + } + + QPopupMenu::dragMoveEvent(e); +} + +void TaskLMBMenu::dragSwitch() +{ + bool ok = false; + Task::Ptr t = m_tasks.at(indexOf(m_lastDragId), &ok); + if (ok) + { + t->activate(); + + for (unsigned int i = 0; i < count(); ++i) + { + setItemChecked(idAt(i), false ); + } + + setItemChecked( m_lastDragId, true ); + } +} + +void TaskLMBMenu::mousePressEvent( QMouseEvent* e ) +{ + if (e->button() == LeftButton) + { + m_dragStartPos = e->pos(); + } + else + { + m_dragStartPos = QPoint(); + } + + QPopupMenu::mousePressEvent(e); +} + +void TaskLMBMenu::mouseReleaseEvent(QMouseEvent* e) +{ + m_dragStartPos = QPoint(); + QPopupMenu::mouseReleaseEvent(e); +} + +void TaskLMBMenu::mouseMoveEvent(QMouseEvent* e) +{ + if (m_dragStartPos.isNull()) + { + QPopupMenu::mouseMoveEvent(e); + return; + } + + int delay = KGlobalSettings::dndEventDelay(); + QPoint newPos(e->pos()); + + if ((m_dragStartPos - newPos).manhattanLength() > delay) + { + int index = indexOf(idAt(m_dragStartPos)); + if (index != -1) + { + bool ok = false; + Task::Ptr task = m_tasks.at(index, &ok); + if (ok) + { + Task::List tasks; + tasks.append(task); + TaskDrag* drag = new TaskDrag(tasks, this); + drag->setPixmap(task->pixmap()); + drag->dragMove(); + } + } + } + + QPopupMenu::mouseMoveEvent(e); +} + diff --git a/kicker/taskmanager/tasklmbmenu.h b/kicker/taskmanager/tasklmbmenu.h new file mode 100644 index 000000000..945c3e649 --- /dev/null +++ b/kicker/taskmanager/tasklmbmenu.h @@ -0,0 +1,85 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2002 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __tasklmbmenu_h__ +#define __tasklmbmenu_h__ + +#include <qpopupmenu.h> +#include <qtimer.h> + +#include "taskmanager.h" + +class TaskMenuItem : public QCustomMenuItem +{ +public: + TaskMenuItem(const QString &text, + bool active, bool minimized, bool attention); + ~TaskMenuItem(); + + void paint(QPainter*, const QColorGroup&, bool, bool, int, int, int, int); + QSize sizeHint(); + void setAttentionState(bool state) { m_attentionState = state; } + +private: + QString m_text; + bool m_isActive; + bool m_isMinimized; + bool m_demandsAttention; + bool m_attentionState; +}; + +/*****************************************************************************/ + +class KDE_EXPORT TaskLMBMenu : public QPopupMenu +{ + Q_OBJECT + +public: + TaskLMBMenu(const Task::List& list, QWidget *parent = 0, const char *name = 0); + +protected slots: + void dragSwitch(); + void attentionTimeout(); + +protected: + void dragEnterEvent(QDragEnterEvent*); + void dragLeaveEvent(QDragLeaveEvent*); + void dragMoveEvent(QDragMoveEvent*); + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + +private: + void fillMenu(); + + Task::List m_tasks; + int m_lastDragId; + bool m_attentionState; + QTimer* m_attentionTimer; + QTimer* m_dragSwitchTimer; + QPoint m_dragStartPos; + QValueList<TaskMenuItem*> m_attentionMap; +}; + +#endif diff --git a/kicker/taskmanager/taskmanager.cpp b/kicker/taskmanager/taskmanager.cpp new file mode 100644 index 000000000..dd9364c0e --- /dev/null +++ b/kicker/taskmanager/taskmanager.cpp @@ -0,0 +1,1521 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qcursor.h> +#include <qimage.h> +#include <qtimer.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +// #include <kpixmapio.h> +#include <kstaticdeleter.h> +#include <kwinmodule.h> +#include <kxerrorhandler.h> +#include <netwm.h> + +#include "taskmanager.h" +#include "taskmanager.moc" + +TaskManager* TaskManager::m_self = 0; +static KStaticDeleter<TaskManager> staticTaskManagerDeleter; +uint TaskManager::m_xCompositeEnabled = 0; + +TaskManager* TaskManager::the() +{ + if (!m_self) + { + staticTaskManagerDeleter.setObject(m_self, new TaskManager()); + } + return m_self; +} + +TaskManager::TaskManager() + : QObject(), + _active(0), + _startup_info(0), + m_winModule(new KWinModule()), + m_trackGeometry(false) +{ + KGlobal::locale()->insertCatalogue("libtaskmanager"); + connect(m_winModule, SIGNAL(windowAdded(WId)), + this, SLOT(windowAdded(WId))); + connect(m_winModule, SIGNAL(windowRemoved(WId)), + this, SLOT(windowRemoved(WId))); + connect(m_winModule, SIGNAL(activeWindowChanged(WId)), + this, SLOT(activeWindowChanged(WId))); + connect(m_winModule, SIGNAL(currentDesktopChanged(int)), + this, SLOT(currentDesktopChanged(int))); + connect(m_winModule, SIGNAL(windowChanged(WId,unsigned int)), + this, SLOT(windowChanged(WId,unsigned int))); + + // register existing windows + const QValueList<WId> windows = m_winModule->windows(); + QValueList<WId>::ConstIterator end(windows.end()); + for (QValueList<WId>::ConstIterator it = windows.begin(); it != end; ++it) + { + windowAdded(*it); + } + + // set active window + WId win = m_winModule->activeWindow(); + activeWindowChanged(win); + configure_startup(); +} + +TaskManager::~TaskManager() +{ + KGlobal::locale()->removeCatalogue("libtaskmanager"); +} + +void TaskManager::configure_startup() +{ + KConfig c("klaunchrc", true); + c.setGroup("FeedbackStyle"); + if (!c.readBoolEntry("TaskbarButton", true)) + return; + _startup_info = new KStartupInfo( KStartupInfo::CleanOnCantDetect, this ); + connect( _startup_info, + SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )), + SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& ))); + connect( _startup_info, + SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )), + SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& ))); + connect( _startup_info, + SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )), + SLOT( killStartup( const KStartupInfoId& ))); + c.setGroup( "TaskbarButtonSettings" ); + _startup_info->setTimeout( c.readUnsignedNumEntry( "Timeout", 30 )); +} + +#ifdef THUMBNAILING_POSSIBLE +void TaskManager::setXCompositeEnabled(bool state) +{ + Display *dpy = QPaintDevice::x11AppDisplay(); + + if (!state) + { + if (!--m_xCompositeEnabled) + { + // unredirecting windows + for (int i = 0; i < ScreenCount(dpy); i++) + { + XCompositeUnredirectSubwindows(dpy, RootWindow(dpy, i), + CompositeRedirectAutomatic); + } + } + return; + } + + if (m_xCompositeEnabled) + { + // we don't unlearn riding bike ;) + m_xCompositeEnabled++; + return; + } + + // XComposite extension check + int event_base, error_base; + if (!XCompositeQueryExtension(dpy, &event_base, &error_base)) + { + return; + } + + int major = 0, minor = 99; // The highest version we support + XCompositeQueryVersion(dpy, &major, &minor); + + // We use XCompositeNameWindowPixmap(), i.e. we need at least + // version 0.2. + if (major == 0 && minor < 2) + { + return; + } + + // XRender extension check + if (!XRenderQueryExtension(dpy, &event_base, &error_base)) + { + return; + } + + major = 0, minor = 99; // The highest version we support + XRenderQueryVersion(dpy, &major, &minor); + + // We use SetPictureTransform() and SetPictureFilter(), i.e. we + // need at least version 0.6. + if (major == 0 && minor < 6) + { + return; + } + + // XFixes extension check + if (!XFixesQueryExtension(dpy, &event_base, &error_base)) + { + return; + } + + major = 3, minor = 99; // The highest version we support + XFixesQueryVersion(dpy, &major, &minor); + + // We use Region objects, i.e. we need at least version 2.0. + if (major < 2) + { + return; + } + + // if we get here, we've got usable extensions + m_xCompositeEnabled++; + + // redirecting windows to backing pixmaps + for (int i = 0; i < ScreenCount(dpy); i++) + { + XCompositeRedirectSubwindows(dpy, RootWindow(dpy, i), + CompositeRedirectAutomatic); + } + + Task::Dict::iterator itEnd = m_tasksByWId.end(); + for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it) + { + it.data()->updateWindowPixmap(); + } +} +#else // THUMBNAILING_POSSIBLE +void TaskManager::setXCompositeEnabled(bool) +{ +} +#endif // !THUMBNAILING_POSSIBLE + +Task::Ptr TaskManager::findTask(WId w) +{ + // TODO: might be able to be made more efficient if + // we check to see if w is a transient first? + // profiling would say whether this is worth the effort + + Task::Dict::iterator it = m_tasksByWId.begin(); + Task::Dict::iterator itEnd = m_tasksByWId.end(); + + for (; it != itEnd; ++it) + { + if (it.key() == w || it.data()->hasTransient(w)) + { + return it.data(); + } + } + + return 0; +} + +Task::Ptr TaskManager::findTask(int desktop, const QPoint& p) +{ + QValueList<WId> list = winModule()->stackingOrder(); + + Task::Ptr task = 0; + int currentIndex = -1; + Task::Dict::iterator itEnd = m_tasksByWId.end(); + for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it) + { + Task::Ptr t = it.data(); + if (!t->isOnAllDesktops() && t->desktop() != desktop) + { + continue; + } + + if (t->isIconified() || t->isShaded()) + { + continue; + } + + if (t->geometry().contains(p)) + { + int index = list.findIndex(t->window()); + if (index > currentIndex) + { + currentIndex = index; + task = t; + } + } + } + + return task; +} + +void TaskManager::windowAdded(WId w ) +{ + NETWinInfo info(qt_xdisplay(), w, qt_xrootwin(), + NET::WMWindowType | NET::WMPid | NET::WMState); + + // ignore NET::Tool and other special window types + NET::WindowType wType = + info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask | + NET::ToolbarMask | NET::MenuMask | NET::DialogMask | + NET::OverrideMask | NET::TopMenuMask | + NET::UtilityMask | NET::SplashMask ); + + if (wType != NET::Normal && + wType != NET::Override && + wType != NET::Unknown && + wType != NET::Dialog && + wType != NET::Utility) + { + return; + } + + // ignore windows that want to be ignored by the taskbar + if ((info.state() & NET::SkipTaskbar) != 0) + { + _skiptaskbar_windows.push_front( w ); // remember them though + return; + } + + Window transient_for_tmp; + if (XGetTransientForHint( qt_xdisplay(), (Window) w, &transient_for_tmp )) + { + WId transient_for = (WId) transient_for_tmp; + + // check if it's transient for a skiptaskbar window + if( _skiptaskbar_windows.contains( transient_for )) + return; + + // lets see if this is a transient for an existing task + if( transient_for != qt_xrootwin() + && transient_for != 0 + && wType != NET::Utility ) + { + Task::Ptr t = findTask(transient_for); + if (t) + { + if (t->window() != w) + { + t->addTransient(w, info); + // kdDebug() << "TM: Transient " << w << " added for Task: " << t->window() << endl; + } + return; + } + } + } + + Task::Ptr t = new Task(w, this); + m_tasksByWId[w] = t; + + // kdDebug() << "TM: Task added for WId: " << w << endl; + + emit taskAdded(t); +} + +void TaskManager::windowRemoved(WId w) +{ + _skiptaskbar_windows.remove(w); + + // find task + Task::Ptr t = findTask(w); + if (!t) + { + return; + } + + if (t->window() == w) + { + m_tasksByWId.remove(w); + emit taskRemoved(t); + + if (t == _active) + { + _active = 0; + } + + //kdDebug() << "TM: Task for WId " << w << " removed." << endl; + } + else + { + t->removeTransient(w); + //kdDebug() << "TM: Transient " << w << " for Task " << t->window() << " removed." << endl; + } +} + +void TaskManager::windowChanged(WId w, unsigned int dirty) +{ + if (dirty & NET::WMState) + { + NETWinInfo info (qt_xdisplay(), w, qt_xrootwin(), + NET::WMState | NET::XAWMState); + if (info.state() & NET::SkipTaskbar) + { + windowRemoved(w); + _skiptaskbar_windows.push_front(w); + return; + } + else + { + _skiptaskbar_windows.remove(w); + if (info.mappingState() != NET::Withdrawn && !findTask(w)) + { + // skipTaskBar state was removed and the window is still + // mapped, so add this window + windowAdded( w ); + } + } + } + + // check if any state we are interested in is marked dirty + if (!(dirty & (NET::WMVisibleName | NET::WMName | NET::WMIcon | + NET::WMState | NET::XAWMState | NET::WMDesktop) || + (m_trackGeometry && dirty & NET::WMGeometry))) + { + return; + } + + // find task + Task::Ptr t = findTask(w); + if (!t) + { + return; + } + + //kdDebug() << "TaskManager::windowChanged " << w << " " << dirty << endl; + + if (dirty & NET::WMState) + { + t->updateDemandsAttentionState(w); + } + + // refresh icon pixmap if necessary + if (dirty & NET::WMIcon) + { + t->refreshIcon(); + + // we're done with the icon processing, don't pass this on anymore + dirty ^= NET::WMIcon; + } + + if (dirty) + { + // only refresh this stuff if we have other changes besides icons + t->refresh(dirty); + } + + if (dirty & (NET::WMDesktop | NET::WMState | NET::XAWMState)) + { + // moved to different desktop or is on all or change in iconification/withdrawnnes + emit windowChanged(t); + + if (m_xCompositeEnabled && dirty & NET::WMState) + { + // update on restoring a minimized window + updateWindowPixmap(w); + } + + } + else if (dirty & NET::WMGeometry) + { + emit windowChangedGeometry(t); + + if (m_xCompositeEnabled) + { + // update on size changes, not on task drags + updateWindowPixmap(w); + } + + } +} + +void TaskManager::updateWindowPixmap(WId w) +{ + if (!m_xCompositeEnabled) + { + return; + } + + Task::Ptr task = findTask(w); + if (task) + { + task->updateWindowPixmap(); + } +} + +void TaskManager::activeWindowChanged(WId w ) +{ + //kdDebug() << "TaskManager::activeWindowChanged" << endl; + + Task::Ptr t = findTask( w ); + if (!t) { + if (_active) { + _active->setActive(false); + _active = 0; + } + } + else { + if (_active) + _active->setActive(false); + + _active = t; + _active->setActive(true); + } +} + +void TaskManager::currentDesktopChanged(int desktop) +{ + emit desktopChanged(desktop); +} + +void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data ) +{ + Startup::Ptr s = new Startup( id, data, this ); + _startups.append(s); + + emit startupAdded(s); +} + +void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data ) +{ + Startup::List::iterator itEnd = _startups.end(); + for (Startup::List::iterator sIt = _startups.begin(); sIt != itEnd; ++sIt) + { + if ((*sIt)->id() == id) + { + (*sIt)->update(data); + return; + } + } +} + +void TaskManager::killStartup( const KStartupInfoId& id ) +{ + Startup::List::iterator sIt = _startups.begin(); + Startup::List::iterator itEnd = _startups.end(); + Startup::Ptr s = 0; + for (; sIt != itEnd; ++sIt) + { + if ((*sIt)->id() == id) + { + s = *sIt; + break; + } + } + + if (!s) + { + return; + } + + _startups.erase(sIt); + emit startupRemoved(s); +} + +void TaskManager::killStartup(Startup::Ptr s) +{ + if (!s) + { + return; + } + + Startup::List::iterator sIt = _startups.begin(); + Startup::List::iterator itEnd = _startups.end(); + for (; sIt != itEnd; ++sIt) + { + if ((*sIt) == s) + { + _startups.erase(sIt); + break; + } + } + + emit startupRemoved(s); +} + +QString TaskManager::desktopName(int desk) const +{ + return m_winModule->desktopName(desk); +} + +int TaskManager::numberOfDesktops() const +{ + return m_winModule->numberOfDesktops(); +} + +bool TaskManager::isOnTop(const Task* task) +{ + if (!task) + { + return false; + } + + QValueList<WId>::ConstIterator begin(m_winModule->stackingOrder().constBegin()); + QValueList<WId>::ConstIterator it = m_winModule->stackingOrder().fromLast(); + do + { + Task::Dict::iterator taskItEnd = m_tasksByWId.end(); + for (Task::Dict::iterator taskIt = m_tasksByWId.begin(); + taskIt != taskItEnd; ++taskIt) + { + Task::Ptr t = taskIt.data(); + if ((*it) == t->window()) + { + if (t == task) + { + return true; + } + + if (!t->isIconified() && + (t->isAlwaysOnTop() == task->isAlwaysOnTop())) + { + return false; + } + + break; + } + } + } while (it-- != begin); + + return false; +} + +bool TaskManager::isOnScreen(int screen, const WId wid) +{ + if (screen == -1) + { + return true; + } + + KWin::WindowInfo wi = KWin::windowInfo(wid, NET::WMKDEFrameStrut); + + // for window decos that fudge a bit and claim to extend beyond the + // edge of the screen, we just contract a bit. + QRect window = wi.frameGeometry(); + QRect desktop = QApplication::desktop()->screenGeometry(screen); + desktop.addCoords(5, 5, -5, -5); + return window.intersects(desktop); +} + +Task::Task(WId win, QObject *parent, const char *name) + : QObject(parent, name), + _active(false), + _win(win), + m_frameId(win), + _info(KWin::windowInfo(_win, 0, NET::WM2AllowedActions)), + _lastWidth(0), + _lastHeight(0), + _lastResize(false), + _lastIcon(), + _thumbSize(0.2), + _thumb(), + _grab() +{ + // try to load icon via net_wm + _pixmap = KWin::icon(_win, 16, 16, true); + + // try to guess the icon from the classhint + if(_pixmap.isNull()) + { + KGlobal::iconLoader()->loadIcon(className().lower(), + KIcon::Small, + KIcon::Small, + KIcon::DefaultState, + 0, true); + } + + // load xapp icon + if (_pixmap.isNull()) + { + _pixmap = SmallIcon("kcmx"); + } + +#ifdef THUMBNAILING_POSSIBLE + m_windowPixmap = 0; + findWindowFrameId(); + + if (TaskManager::xCompositeEnabled()) + { + updateWindowPixmap(); + } +#endif // THUMBNAILING_POSSIBLE +} + +Task::~Task() +{ +#ifdef THUMBNAILING_POSSIBLE + if (m_windowPixmap) + { + XFreePixmap(QPaintDevice::x11AppDisplay(), m_windowPixmap); + } +#endif // THUMBNAILING_POSSIBLE +} + +// Task::findWindowFrameId() +// Code was copied from Kompose. +// Copyright (C) 2004 Hans Oischinger +// Permission granted on 2005-04-27. +void Task::findWindowFrameId() +{ +#ifdef THUMBNAILING_POSSIBLE + Window target_win, parent, root; + Window *children; + uint nchildren; + + target_win = _win; + for (;;) + { + if (!XQueryTree(QPaintDevice::x11AppDisplay(), target_win, &root, + &parent, &children, &nchildren)) + { + break; + } + + if (children) + { + XFree(children); // it's a list, that's deallocated! + } + + if (!parent || parent == root) + { + break; + } + else + { + target_win = parent; + } + } + + m_frameId = target_win; +#endif // THUMBNAILING_POSSIBLE +} + +void Task::refreshIcon() +{ + // try to load icon via net_wm + _pixmap = KWin::icon(_win, 16, 16, true); + + // try to guess the icon from the classhint + if(_pixmap.isNull()) + { + KGlobal::iconLoader()->loadIcon(className().lower(), + KIcon::Small, + KIcon::Small, + KIcon::DefaultState, + 0, true); + } + + // load xapp icon + if (_pixmap.isNull()) + { + _pixmap = SmallIcon("kcmx"); + } + + _lastIcon.resize(0,0); + emit iconChanged(); +} + +void Task::refresh(unsigned int dirty) +{ + QString name = visibleName(); + _info = KWin::windowInfo(_win, 0, NET::WM2AllowedActions); + + if (dirty != NET::WMName || name != visibleName()) + { + emit changed(dirty == NET::WMGeometry); + } +} + +void Task::setActive(bool a) +{ + _active = a; + emit changed(false); + if ( a ) + emit activated(); + else + emit deactivated(); +} + +bool Task::isMaximized() const +{ + return _info.valid() && (_info.state() & NET::Max); +} + +bool Task::isMinimized() const +{ + return _info.valid() && _info.isMinimized(); +} + +bool Task::isIconified() const +{ + return _info.valid() && _info.isMinimized(); +} + +bool Task::isAlwaysOnTop() const +{ + return _info.valid() && (_info.state() & NET::StaysOnTop); +} + +bool Task::isKeptBelowOthers() const +{ + return _info.valid() && (_info.state() & NET::KeepBelow); +} + +bool Task::isFullScreen() const +{ + return _info.valid() && (_info.state() & NET::FullScreen); +} + +bool Task::isShaded() const +{ + return _info.valid() && (_info.state() & NET::Shaded); +} + +bool Task::isOnCurrentDesktop() const +{ + return _info.valid() && _info.isOnCurrentDesktop(); +} + +bool Task::isOnAllDesktops() const +{ + return _info.valid() && _info.onAllDesktops(); +} + +bool Task::isActive() const +{ + return _active; +} + +bool Task::isOnTop() const +{ + return TaskManager::the()->isOnTop(this); +} + +bool Task::isModified() const +{ + static QString modStr = QString::fromUtf8("[") + + i18n("modified") + + QString::fromUtf8("]"); + int modStrPos = _info.visibleName().find(modStr); + + return ( modStrPos != -1 ); +} + +bool Task::demandsAttention() const +{ + return (_info.valid() && (_info.state() & NET::DemandsAttention)) || + _transients_demanding_attention.count() > 0; +} + +bool Task::isOnScreen( int screen ) const +{ + return TaskManager::isOnScreen( screen, _win ); +} + +void Task::updateDemandsAttentionState( WId w ) +{ + if (window() != w) + { + // 'w' is a transient for this task + NETWinInfo i( qt_xdisplay(), w, qt_xrootwin(), NET::WMState ); + if(i.state() & NET::DemandsAttention) + { + if (!_transients_demanding_attention.contains(w)) + { + _transients_demanding_attention.append(w); + } + } + else + { + _transients_demanding_attention.remove( w ); + } + } +} + +void Task::addTransient( WId w, const NETWinInfo& info ) +{ + _transients.append(w); + if (info.state() & NET::DemandsAttention) + { + _transients_demanding_attention.append(w); + emit changed(false); + } +} + +void Task::removeTransient(WId w) +{ + _transients.remove(w); + _transients_demanding_attention.remove(w); +} + +QString Task::className() +{ + XClassHint hint; + if(XGetClassHint(qt_xdisplay(), _win, &hint)) { + QString nh( hint.res_name ); + XFree( hint.res_name ); + XFree( hint.res_class ); + return nh; + } + return QString::null; +} + +QString Task::classClass() +{ + XClassHint hint; + if(XGetClassHint(qt_xdisplay(), _win, &hint)) { + QString ch( hint.res_class ); + XFree( hint.res_name ); + XFree( hint.res_class ); + return ch; + } + return QString::null; +} + +QPixmap Task::icon( int width, int height, bool allowResize ) +{ + if ( (width == _lastWidth) + && (height == _lastHeight) + && (allowResize == _lastResize ) + && (!_lastIcon.isNull()) ) + return _lastIcon; + + QPixmap newIcon = KWin::icon( _win, width, height, allowResize ); + if ( !newIcon.isNull() ) { + _lastIcon = newIcon; + _lastWidth = width; + _lastHeight = height; + _lastResize = allowResize; + } + + return newIcon; +} + +QPixmap Task::bestIcon( int size, bool &isStaticIcon ) +{ + QPixmap pixmap; + isStaticIcon = false; + + switch( size ) { + case KIcon::SizeSmall: + { + pixmap = icon( 16, 16, true ); + + // Icon of last resort + if( pixmap.isNull() ) { + pixmap = KGlobal::iconLoader()->loadIcon( "go", + KIcon::NoGroup, + KIcon::SizeSmall ); + isStaticIcon = true; + } + } + break; + case KIcon::SizeMedium: + { + // + // Try 34x34 first for KDE 2.1 icons with shadows, if we don't + // get one then try 32x32. + // + pixmap = icon( 34, 34, false ); + + if ( (( pixmap.width() != 34 ) || ( pixmap.height() != 34 )) && + (( pixmap.width() != 32 ) || ( pixmap.height() != 32 )) ) + { + pixmap = icon( 32, 32, true ); + } + + // Icon of last resort + if( pixmap.isNull() ) { + pixmap = KGlobal::iconLoader()->loadIcon( "go", + KIcon::NoGroup, + KIcon::SizeMedium ); + isStaticIcon = true; + } + } + break; + case KIcon::SizeLarge: + { + // If there's a 48x48 icon in the hints then use it + pixmap = icon( size, size, false ); + + // If not, try to get one from the classname + if ( pixmap.isNull() || pixmap.width() != size || pixmap.height() != size ) { + pixmap = KGlobal::iconLoader()->loadIcon( className(), + KIcon::NoGroup, + size, + KIcon::DefaultState, + 0L, + true ); + isStaticIcon = true; + } + + // If we still don't have an icon then scale the one in the hints + if ( pixmap.isNull() || ( pixmap.width() != size ) || ( pixmap.height() != size ) ) { + pixmap = icon( size, size, true ); + isStaticIcon = false; + } + + // Icon of last resort + if( pixmap.isNull() ) { + pixmap = KGlobal::iconLoader()->loadIcon( "go", + KIcon::NoGroup, + size ); + isStaticIcon = true; + } + } + } + + return pixmap; +} + +bool Task::idMatch( const QString& id1, const QString& id2 ) +{ + if ( id1.isEmpty() || id2.isEmpty() ) + return false; + + if ( id1.contains( id2 ) > 0 ) + return true; + + if ( id2.contains( id1 ) > 0 ) + return true; + + return false; +} + + +void Task::move() +{ + bool on_current = _info.isOnCurrentDesktop(); + + if (!on_current) + { + KWin::setCurrentDesktop(_info.desktop()); + KWin::forceActiveWindow(_win); + } + + if (_info.isMinimized()) + { + KWin::deIconifyWindow(_win); + } + + QRect geom = _info.geometry(); + QCursor::setPos(geom.center()); + + NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize); + ri.moveResizeRequest(_win, geom.center().x(), + geom.center().y(), NET::Move); +} + +void Task::resize() +{ + bool on_current = _info.isOnCurrentDesktop(); + + if (!on_current) + { + KWin::setCurrentDesktop(_info.desktop()); + KWin::forceActiveWindow(_win); + } + + if (_info.isMinimized()) + { + KWin::deIconifyWindow(_win); + } + + QRect geom = _info.geometry(); + QCursor::setPos(geom.bottomRight()); + + NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize); + ri.moveResizeRequest(_win, geom.bottomRight().x(), + geom.bottomRight().y(), NET::BottomRight); +} + +void Task::setMaximized(bool maximize) +{ + KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); + bool on_current = info.isOnCurrentDesktop(); + + if (!on_current) + { + KWin::setCurrentDesktop(info.desktop()); + } + + if (info.isMinimized()) + { + KWin::deIconifyWindow(_win); + } + + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + + if (maximize) + { + ni.setState(NET::Max, NET::Max); + } + else + { + ni.setState(0, NET::Max); + } + + if (!on_current) + { + KWin::forceActiveWindow(_win); + } +} + +void Task::toggleMaximized() +{ + setMaximized(!isMaximized()); +} + +void Task::restore() +{ + KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); + bool on_current = info.isOnCurrentDesktop(); + + if (!on_current) + { + KWin::setCurrentDesktop(info.desktop()); + } + + if( info.isMinimized()) + { + KWin::deIconifyWindow(_win); + } + + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + ni.setState(0, NET::Max); + + if (!on_current) + { + KWin::forceActiveWindow( _win ); + } +} + +void Task::setIconified(bool iconify) +{ + if (iconify) + { + KWin::iconifyWindow(_win); + } + else + { + KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); + bool on_current = info.isOnCurrentDesktop(); + + if (!on_current) + { + KWin::setCurrentDesktop(info.desktop()); + } + + KWin::deIconifyWindow(_win); + + if (!on_current) + { + KWin::forceActiveWindow(_win); + } + } +} + +void Task::toggleIconified() +{ + setIconified(!isIconified()); +} + +void Task::close() +{ + NETRootInfo ri( qt_xdisplay(), NET::CloseWindow ); + ri.closeWindowRequest( _win ); +} + +void Task::raise() +{ +// kdDebug(1210) << "Task::raise(): " << name() << endl; + KWin::raiseWindow( _win ); +} + +void Task::lower() +{ +// kdDebug(1210) << "Task::lower(): " << name() << endl; + KWin::lowerWindow( _win ); +} + +void Task::activate() +{ +// kdDebug(1210) << "Task::activate():" << name() << endl; + WId w = _win; + if (_transients_demanding_attention.count() > 0) + { + w = _transients_demanding_attention.last(); + } + KWin::forceActiveWindow( w ); +} + +void Task::activateRaiseOrIconify() +{ + if (!isActive() || isIconified()) + { + activate(); + } + else if (!isOnTop()) + { + raise(); + } + else + { + setIconified(true); + } +} + +void Task::toDesktop(int desk) +{ + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMDesktop); + if (desk == 0) + { + if (_info.valid() && _info.onAllDesktops()) + { + ni.setDesktop(TaskManager::the()->winModule()->currentDesktop()); + KWin::forceActiveWindow(_win); + } + else + { + ni.setDesktop(NETWinInfo::OnAllDesktops); + } + + return; + } + ni.setDesktop(desk); + if(desk == TaskManager::the()->winModule()->currentDesktop()) + KWin::forceActiveWindow(_win); +} + +void Task::toCurrentDesktop() +{ + toDesktop(TaskManager::the()->winModule()->currentDesktop()); +} + +void Task::setAlwaysOnTop(bool stay) +{ + NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + if(stay) + ni.setState( NET::StaysOnTop, NET::StaysOnTop ); + else + ni.setState( 0, NET::StaysOnTop ); +} + +void Task::toggleAlwaysOnTop() +{ + setAlwaysOnTop( !isAlwaysOnTop() ); +} + +void Task::setKeptBelowOthers(bool below) +{ + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + + if (below) + { + ni.setState(NET::KeepBelow, NET::KeepBelow); + } + else + { + ni.setState(0, NET::KeepBelow); + } +} + +void Task::toggleKeptBelowOthers() +{ + setKeptBelowOthers(!isKeptBelowOthers()); +} + +void Task::setFullScreen(bool fullscreen) +{ + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + + if (fullscreen) + { + ni.setState(NET::FullScreen, NET::FullScreen); + } + else + { + ni.setState(0, NET::FullScreen); + } +} + +void Task::toggleFullScreen() +{ + setFullScreen(!isFullScreen()); +} + +void Task::setShaded(bool shade) +{ + NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + if(shade) + ni.setState( NET::Shaded, NET::Shaded ); + else + ni.setState( 0, NET::Shaded ); +} + +void Task::toggleShaded() +{ + setShaded( !isShaded() ); +} + +void Task::publishIconGeometry(QRect rect) +{ + if (rect == m_iconGeometry) + { + return; + } + + m_iconGeometry = rect; + NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), 0); + NETRect r; + + if (rect.isValid()) + { + r.pos.x = rect.x(); + r.pos.y = rect.y(); + r.size.width = rect.width(); + r.size.height = rect.height(); + } + ni.setIconGeometry(r); +} + +void Task::updateThumbnail() +{ + if ( !_info.valid() || + !isOnCurrentDesktop() || + !isActive() || + !_grab.isNull() ) // We're already processing one... + { + return; + } + + // + // We do this as a two stage process to remove the delay caused + // by the thumbnail generation. This makes things much smoother + // on slower machines. + // + QWidget *rootWin = qApp->desktop(); + QRect geom = _info.geometry(); + _grab = QPixmap::grabWindow(rootWin->winId(), + geom.x(), geom.y(), + geom.width(), geom.height()); + + if (!_grab.isNull()) + { + QTimer::singleShot(200, this, SLOT(generateThumbnail())); + } +} + +void Task::generateThumbnail() +{ + if ( _grab.isNull() ) + return; + + QImage img = _grab.convertToImage(); + + double width = img.width(); + double height = img.height(); + width = width * _thumbSize; + height = height * _thumbSize; + + img = img.smoothScale( qRound(width), qRound(height) ); + _thumb = img; + _grab.resize( 0, 0 ); // Makes grab a null image. + + emit thumbnailChanged(); +} + +#ifdef THUMBNAILING_POSSIBLE +QPixmap Task::thumbnail(int maxDimension) +{ + if (!TaskManager::xCompositeEnabled() || !m_windowPixmap) + { + return QPixmap(); + } + + Display *dpy = QPaintDevice::x11AppDisplay(); + + XWindowAttributes winAttr; + XGetWindowAttributes(dpy, m_frameId, &winAttr); + XRenderPictFormat *format = XRenderFindVisualFormat(dpy, winAttr.visual); + + XRenderPictureAttributes picAttr; + picAttr.subwindow_mode = IncludeInferiors; // Don't clip child widgets + + Picture picture = XRenderCreatePicture(dpy, m_windowPixmap, format, + CPSubwindowMode, &picAttr); + + // Get shaped windows handled correctly. + XserverRegion region = XFixesCreateRegionFromWindow(dpy, m_frameId, + WindowRegionBounding); + XFixesSetPictureClipRegion(dpy, picture, 0, 0, region); + XFixesDestroyRegion(dpy, region); + + double factor; + if (winAttr.width > winAttr.height) + { + factor = (double)maxDimension / (double)winAttr.width; + } + else + { + factor = (double)maxDimension / (double)winAttr.height; + } + int thumbnailWidth = (int)(winAttr.width * factor); + int thumbnailHeight = (int)(winAttr.height * factor); + + QPixmap thumbnail(thumbnailWidth, thumbnailHeight); + thumbnail.fill(QApplication::palette().active().background()); + +#if 0 // QImage::smoothScale() scaling + QPixmap full(winAttr.width, winAttr.height); + full.fill(QApplication::palette().active().background()); + + bool hasAlpha = format->type == PictTypeDirect && format->direct.alphaMask; + + XRenderComposite(dpy, + hasAlpha ? PictOpOver : PictOpSrc, + picture, // src + None, // mask + full.x11RenderHandle(), // dst + 0, 0, // src offset + 0, 0, // mask offset + 0, 0, // dst offset + winAttr.width, winAttr.height); + + KPixmapIO io; + QImage image = io.convertToImage(full); + thumbnail = io.convertToPixmap(image.smoothScale(thumbnailWidth, + thumbnailHeight)); +#else // XRENDER scaling + // Scaling matrix + XTransform transformation = {{ + { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed( 0) }, + { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed( 0) }, + { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(factor) } + }}; + + XRenderSetPictureTransform(dpy, picture, &transformation); + XRenderSetPictureFilter(dpy, picture, FilterBest, 0, 0); + + XRenderComposite(QPaintDevice::x11AppDisplay(), + PictOpOver, // we're filtering, alpha values are probable + picture, // src + None, // mask + thumbnail.x11RenderHandle(), // dst + 0, 0, // src offset + 0, 0, // mask offset + 0, 0, // dst offset + thumbnailWidth, thumbnailHeight); +#endif + XRenderFreePicture(dpy, picture); + + return thumbnail; +} +#else // THUMBNAILING_POSSIBLE +QPixmap Task::thumbnail(int /* maxDimension */) +{ + return QPixmap(); +} +#endif // THUMBNAILING_POSSIBLE + +void Task::updateWindowPixmap() +{ +#ifdef THUMBNAILING_POSSIBLE + if (!TaskManager::xCompositeEnabled() || !isOnCurrentDesktop() || + isMinimized()) + { + return; + } + + Display *dpy = QPaintDevice::x11AppDisplay(); + + if (m_windowPixmap) + { + XFreePixmap(dpy, m_windowPixmap); + } + + KXErrorHandler err; + m_windowPixmap = XCompositeNameWindowPixmap(dpy, m_frameId); + if( err.error( true )) + m_windowPixmap = None; +#endif // THUMBNAILING_POSSIBLE +} + +Startup::Startup(const KStartupInfoId& id, const KStartupInfoData& data, + QObject * parent, const char *name) + : QObject(parent, name), _id(id), _data(data) +{ +} + +Startup::~Startup() +{ +} + +void Startup::update(const KStartupInfoData& data) +{ + _data.update(data); + emit changed(); +} + +int TaskManager::currentDesktop() const +{ + return m_winModule->currentDesktop(); +} + +TaskDrag::TaskDrag(const Task::List& tasks, QWidget* source, const char* name) + : QStoredDrag("taskbar/task", source, name) +{ + QByteArray data; + QDataStream stream(data, IO_WriteOnly); + + Task::List::const_iterator itEnd = tasks.constEnd(); + for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) + { + stream << (*it)->window(); + } + + setEncodedData(data); +} + +TaskDrag::~TaskDrag() +{ +} + +bool TaskDrag::canDecode(const QMimeSource* e) +{ + return e->provides("taskbar/task"); +} + +Task::List TaskDrag::decode( const QMimeSource* e ) +{ + QByteArray data(e->encodedData("taskbar/task")); + Task::List tasks; + + if (data.size()) + { + QDataStream stream(data, IO_ReadOnly); + while (!stream.atEnd()) + { + WId id; + stream >> id; + if (Task::Ptr task = TaskManager::the()->findTask(id)) + { + tasks.append(task); + } + } + } + + return tasks; +} + diff --git a/kicker/taskmanager/taskmanager.h b/kicker/taskmanager/taskmanager.h new file mode 100644 index 000000000..5885569d9 --- /dev/null +++ b/kicker/taskmanager/taskmanager.h @@ -0,0 +1,713 @@ +/***************************************************************** + +Copyright (c) 2000-2001 Matthias Elter <elter@kde.org> +Copyright (c) 2001 Richard Moore <rich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskmanager_h__ +#define __taskmanager_h__ + +#include <sys/types.h> + +#include <qobject.h> +#include <qpixmap.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <qpixmap.h> +#include <qdragobject.h> +#include <qrect.h> +#include <qvaluelist.h> +#include <qvaluevector.h> + +#include <ksharedptr.h> +#include <kstartupinfo.h> +#include <kwin.h> + +#include <config.h> + +#if defined(HAVE_XCOMPOSITE) && \ + defined(HAVE_XRENDER) && \ + defined(HAVE_XFIXES) +#include <X11/Xlib.h> +#include <X11/extensions/Xcomposite.h> +#include <X11/extensions/Xfixes.h> +#include <X11/extensions/Xrender.h> +#if XCOMPOSITE_VERSION >= 00200 && \ + XFIXES_VERSION >= 20000 && \ + (RENDER_MAJOR > 0 || RENDER_MINOR >= 6) +#define THUMBNAILING_POSSIBLE +#endif +#endif + +class KWinModule; +class TaskManager; + +typedef QValueList<WId> WindowList; + +/** + * A dynamic interface to a task (main window). + * + * @see TaskManager + * @see KWinModule + */ +class KDE_EXPORT Task: public QObject, public KShared +{ + Q_OBJECT + Q_PROPERTY( QString visibleIconicName READ visibleIconicName ) + Q_PROPERTY( QString iconicName READ iconicName ) + Q_PROPERTY( QString visibleIconicNameWithState READ visibleIconicNameWithState ) + Q_PROPERTY( QString visibleName READ visibleName ) + Q_PROPERTY( QString name READ name ) + Q_PROPERTY( QString visibleNameWithState READ visibleNameWithState ) + Q_PROPERTY( QPixmap pixmap READ pixmap ) + Q_PROPERTY( bool maximized READ isMaximized ) + Q_PROPERTY( bool minimized READ isMinimized ) + // KDE4 deprecated + Q_PROPERTY( bool iconified READ isIconified ) + Q_PROPERTY( bool shaded READ isShaded WRITE setShaded ) + Q_PROPERTY( bool active READ isActive ) + Q_PROPERTY( bool onCurrentDesktop READ isOnCurrentDesktop ) + Q_PROPERTY( bool onAllDesktops READ isOnAllDesktops ) + Q_PROPERTY( bool alwaysOnTop READ isAlwaysOnTop WRITE setAlwaysOnTop ) + Q_PROPERTY( bool modified READ isModified ) + Q_PROPERTY( bool demandsAttention READ demandsAttention ) + Q_PROPERTY( int desktop READ desktop ) + Q_PROPERTY( double thumbnailSize READ thumbnailSize WRITE setThumbnailSize ) + Q_PROPERTY( bool hasThumbnail READ hasThumbnail ) + Q_PROPERTY( QPixmap thumbnail READ thumbnail ) + +public: + typedef KSharedPtr<Task> Ptr; + typedef QValueVector<Task::Ptr> List; + typedef QMap<WId, Task::Ptr> Dict; + + Task(WId win, QObject *parent, const char *name = 0); + virtual ~Task(); + + WId window() const { return _win; } + KWin::WindowInfo info() const { return _info; } + +#if 0 // this would use (_NET_)WM_ICON_NAME, which is shorter, but can be different from window name + QString visibleIconicName() const { return _info.visibleIconName(); } + QString visibleIconicNameWithState() const { return _info.visibleIconNameWithState(); } + QString iconicName() const { return _info.iconName(); } +#else + QString visibleIconicName() const { return _info.visibleName(); } + QString visibleIconicNameWithState() const { return _info.visibleNameWithState(); } + QString iconicName() const { return _info.name(); } +#endif + QString visibleName() const { return _info.visibleName(); } + QString visibleNameWithState() const { return _info.visibleNameWithState(); } + QString name() const { return _info.name(); } + QString className(); + QString classClass(); + + /** + * A list of the window ids of all transient windows (dialogs) associated + * with this task. + */ + WindowList transients() const { return _transients; } + + /** + * Returns a 16x16 (KIcon::Small) icon for the task. This method will + * only fall back to a static icon if there is no icon of any size in + * the WM hints. + */ + QPixmap pixmap() const { return _pixmap; } + + /** + * Returns the best icon for any of the KIcon::StdSizes. If there is no + * icon of the specified size specified in the WM hints, it will try to + * get one using KIconLoader. + * + * <pre> + * bool gotStaticIcon; + * QPixmap icon = myTask->icon( KIcon::SizeMedium, gotStaticIcon ); + * </pre> + * + * @param size Any of the constants in KIcon::StdSizes. + * @param isStaticIcon Set to true if KIconLoader was used, false otherwise. + * @see KIcon + */ + QPixmap bestIcon( int size, bool &isStaticIcon ); + + /** + * Tries to find an icon for the task with the specified size. If there + * is no icon that matches then it will either resize the closest available + * icon or return a null pixmap depending on the value of allowResize. + * + * Note that the last icon is cached, so a sequence of calls with the same + * parameters will only query the NET properties if the icon has changed or + * none was found. + */ + QPixmap icon( int width, int height, bool allowResize = false ); + + /** + * Returns true iff the windows with the specified ids should be grouped + * together in the task list. + */ + static bool idMatch(const QString &, const QString &); + + // state + + /** + * Returns true if the task's window is maximized. + */ + bool isMaximized() const; + + /** + * Returns true if the task's window is minimized. + */ + bool isMinimized() const; + + /** + * @deprecated + * Returns true if the task's window is minimized(iconified). + */ + bool isIconified() const; + + /** + * Returns true if the task's window is shaded. + */ + bool isShaded() const; + + /** + * Returns true if the task's window is the active window. + */ + bool isActive() const; + + /** + * Returns true if the task's window is the topmost non-iconified, + * non-always-on-top window. + */ + bool isOnTop() const; + + /** + * Returns true if the task's window is on the current virtual desktop. + */ + bool isOnCurrentDesktop() const; + + /** + * Returns true if the task's window is on all virtual desktops. + */ + bool isOnAllDesktops() const; + + /** + * Returns true if the task's window will remain at the top of the + * stacking order. + */ + bool isAlwaysOnTop() const; + + /** + * Returns true if the task's window will remain at the bottom of the + * stacking order. + */ + bool isKeptBelowOthers() const; + + /** + * Returns true if the task's window is in full screen mode + */ + bool isFullScreen() const; + + /** + * Returns true if the document the task is editing has been modified. + * This is currently handled heuristically by looking for the string + * '[i18n_modified]' in the window title where i18n_modified is the + * word 'modified' in the current language. + */ + bool isModified() const ; + + /** + * Returns the desktop on which this task's window resides. + */ + int desktop() const { return _info.desktop(); } + + /** + * Returns true if the task is not active but demands user's attention. + */ + bool demandsAttention() const; + + + /** + * Returns true if the window is on the specified screen of a multihead configuration + */ + bool isOnScreen( int screen ) const; + + /** + * Returns true if the task should be shown in taskbar-like apps + */ + bool showInTaskbar() const { return _info.state() ^ NET::SkipTaskbar; } + + /** + * Returns true if the task should be shown in pager-like apps + */ + bool showInPager() const { return _info.state() ^ NET::SkipPager; } + + /** + * Returns the geometry for this window + */ + QRect geometry() const { return _info.geometry(); } + + /** + * Returns the geometry for the from of this window + */ + QRect frameGeometry() const { return _info.frameGeometry(); } + + // internal + + //* @internal + void refresh(unsigned int dirty); + //* @internal + void refreshIcon(); + //* @internal + void addTransient( WId w, const NETWinInfo& info ); + //* @internal + void removeTransient( WId w ); + //* @internal + bool hasTransient(WId w) const { return _transients.find(w) != _transients.end(); } + //* @internal + void updateDemandsAttentionState( WId w ); + //* @internal + void setActive(bool a); + + // For thumbnails + + /** + * Returns the current thumbnail size. + */ + double thumbnailSize() const { return _thumbSize; } + + /** + * Sets the size for the window thumbnail. For example a size of + * 0.2 indicates the thumbnail will be 20% of the original window + * size. + */ + void setThumbnailSize( double size ) { _thumbSize = size; } + + /** + * Returns true if this task has a thumbnail. Note that this method + * can only ever return true after a call to updateThumbnail(). + */ + bool hasThumbnail() const { return !_thumb.isNull(); } + + /** + * Returns the thumbnail for this task (or a null image if there is + * none). + */ + const QPixmap &thumbnail() const { return _thumb; } + + QPixmap thumbnail(int maxDimension); + + void updateWindowPixmap(); + +public slots: + // actions + + /** + * Maximise the main window of this task. + */ + void setMaximized(bool); + void toggleMaximized(); + + /** + * Restore the main window of the task (if it was iconified). + */ + void restore(); + + /** + * Move the window of this task. + */ + void move(); + + /** + * Resize the window of this task. + */ + void resize(); + + /** + * Iconify the task. + */ + void setIconified(bool); + void toggleIconified(); + + /** + * Close the task's window. + */ + void close(); + + /** + * Raise the task's window. + */ + void raise(); + + /** + * Lower the task's window. + */ + void lower(); + + /** + * Activate the task's window. + */ + void activate(); + + /** + * Perform the action that is most appropriate for this task. If it + * is not active, activate it. Else if it is not the top window, raise + * it. Otherwise, iconify it. + */ + void activateRaiseOrIconify(); + + /** + * If true, the task's window will remain at the top of the stacking order. + */ + void setAlwaysOnTop(bool); + void toggleAlwaysOnTop(); + + /** + * If true, the task's window will remain at the bottom of the stacking order. + */ + void setKeptBelowOthers(bool); + void toggleKeptBelowOthers(); + + /** + * If true, the task's window will enter full screen mode. + */ + void setFullScreen(bool); + void toggleFullScreen(); + + /** + * If true then the task's window will be shaded. Most window managers + * represent this state by displaying on the window's title bar. + */ + void setShaded(bool); + void toggleShaded(); + + /** + * Moves the task's window to the specified virtual desktop. + */ + void toDesktop(int); + + /** + * Moves the task's window to the current virtual desktop. + */ + void toCurrentDesktop(); + + /** + * This method informs the window manager of the location at which this + * task will be displayed when iconised. It is used, for example by the + * KWin inconify animation. + */ + void publishIconGeometry(QRect); + + /** + * Tells the task to generate a new thumbnail. When the thumbnail is + * ready the thumbnailChanged() signal will be emitted. + */ + void updateThumbnail(); + +signals: + /** + * Indicates that this task has changed in some way. + */ + void changed(bool geometryChangeOnly); + + /** + * Indicates that the icon for this task has changed. + */ + void iconChanged(); + + /** + * Indicates that this task is now the active task. + */ + void activated(); + + /** + * Indicates that this task is no longer the active task. + */ + void deactivated(); + + /** + * Indicates that the thumbnail for this task has changed. + */ + void thumbnailChanged(); + +protected slots: + //* @internal + void generateThumbnail(); + +protected: + void findWindowFrameId(); + +private: + bool _active; + WId _win; + WId m_frameId; + QPixmap _pixmap; + KWin::WindowInfo _info; + WindowList _transients; + WindowList _transients_demanding_attention; + + int _lastWidth; + int _lastHeight; + bool _lastResize; + QPixmap _lastIcon; + + double _thumbSize; + QPixmap _thumb; + QPixmap _grab; + QRect m_iconGeometry; +#ifdef THUMBNAILING_POSSIBLE + Pixmap m_windowPixmap; +#endif // THUMBNAILING_POSSIBLE +}; + + +/** + * Provids a drag object for tasks across desktops. + */ +class KDE_EXPORT TaskDrag : public QStoredDrag +{ +public: + /** + * Constructs a task drag object for a task list. + */ + TaskDrag(const Task::List& tasks, QWidget* source = 0, + const char* name = 0); + ~TaskDrag(); + + /** + * Returns true if the mime source can be decoded to a TaskDrag. + */ + static bool canDecode( const QMimeSource* e ); + + /** + * Decodes the tasks from the mime source and returns them if successful. + * Otherwise an empty task list is returned. + */ + static Task::List decode( const QMimeSource* e ); +}; + + +/** + * Represents a task which is in the process of starting. + * + * @see TaskManager + */ +class KDE_EXPORT Startup: public QObject, public KShared +{ + Q_OBJECT + Q_PROPERTY( QString text READ text ) + Q_PROPERTY( QString bin READ bin ) + Q_PROPERTY( QString icon READ icon ) + +public: + typedef KSharedPtr<Startup> Ptr; + typedef QValueVector<Startup::Ptr> List; + + Startup( const KStartupInfoId& id, const KStartupInfoData& data, QObject * parent, + const char *name = 0); + virtual ~Startup(); + + /** + * The name of the starting task (if known). + */ + QString text() const { return _data.findName(); } + + /** + * The name of the executable of the starting task. + */ + QString bin() const { return _data.bin(); } + + /** + * The name of the icon to be used for the starting task. + */ + QString icon() const { return _data.findIcon(); } + void update( const KStartupInfoData& data ); + const KStartupInfoId& id() const { return _id; } + +signals: + /** + * Indicates that this startup has changed in some way. + */ + void changed(); + +private: + KStartupInfoId _id; + KStartupInfoData _data; + class StartupPrivate *d; +}; + + +/** + * A generic API for task managers. This class provides an easy way to + * build NET compliant task managers. It provides support for startup + * notification, virtual desktops and the full range of WM properties. + * + * @see Task + * @see Startup + * @see KWinModule + */ +class KDE_EXPORT TaskManager : public QObject +{ + Q_OBJECT + Q_PROPERTY( int currentDesktop READ currentDesktop ) + Q_PROPERTY( int numberOfDesktops READ numberOfDesktops ) + +public: + static TaskManager* the(); + ~TaskManager(); + + /** + * Returns the task for a given WId, or 0 if there is no such task. + */ + Task::Ptr findTask(WId w); + + /** + * Returns the task for a given location, or 0 if there is no such task. + */ + Task::Ptr findTask(int desktop, const QPoint& p); + + /** + * Returns a list of all current tasks. + */ + Task::Dict tasks() const { return m_tasksByWId; } + + /** + * Returns a list of all current startups. + */ + Startup::List startups() const { return _startups; } + + /** + * Returns the name of the nth desktop. + */ + QString desktopName(int n) const; + + /** + * Returns the number of virtual desktops. + */ + int numberOfDesktops() const; + + /** + * Returns the number of the current desktop. + */ + int currentDesktop() const; + + /** + * Returns true if the specified task is on top. + */ + bool isOnTop(const Task*); + + /** + * Tells the task manager whether or not we care about geometry + * updates. This generates a lot of activity so should only be used + * when necessary. + */ + void trackGeometry() { m_trackGeometry = true; } + void trackGeometry(bool track) { m_trackGeometry = track; } + + /** + * Returns whether the Window with WId wid is on the screen screen + */ + static bool isOnScreen( int screen, const WId wid ); + + KWinModule* winModule() const { return m_winModule; } + + void setXCompositeEnabled(bool state); + static bool xCompositeEnabled() { return m_xCompositeEnabled != 0; } + +signals: + /** + * Emitted when a new task has started. + */ + void taskAdded(Task::Ptr); + + /** + * Emitted when a task has terminated. + */ + void taskRemoved(Task::Ptr); + + /** + * Emitted when a new task is expected. + */ + void startupAdded(Startup::Ptr); + + /** + * Emitted when a startup item should be removed. This could be because + * the task has started, because it is known to have died, or simply + * as a result of a timeout. + */ + void startupRemoved(Startup::Ptr); + + /** + * Emitted when the current desktop changes. + */ + void desktopChanged(int desktop); + + /** + * Emitted when a window changes desktop. + */ + void windowChanged(Task::Ptr); + void windowChangedGeometry(Task::Ptr); + +protected slots: + //* @internal + void windowAdded(WId); + //* @internal + void windowRemoved(WId); + //* @internal + void windowChanged(WId, unsigned int); + + //* @internal + void activeWindowChanged(WId); + //* @internal + void currentDesktopChanged(int); + //* @internal + void killStartup( const KStartupInfoId& ); + //* @internal + void killStartup(Startup::Ptr); + + //* @internal + void gotNewStartup( const KStartupInfoId&, const KStartupInfoData& ); + //* @internal + void gotStartupChange( const KStartupInfoId&, const KStartupInfoData& ); + +protected: + void configure_startup(); + void updateWindowPixmap(WId); + +private: + TaskManager(); + + Task::Ptr _active; + Task::Dict m_tasksByWId; + WindowList _skiptaskbar_windows; + Startup::List _startups; + KStartupInfo* _startup_info; + KWinModule* m_winModule; + bool m_trackGeometry; + + static TaskManager* m_self; + static uint m_xCompositeEnabled; + + class TaskManagerPrivate *d; +}; + +#endif diff --git a/kicker/taskmanager/taskrmbmenu.cpp b/kicker/taskmanager/taskrmbmenu.cpp new file mode 100644 index 000000000..47260687f --- /dev/null +++ b/kicker/taskmanager/taskrmbmenu.cpp @@ -0,0 +1,328 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2001 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <assert.h> + +#include <kiconloader.h> +#include <klocale.h> + +#include "taskmanager.h" + +#if defined(HAVE_XCOMPOSITE) && \ + defined(HAVE_XRENDER) && \ + defined(HAVE_XFIXES) +#include <fixx11h.h> +#endif + +#include "taskrmbmenu.h" +#include "taskrmbmenu.moc" + +TaskRMBMenu::TaskRMBMenu(const Task::List& theTasks, bool show, QWidget *parent, const char *name) + : QPopupMenu( parent, name ) + , tasks( theTasks ) + , showAll( show ) +{ + assert(tasks.count() > 0); + if (tasks.count() == 1) + { + fillMenu(tasks.first()); + } + else + { + fillMenu(); + } +} + +TaskRMBMenu::TaskRMBMenu(Task::Ptr task, bool show, QWidget *parent, const char *name) + : QPopupMenu( parent, name ) + , showAll( show ) +{ + fillMenu(task); +} + +void TaskRMBMenu::fillMenu(Task::Ptr t) +{ + int id; + setCheckable(true); + + insertItem(i18n("Ad&vanced"), makeAdvancedMenu(t)); + bool checkActions = KWin::allowedActionsSupported(); + + if (TaskManager::the()->numberOfDesktops() > 1) + { + id = insertItem(i18n("To &Desktop"), makeDesktopsMenu(t)); + + if (showAll) + { + id = insertItem(i18n("&To Current Desktop"), + t, SLOT(toCurrentDesktop())); + setItemEnabled( id, !t->isOnCurrentDesktop() ); + } + + if (checkActions) + { + setItemEnabled(id, t->info().actionSupported(NET::ActionChangeDesktop)); + } + } + + id = insertItem(SmallIconSet("move"), i18n("&Move"), t, SLOT(move())); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMove)); + + id = insertItem(i18n("Re&size"), t, SLOT(resize())); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionResize)); + + id = insertItem(i18n("Mi&nimize"), t, SLOT(toggleIconified())); + setItemChecked(id, t->isIconified()); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMinimize)); + + id = insertItem(i18n("Ma&ximize"), t, SLOT(toggleMaximized())); + setItemChecked(id, t->isMaximized()); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMax)); + + id = insertItem(i18n("&Shade"), t, SLOT(toggleShaded())); + setItemChecked(id, t->isShaded()); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionShade)); + + insertSeparator(); + + id = insertItem(SmallIcon("fileclose"), i18n("&Close"), t, SLOT(close())); + setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionClose)); +} + +void TaskRMBMenu::fillMenu() +{ + int id; + setCheckable( true ); + + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + Task::Ptr t = (*it); + + id = insertItem( QIconSet( t->pixmap() ), + t->visibleNameWithState(), + new TaskRMBMenu(t, this) ); + setItemChecked( id, t->isActive() ); + connectItem( id, t, SLOT( activateRaiseOrIconify() ) ); + } + + insertSeparator(); + + bool enable = false; + + if (TaskManager::the()->numberOfDesktops() > 1) + { + id = insertItem(i18n("All to &Desktop"), makeDesktopsMenu()); + + id = insertItem(i18n("All &to Current Desktop"), this, SLOT(slotAllToCurrentDesktop())); + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if (!(*it)->isOnCurrentDesktop()) + { + enable = true; + break; + } + } + setItemEnabled(id, enable); + } + + enable = false; + + id = insertItem( i18n( "Mi&nimize All" ), this, SLOT( slotMinimizeAll() ) ); + itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if( !(*it)->isIconified() ) { + enable = true; + break; + } + } + setItemEnabled( id, enable ); + + enable = false; + + id = insertItem( i18n( "Ma&ximize All" ), this, SLOT( slotMaximizeAll() ) ); + itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if( !(*it)->isMaximized() ) { + enable = true; + break; + } + } + setItemEnabled( id, enable ); + + enable = false; + + id = insertItem( i18n( "&Restore All" ), this, SLOT( slotRestoreAll() ) ); + itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + if( (*it)->isIconified() || (*it)->isMaximized() ) { + enable = true; + break; + } + } + setItemEnabled( id, enable ); + + insertSeparator(); + + enable = false; + + insertItem( SmallIcon( "remove" ), i18n( "&Close All" ), this, SLOT( slotCloseAll() ) ); +} + +QPopupMenu* TaskRMBMenu::makeAdvancedMenu(Task::Ptr t) +{ + int id; + QPopupMenu* menu = new QPopupMenu(this); + + menu->setCheckable(true); + + id = menu->insertItem(SmallIconSet("up"), + i18n("Keep &Above Others"), + t, SLOT(toggleAlwaysOnTop())); + menu->setItemChecked(id, t->isAlwaysOnTop()); + + id = menu->insertItem(SmallIconSet("down"), + i18n("Keep &Below Others"), + t, SLOT(toggleKeptBelowOthers())); + menu->setItemChecked(id, t->isKeptBelowOthers()); + + id = menu->insertItem(SmallIconSet("window_fullscreen"), + i18n("&Fullscreen"), + t, SLOT(toggleFullScreen())); + menu->setItemChecked(id, t->isFullScreen()); + + if (KWin::allowedActionsSupported()) + { + menu->setItemEnabled(id, t->info().actionSupported(NET::ActionFullScreen)); + } + + return menu; +} + +QPopupMenu* TaskRMBMenu::makeDesktopsMenu(Task::Ptr t) +{ + QPopupMenu* m = new QPopupMenu( this ); + m->setCheckable( true ); + + int id = m->insertItem( i18n("&All Desktops"), t, SLOT( toDesktop(int) ) ); + m->setItemParameter( id, 0 ); // 0 means all desktops + m->setItemChecked( id, t->isOnAllDesktops() ); + + m->insertSeparator(); + + for (int i = 1; i <= TaskManager::the()->numberOfDesktops(); i++) { + QString name = QString("&%1 %2").arg(i).arg(TaskManager::the()->desktopName(i).replace('&', "&&")); + id = m->insertItem( name, t, SLOT( toDesktop(int) ) ); + m->setItemParameter( id, i ); + m->setItemChecked( id, !t->isOnAllDesktops() && t->desktop() == i ); + } + + return m; +} + +QPopupMenu* TaskRMBMenu::makeDesktopsMenu() +{ + QPopupMenu* m = new QPopupMenu( this ); + m->setCheckable( true ); + + int id = m->insertItem( i18n("&All Desktops"), this, SLOT( slotAllToDesktop(int) ) ); + m->setItemParameter( id, 0 ); // 0 means all desktops + + m->insertSeparator(); + + for (int i = 1; i <= TaskManager::the()->numberOfDesktops(); i++) { + QString name = QString("&%1 %2").arg(i).arg(TaskManager::the()->desktopName(i).replace('&', "&&")); + id = m->insertItem( name, this, SLOT( slotAllToDesktop(int) ) ); + m->setItemParameter( id, i ); + } + + return m; +} + +void TaskRMBMenu::slotMinimizeAll() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->setIconified(true); + } +} + +void TaskRMBMenu::slotMaximizeAll() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->setMaximized(true); + } +} + +void TaskRMBMenu::slotRestoreAll() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->restore(); + } +} + +void TaskRMBMenu::slotShadeAll() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->setShaded( !(*it)->isShaded() ); + } +} + +void TaskRMBMenu::slotCloseAll() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->close(); + } +} + +void TaskRMBMenu::slotAllToDesktop( int desktop ) +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->toDesktop( desktop ); + } +} + +void TaskRMBMenu::slotAllToCurrentDesktop() +{ + Task::List::iterator itEnd = tasks.end(); + for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it) + { + (*it)->toCurrentDesktop(); + } +} diff --git a/kicker/taskmanager/taskrmbmenu.h b/kicker/taskmanager/taskrmbmenu.h new file mode 100644 index 000000000..a167d6665 --- /dev/null +++ b/kicker/taskmanager/taskrmbmenu.h @@ -0,0 +1,59 @@ +/***************************************************************** + +Copyright (c) 2001 Matthias Elter <elter@kde.org> +Copyright (c) 2001 John Firebaugh <jfirebaugh@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __taskrmbmenu_h__ +#define __taskrmbmenu_h__ + +#include <qpopupmenu.h> + +class KDE_EXPORT TaskRMBMenu : public QPopupMenu +{ + Q_OBJECT + +public: + TaskRMBMenu(const Task::List&, bool showAll = true, QWidget *parent = 0, const char *name = 0); + TaskRMBMenu(Task::Ptr, bool showAll = true, QWidget *parent = 0, const char *name = 0); + +private: + void fillMenu(Task::Ptr); + void fillMenu(); + QPopupMenu* makeAdvancedMenu(Task::Ptr); + QPopupMenu* makeDesktopsMenu(Task::Ptr); + QPopupMenu* makeDesktopsMenu(); + +private slots: + void slotMinimizeAll(); + void slotMaximizeAll(); + void slotRestoreAll(); + void slotShadeAll(); + void slotCloseAll(); + void slotAllToDesktop( int desktop ); + void slotAllToCurrentDesktop(); + +private: + Task::List tasks; + bool showAll; +}; + +#endif |