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/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/kicker')
122 files changed, 21655 insertions, 0 deletions
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 |