rev 7542 - in branches/kde4/packages/kdebase-workspace/debian: . patches

Fathi Boudra fboudra-guest at alioth.debian.org
Thu Oct 18 22:16:00 UTC 2007


Author: fboudra-guest
Date: 2007-10-18 22:16:00 +0000 (Thu, 18 Oct 2007)
New Revision: 7542

Added:
   branches/kde4/packages/kdebase-workspace/debian/patches/01_kdebase-workspace_branch_r726786.diff
Removed:
   branches/kde4/packages/kdebase-workspace/debian/patches/01_pull_r726655_r725907_r725662_r725652_r725648_r725642.diff
Modified:
   branches/kde4/packages/kdebase-workspace/debian/changelog
Log:
* svn branch pull to r726786.


Modified: branches/kde4/packages/kdebase-workspace/debian/changelog
===================================================================
--- branches/kde4/packages/kdebase-workspace/debian/changelog	2007-10-18 21:35:03 UTC (rev 7541)
+++ branches/kde4/packages/kdebase-workspace/debian/changelog	2007-10-18 22:16:00 UTC (rev 7542)
@@ -1,5 +1,7 @@
 kdebase-workspace (4:3.94.0-1) experimental; urgency=low
 
+  * svn branch pull to r726786.
+
   +++ Changes by Armin Berres:
 
   * Remove some Oxygen icons from ksysguard which are already shipped by
@@ -13,9 +15,6 @@
   * Update *.install files.
   * Add libstrigiqtdbusclient-dev as build dependency (needed for kickoff).
   * Add dependency of kdebase-workspace-dev on kdepimlibs5-dev.
-  * Cherry pick some patches from upstream which are needed for
-    co-installability of kde4base and kde3libs and a correct search path for
-    kdm. Namely r726655, r725907, r725662, r725652, r725648 and r725642.
 
   +++ Changes by Fathi Boudra:
 

Added: branches/kde4/packages/kdebase-workspace/debian/patches/01_kdebase-workspace_branch_r726786.diff
===================================================================
--- branches/kde4/packages/kdebase-workspace/debian/patches/01_kdebase-workspace_branch_r726786.diff	                        (rev 0)
+++ branches/kde4/packages/kdebase-workspace/debian/patches/01_kdebase-workspace_branch_r726786.diff	2007-10-18 22:16:00 UTC (rev 7542)
@@ -0,0 +1,28873 @@
+--- a/ksmserver/shutdowndlg.cpp
++++ b/ksmserver/shutdowndlg.cpp
+@@ -23,7 +23,6 @@
+ ******************************************************************/
+ 
+ #include <config-workspace.h>
+-#include <config-X11.h>
+ 
+ #include "shutdowndlg.h"
+ #include "plasma/svg.h"
+@@ -38,7 +37,6 @@
+ #include <QTimer>
+ #include <QSvgRenderer>
+ #include <QPaintEvent>
+-#include <QPaintEngine>
+ 
+ #include <kdebug.h>
+ #include <kdialog.h>
+@@ -59,9 +57,6 @@
+ #include <dmctl.h>
+ 
+ #include <X11/Xlib.h>
+-#ifdef HAVE_XRENDER
+-#  include <X11/extensions/Xrender.h>
+-#endif
+ 
+ #include "shutdowndlg.moc"
+ #include <QX11Info>
+@@ -103,29 +98,7 @@
+     if ( m_currentY >= height() )
+         return;
+ 
+-    QPixmap pixmap( width(), 10 );
+-
+-    // grabWindow() is broken in Qt4 (because QPixmap is 32bpp).
+-    // Work around this bug by using Xrender to grab the screenshot, since
+-    // XRenderComposite() will convert the pixmap format automatically.
+-#ifdef HAVE_XRENDER
+-    if ( pixmap.paintEngine()->hasFeature( QPaintEngine::PorterDuff ) )
+-    {
+-        Display *dpy = QX11Info::display();
+-        Window root = DefaultRootWindow( dpy );
+-        XRenderPictureAttributes attr;
+-        attr.subwindow_mode = IncludeInferiors;
+-        XRenderPictFormat *format = XRenderFindVisualFormat( dpy, DefaultVisual( dpy, 0 ) );
+-        Picture rootPict = XRenderCreatePicture( dpy, root, format, CPSubwindowMode, &attr );
+-        XRenderComposite( dpy, PictOpSrc, rootPict, None, pixmap.x11PictureHandle(), 0, m_currentY,
+-                          0, 0, 0, 0, pixmap.width(), pixmap.height() );
+-        XRenderFreePicture( dpy, rootPict );
+-    } else
+-#endif
+-        pixmap = QPixmap::grabWindow( QX11Info::appRootWindow(), 0, m_currentY,
+-                                      pixmap.width(), pixmap.height() );
+-
+-    QImage image = pixmap.toImage();
++    QImage image = QPixmap::grabWindow( QX11Info::appRootWindow(), 0, m_currentY, width(), 10 ).toImage();
+     Blitz::intensity( image, -0.4 );
+     Blitz::grayscale( image );
+ 
+@@ -133,7 +106,7 @@
+     painter.drawImage( 0, m_currentY, image );
+     painter.end();
+ 
+-    m_currentY += pixmap.height();
++    m_currentY += 10;
+     update( 0, 0, width(), m_currentY );
+ 
+     QTimer::singleShot( 1, this, SLOT( slotPaintEffect() ) );
+--- a/ksmserver/server.h
++++ b/ksmserver/server.h
+@@ -33,10 +33,9 @@
+ #include <kapplication.h>
+ #include <kworkspace.h>
+ #include <QTimer>
+-#include <Qt3Support/Q3CString>
+ #include <QTime>
+ #include <QMap>
+-
++#include <Qt3Support/Q3CString>
+ #include "server2.h"
+ 
+ #define SESSION_PREVIOUS_LOGOUT "saved at previous logout"
+@@ -198,7 +197,6 @@
+     QString wm;
+     QString sessionGroup;
+     QString sessionName;
+-    Q3CString launcher;
+     QTimer protectionTimer;
+     QTimer restoreTimer;
+     QString xonCommand;
+--- a/ksmserver/CMakeLists.txt
++++ b/ksmserver/CMakeLists.txt
+@@ -41,7 +41,7 @@
+ 
+ kde4_add_kdeinit_executable( ksmserver ${ksmserver_KDEINIT_SRCS})
+ 
+-target_link_libraries(kdeinit_ksmserver plasma solidcontrol kworkspace ${KDE4_KDEUI_LIBS} ${BLITZ_LIBRARIES} ${QT_QT3SUPPORT_LIBRARY} ${X11_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBRARY} ${X11_Xrender_LIB})
++target_link_libraries(kdeinit_ksmserver plasma solidcontrol kworkspace ${KDE4_KDEUI_LIBS} ${BLITZ_LIBRARIES} ${QT_QT3SUPPORT_LIBRARY} ${X11_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBRARY})
+ 
+ install(TARGETS kdeinit_ksmserver  DESTINATION ${LIB_INSTALL_DIR})
+ 
+--- a/ConfigureChecks.cmake
++++ b/ConfigureChecks.cmake
+@@ -1,4 +1,5 @@
+ include(UnixAuth)
++include(CheckTypeSize)
+ 
+ macro_optional_find_package(XKB) # kxkb, kdm
+ 
+--- a/kcontrol/dateandtime/tzone.h
++++ b/kcontrol/dateandtime/tzone.h
+@@ -22,11 +22,11 @@
+ #ifndef tzone_included
+ #define tzone_included
+ 
+-#include <Qt3Support/Q3GroupBox>
+ //Added by qt3to4:
+ #include <QLabel>
+ #include <ktimezone.h>
+ #include <ktimezonewidget.h>
++#include <QGroupBox>
+ 
+ class QLabel;
+ 
+--- a/kcontrol/dateandtime/clock.desktop
++++ b/kcontrol/dateandtime/clock.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kde-clock.desktop
++Exec=kcmshell4 kde-clock.desktop
+ Icon=preferences-system-time
+ Type=Service
+ ServiceTypes=KCModule
+@@ -12,7 +12,7 @@
+ X-KDE-ParentApp=kcontrol
+ 
+ #FIXME should this be in system settings when we can get to it through the panel?
+-X-KDE-System-Settings-Parent-Category=date-and-time
++X-KDE-System-Settings-Parent-Category=computer-administration
+ 
+ Name=Date & Time
+ Name[af]=Datum & Tyd
+--- a/kcontrol/background/background.desktop
++++ b/kcontrol/background/background.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell background
++Exec=kcmshell4 background
+ Icon=preferences-desktop-wallpaper
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/kfontinst/kcmfontinst/KCmFontInst.cpp
++++ b/kcontrol/kfontinst/kcmfontinst/KCmFontInst.cpp
+@@ -40,6 +40,7 @@
+ #include <QTextStream>
+ #include <QComboBox>
+ #include <QProcess>
++#include <QPainter>
+ #include <kaboutdata.h>
+ #include <ktoolbar.h>
+ #include <kfiledialog.h>
+@@ -111,6 +112,8 @@
+         sh.setHeight(theirHeight);
+         if(sh.width()<sh.height())
+             sh.setWidth(sh.height());
++        else if(text().isEmpty())
++            sh.setWidth(theirHeight);
+         return sh;
+     }
+ 
+@@ -127,6 +130,14 @@
+         : KToolBar(parent)
+     {
+         theirHeight=qMax(theirHeight, height());
++        setMovable(false);
++        setFloatable(false);
++        setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
++    }
++
++    void addSeparator()
++    {
++        addWidget(new QLabel(" ", this));
+     }
+ 
+     void link(CToolBar *l)
+@@ -142,6 +153,14 @@
+         return sh;
+     }
+ 
++    void paintEvent(QPaintEvent *)
++    {
++        QColor col(palette().color(backgroundRole()));
++
++        col.setAlphaF(0.0);
++        QPainter(this).fillRect(rect(), col);
++    }
++
+     void resizeEvent(QResizeEvent *ev)
+     {
+         KToolBar::resizeEvent(ev);
+@@ -242,7 +261,6 @@
+     itsPreviewControl=new CPreviewSelectAction(itsPreviewWidget);
+ 
+     previewToolbar->addAction(itsPreviewControl);
+-    previewToolbar->setMovable(false);
+ 
+     previewLayout->setMargin(0);
+     previewLayout->setSpacing(KDialog::spacingHint());
+@@ -284,8 +302,6 @@
+     itsToolsMenu->setDelayed(false);
+     toolbar->addAction(settingsMenu);
+     toolbar->addAction(itsToolsMenu);
+-    toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+-    toolbar->setMovable(false);
+     if(Misc::root())
+         itsModeControl=NULL;
+     else
+--- a/kcontrol/kfontinst/kcmfontinst/FontList.cpp
++++ b/kcontrol/kfontinst/kcmfontinst/FontList.cpp
+@@ -60,6 +60,10 @@
+ // cached to disk.
+ #define KFI_SAVE_PIXMAPS
+ 
++#ifdef KFI_FONTLIST_DEBUG
++#include <kdebug.h>
++#endif
++
+ namespace KFI
+ {
+ 
+@@ -239,6 +243,40 @@
+     return rv;
+ }
+ 
++QString capitaliseFoundry(const QString &foundry)
++{
++    QString f(foundry.toLower());
++
++    if(f==QString::fromLatin1("ibm"))
++        return QString::fromLatin1("IBM");
++    else if(f==QString::fromLatin1("urw"))
++        return QString::fromLatin1("URW");
++    else if(f==QString::fromLatin1("itc"))
++        return QString::fromLatin1("ITC");
++    else if(f==QString::fromLatin1("nec"))
++        return QString::fromLatin1("NEC");
++    else if(f==QString::fromLatin1("b&h"))
++        return QString::fromLatin1("B&H");
++    else
++    {
++        QChar   *ch(f.data());
++        int     len(f.length());
++        bool    isSpace(true);
++
++        while(len--)
++        {
++            if (isSpace)
++                *ch=ch->toUpper();
++
++            isSpace=ch->isSpace();
++            ++ch;
++        }
++
++    }
++
++    return f;
++}
++
+ static void toggle(QString &file, bool enable)
+ {
+     QString newFile(enable
+@@ -383,22 +421,21 @@
+ 
+ CFontItem::CFontItem(CFontModelItem *p, const KFileItem &item, const QString &style)
+          : CFontModelItem(p),
+-           itsItem(item),
+            itsStyle(style),
+            itsPixmap(NULL)
+ {
+-    const KIO::UDSEntry &udsEntry(entry());
++    const KIO::UDSEntry &udsEntry(item.entry());
+ 
+-    updateStatus();
++    setUrl(item.url());
+     itsName=udsEntry.stringValue(KIO::UDSEntry::UDS_NAME);
+     itsFileName=udsEntry.stringValue((uint)UDS_EXTRA_FILE_NAME);
+     itsStyleInfo=udsEntry.numberValue((uint)UDS_EXTRA_FC_STYLE);
+     itsIndex=Misc::getIntQueryVal(KUrl(udsEntry.stringValue((uint)KIO::UDSEntry::UDS_URL)),
+                                   KFI_KIO_FACE, 0);
+     itsWritingSystems=udsEntry.numberValue((uint)UDS_EXTRA_WRITING_SYSTEMS);
+-    QString mime(mimetype());
+-
+-    itsBitmap="application/x-font-pcf"==mime || "application/x-font-bdf"==mime;
++    itsMimeType=item.mimetype();
++    itsBitmap="application/x-font-pcf"==itsMimeType || "application/x-font-bdf"==itsMimeType;
++    itsSize=item.size();
+ 
+     if(!Misc::root())
+         setIsSystem(isSysFolder(url().path().section('/', 1, 1)));
+@@ -421,9 +458,10 @@
+ #endif
+ }
+ 
+-void CFontItem::updateStatus()
++void CFontItem::setUrl(const KUrl &url)
+ {
+-    itsEnabled=!Misc::isHidden(url());
++    itsUrl=url;
++    itsEnabled=!Misc::isHidden(itsUrl);
+ 
+     if(!itsFiles.isEmpty()) // Then we changed state, so need to alter filename list...
+     {
+@@ -478,7 +516,7 @@
+                                       fEnd(itsFonts.end());
+ 
+     for(; fIt!=fEnd; ++fIt)
+-        if((*(*fIt)).item()==i)
++        if((*(*fIt)).url()==i.url())
+             return (*fIt);
+ 
+     return NULL;
+@@ -496,7 +534,7 @@
+ 
+         for(; fIt!=fEnd; ++fIt)
+             if(!(*fIt).foundry.isEmpty())
+-                foundries.insert((*fIt).foundry);
++                foundries.insert(capitaliseFoundry((*fIt).foundry));
+     }
+ }
+ 
+@@ -655,8 +693,8 @@
+             SLOT(newItems(const KFileItemList &)));
+     connect(itsLister, SIGNAL(deleteItems(const KFileItemList &)),
+             SLOT(deleteItems(const KFileItemList &)));
+-    connect(itsLister, SIGNAL(refreshItems(const KFileItemList &)),
+-            SLOT(refreshItems(const KFileItemList &)));
++    connect(itsLister, SIGNAL(renameItems(const RenameList &)),
++            SLOT(renameItems(const RenameList &)));
+     connect(itsLister, SIGNAL(percent(int)), SIGNAL(percent(int)));
+     connect(itsLister, SIGNAL(message(QString)), SIGNAL(status(QString)));
+ }
+@@ -915,8 +953,8 @@
+ #ifdef KFI_FONTLIST_DEBUG
+     kDebug() << "************** newItems " << items.count();
+ 
+-    for(KFileItemList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
+-        kDebug() << "               " << (int)(*it);
++//     for(KFileItemList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
++//         kDebug() << "               " << (int)(*it);
+ #endif
+ 
+     for(KFileItemList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
+@@ -938,35 +976,38 @@
+     itsFonts.clear();
+ }
+ 
+-void CFontList::refreshItems(const KFileItemList &items)
++void CFontList::renameItems(const RenameList &items)
+ {
+     emit layoutAboutToBeChanged();
+ 
+ #ifdef KFI_FONTLIST_DEBUG
+-    kDebug() << "************** refreshItems " << items.count();
++    kDebug() << "************** renameItems " << items.count();
+ 
+-    for(KFileItemList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
+-        kDebug() << "               " << (int)(*it);
++    for(RenameList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
++        kDebug() << "               " << (*it).from.prettyUrl();
+ #endif
+ 
+     QSet<CFamilyItem *> families;
+ 
+-    for(KFileItemList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
++    for(RenameList::const_iterator it(items.begin()), end(items.end()) ; it!=end ; ++it)
+     {
+-        CFontItem *font=findFont(*it);
++        CFontItem *font=findFont((*it).from);
+ 
+         if(font)
+         {
+-            font->updateStatus();
++            font->setUrl((*it).to);
++            itsFonts.insert((*it).to, font);
++            itsFonts.erase(itsFonts.find((*it).from));
+ #ifdef KFI_FONTLIST_DEBUG
+             kDebug() << "               Found font, status now:" << font->isEnabled()
+-                     << " url" << (*it)->url().prettyUrl();
++                     << " from:" << (*it).from.prettyUrl()
++                     << " to:" << (*it).to.prettyUrl();
+ #endif
+             families.insert(static_cast<CFamilyItem *>(font->parent()));
+         }
+ #ifdef KFI_FONTLIST_DEBUG
+         else
+-            kDebug() << "               Could not locate font :-( " << (int)(*it);
++            kDebug() << "               Could not locate font :-( " << (*it).from.prettyUrl();
+ #endif
+     }
+ 
+@@ -992,7 +1033,7 @@
+ 
+     for(; it!=end; ++it)
+     {
+-        CFontItem *font=findFont(*it);
++        CFontItem *font=findFont((*it).url());
+ 
+         if(font)
+         {
+@@ -1002,7 +1043,7 @@
+                 itsFamilies.removeAll(fam);
+             else
+                 fam->removeFont(font);
+-            itsFonts.remove(*it);
++            itsFonts.remove((*it).url());
+         }
+     }
+ 
+@@ -1011,7 +1052,7 @@
+ 
+ void CFontList::addItem(const KFileItem &item)
+ {
+-    CFontItem *font=findFont(item);
++    CFontItem *font=findFont(item.url());
+ 
+ #ifdef KFI_FONTLIST_DEBUG
+     kDebug() << "************** addItem " << item.url();
+@@ -1030,7 +1071,7 @@
+             font=new CFontItem(fam, item, style);
+ 
+             fam->addFont(font);
+-            itsFonts.insert(item, font);
++            itsFonts.insert(item.url(), font);
+         }
+ #ifdef KFI_FONTLIST_DEBUG
+         else
+@@ -1062,10 +1103,10 @@
+     return fam;
+ }
+ 
+-CFontItem * CFontList::findFont(const KFileItem &item)
++CFontItem * CFontList::findFont(const KUrl &url)
+ {
+-    return itsFonts.contains(item)
+-            ? itsFonts[item]
++    return itsFonts.contains(url)
++            ? itsFonts[url]
+             : NULL;
+ }
+ 
+@@ -1266,7 +1307,7 @@
+                                                              end(fnt->files().end());
+ 
+                     for(; it!=end && !fontMatch; ++it)
+-                        fontMatch=-1!=(*it).foundry.indexOf(itsFilterText, 0, Qt::CaseInsensitive);
++                        fontMatch=0==(*it).foundry.compare(itsFilterText, Qt::CaseInsensitive);
+                     break;
+                 }
+                 case CFontFilter::CRIT_FILENAME:
+--- a/kcontrol/kfontinst/kcmfontinst/JobRunner.cpp
++++ b/kcontrol/kfontinst/kcmfontinst/JobRunner.cpp
+@@ -59,6 +59,58 @@
+     return url;
+ }
+ 
++class CSkipDialog : public KDialog
++{
++    public:
++
++    enum Result
++    {
++        SKIP,
++        AUTO_SKIP,
++        CANCEL
++    };
++
++    CSkipDialog(QWidget *parent, bool multi, const QString &errorText)
++        : KDialog(parent),
++          itsResult(CANCEL)
++    {
++        setCaption(i18n( "Information"));
++        setButtons(multi ? Cancel|User1|User2 : Cancel );
++        setButtonText(User1, i18n("Skip"));
++        setButtonText(User2, i18n("AutoSkip"));
++        setMainWidget(new QLabel(errorText, this));
++        resize(sizeHint());
++    }
++
++    Result go()
++    {
++        itsResult=CANCEL;
++        exec();
++        return itsResult;
++    }
++
++    void slotButtonClicked(int button)
++    {
++        switch(button)
++        {
++            case User1:
++                itsResult=SKIP;
++                break;
++            case User2:
++                itsResult=AUTO_SKIP;
++                break;
++            default:
++                itsResult=CANCEL;
++        }
++
++        KDialog::accept();
++    }
++
++    private:
++
++    Result itsResult;
++};
++
+ class CPasswordDialog : public KPasswordDialog
+ {
+     public:
+@@ -324,7 +376,7 @@
+                 break;
+             case CMD_DISABLE:
+                 itsStatusLabel->setText(i18n("Disabling %1", (*itsIt).displayName()));
+-                job=KIO::rename(*itsIt, toggle(*itsIt, KIO::HideProgressInfo), KIO::HideProgressInfo);
++                job=KIO::rename(*itsIt, toggle(*itsIt, false), KIO::HideProgressInfo);
+                 break;
+             case CMD_MOVE:
+             {
+@@ -384,17 +436,17 @@
+             }
+             else
+             {
+-                KIO::SkipDialog dlg(this, true, job->errorString());
++                CSkipDialog dlg(this, true, job->errorString());
+ 
+-                switch(dlg.exec())
++                switch(dlg.go())
+                 {
+-                    case KIO::S_SKIP:
++                    case CSkipDialog::SKIP:
+                         cont=true;
+                         break;
+-                    case KIO::S_AUTO_SKIP:
++                    case CSkipDialog::AUTO_SKIP:
+                         cont=itsAutoSkip=true;
+                         break;
+-                    case KIO::S_CANCEL:
++                    case CSkipDialog::CANCEL:
+                         break;
+                 }
+             }
+--- a/kcontrol/kfontinst/kcmfontinst/FontFilter.cpp
++++ b/kcontrol/kfontinst/kcmfontinst/FontFilter.cpp
+@@ -57,7 +57,7 @@
+     itsPixmaps[CRIT_FAMILY]=SmallIcon("text");
+     itsPixmaps[CRIT_STYLE]=SmallIcon("format-text-bold");
+     itsPixmaps[CRIT_FOUNDRY]=SmallIcon("user");
+-    itsPixmaps[CRIT_FONTCONFIG]=SmallIcon("file-find");
++    itsPixmaps[CRIT_FONTCONFIG]=SmallIcon("edit-find");
+     itsPixmaps[CRIT_FILENAME]=SmallIcon("font-type1");
+     itsPixmaps[CRIT_LOCATION]=SmallIcon("folder");
+     itsPixmaps[CRIT_WS]=SmallIcon("pencil");
+@@ -122,7 +122,19 @@
+     QStringList list(foundries.toList());
+ 
+     list.sort();
+-    ((KSelectAction *)itsActions[CRIT_FOUNDRY])->setItems(list);
++
++    // Add foundries to menu - replacing '&' with '&&', as '&' is taken to be
++    // a shortcut!
++    QStringList::ConstIterator it(list.begin()),
++                               end(list.end());
++
++    for(; it!=end; ++it)
++    {
++        QString foundry(*it);
++
++        foundry.replace("&", "&&");
++        ((KSelectAction *)itsActions[CRIT_FOUNDRY])->addAction(foundry);
++    }
+ 
+     if(!prev.isEmpty())
+     {
+@@ -191,7 +203,7 @@
+             setReadOnly(true);
+             modifyPadding();
+             setCriteria(itsCurrentCriteria);
+-            setText(i18n("%1 (Writing System)", act->text()));
++            setText(act->text());
+             setClickMessage(text());
+         }
+     }
+@@ -280,14 +292,16 @@
+ {
+     QPixmap arrowmap(itsPixmaps[crit].width()+constArrowPad, itsPixmaps[crit].height());
+ 
+-    arrowmap.fill(palette().color(QPalette::Active, QPalette::Base));
++    QColor bgnd(palette().color(QPalette::Active, QPalette::Base));
++    bgnd.setAlphaF(0.0);
++    arrowmap.fill(bgnd);
+ 
+     QPainter p(&arrowmap);
+ 
+     p.drawPixmap(0, 0, itsPixmaps[crit]);
+     QStyleOption opt;
+     opt.state = QStyle::State_Enabled;
+-    opt.rect = QRect(arrowmap.width()-(constArrowPad+1), arrowmap.height()-constArrowPad, constArrowPad+1, constArrowPad);
++    opt.rect = QRect(arrowmap.width()-(constArrowPad+1), arrowmap.height()-(constArrowPad+1), constArrowPad, constArrowPad);
+     style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, itsMenuButton);
+     p.end();
+ 
+--- a/kcontrol/kfontinst/kcmfontinst/FontLister.h
++++ b/kcontrol/kfontinst/kcmfontinst/FontLister.h
+@@ -34,6 +34,17 @@
+ namespace KFI
+ {
+ 
++struct Rename
++{
++    Rename(const KUrl &f, const KUrl &t)
++        : from(f), to(t) { }
++
++    KUrl from,
++         to;
++};
++
++typedef QList<Rename> RenameList;
++
+ class CFontLister : public QObject
+ {
+     Q_OBJECT
+@@ -49,6 +60,7 @@
+ 
+     public:
+ 
++
+     CFontLister(QObject *parent);
+ 
+     void scan(const KUrl &url=KUrl());
+@@ -59,7 +71,7 @@
+ 
+     void newItems(const KFileItemList &items);
+     void deleteItems(const KFileItemList &items);
+-    void refreshItems(const KFileItemList &items);
++    void renameItems(const RenameList &items);
+     void started();
+     void completed();
+     void percent(int);
+@@ -87,13 +99,13 @@
+ 
+     typedef QHash<KUrl, KFileItem> ItemCont;
+ 
+-    EListing      itsListing;
+-    ItemCont      itsItems;
+-    bool          itsAutoUpdate,
+-                  itsUpdateRequired;
+-    KIO::Job      *itsJob;
+-    qulonglong    itsJobSize;
+-    KFileItemList itsItemsToRefresh;
++    EListing   itsListing;
++    ItemCont   itsItems;
++    bool       itsAutoUpdate,
++               itsUpdateRequired;
++    KIO::Job   *itsJob;
++    qulonglong itsJobSize;
++    RenameList itsItemsToRename;
+ };
+ 
+ }
+--- a/kcontrol/kfontinst/kcmfontinst/FontList.h
++++ b/kcontrol/kfontinst/kcmfontinst/FontList.h
+@@ -125,25 +125,25 @@
+     void            listingCompleted();
+     void            newItems(const KFileItemList &items);
+     void            clearItems();
+-    void            deleteItems(const KFileItemList &);
+-    void            refreshItems(const KFileItemList &);
++    void            deleteItems(const KFileItemList &items);
++    void            renameItems(const RenameList &items);
+ 
+     private:
+ 
+     void            addItem(const KFileItem &item);
+     CFamilyItem *   findFamily(const QString &familyName, bool create=false);
+-    CFontItem *     findFont(const KFileItem &item);
++    CFontItem *     findFont(const KUrl &url);
+     void            touchThumbnails();
+ 
+     private:
+ 
+-    QList<CFamilyItem *>                  itsFamilies;
+-    QHash<const KFileItem, CFontItem *>   itsFonts;   // Use for quick searching...
+-    CFontLister                           *itsLister;
+-    bool                                  itsAllowSys,
+-                                          itsAllowUser,
+-                                          itsAllowDisabled;
+-    static int                            theirPreviewSize;
++    QList<CFamilyItem *>     itsFamilies;
++    QHash<KUrl, CFontItem *> itsFonts;   // Use for quick searching...
++    CFontLister              *itsLister;
++    bool                     itsAllowSys,
++                             itsAllowUser,
++                             itsAllowDisabled;
++    static int               theirPreviewSize;
+ };
+ 
+ class CFontModelItem
+@@ -225,13 +225,11 @@
+ 
+     void                              touchThumbnail();
+     const QString &                   name() const             { return itsName; }
+-    QString                           mimetype() const         { return itsItem.mimetype(); }
++    QString                           mimetype() const         { return itsMimeType; }
+     bool                              isEnabled() const        { return itsEnabled; }
+     bool                              isHidden() const         { return !itsEnabled; }
+-    void                              updateStatus();
+-    KUrl                              url() const              { return itsItem.url(); }
+-    KIO::UDSEntry                     entry() const            { return itsItem.entry(); }
+-    KFileItem                         item() const             { return itsItem; }
++    void                              setUrl(const KUrl &url);
++    KUrl                              url() const              { return itsUrl; }
+     bool                              isBitmap() const         { return itsBitmap; }
+     const QString &                   fileName() const         { return itsFileName; }
+     const QString &                   style() const            { return itsStyle; }
+@@ -242,15 +240,16 @@
+     void                              clearPixmap()            { itsPixmap=NULL; }
+     int                               rowNumber() const        { return (static_cast<CFamilyItem *>(parent()))->row(this); }
+     const CDisabledFonts::TFileList & files() const            { return itsFiles; }
+-    KIO::filesize_t                   size() const             { return !itsItem.isNull() ? itsItem.size() : 0; }
++    KIO::filesize_t                   size() const             { return itsSize; }
+     qulonglong                        writingSystems() const   { return itsWritingSystems; }
+ 
+     private:
+ 
+-    KFileItem                 itsItem;
++    KUrl                      itsUrl;
+     QString                   itsName,
+                               itsFileName,
+-                              itsStyle;
++                              itsStyle,
++                              itsMimeType;
+     int                       itsIndex;
+     QPixmap                   *itsPixmap;
+     quint32                   itsStyleInfo;
+@@ -258,6 +257,7 @@
+                               itsEnabled;
+     CDisabledFonts::TFileList itsFiles;
+     qulonglong                itsWritingSystems;
++    KIO::filesize_t           itsSize;
+ };
+ 
+ class CFontListSortFilterProxy : public QSortFilterProxyModel
+--- a/kcontrol/kfontinst/kcmfontinst/FontLister.cpp
++++ b/kcontrol/kfontinst/kcmfontinst/FontLister.cpp
+@@ -55,10 +55,10 @@
+ {
+     if(!busy())
+     {
+-        if(itsItemsToRefresh.count())
++        if(itsItemsToRename.count())
+         {
+-            emit refreshItems(itsItemsToRefresh);
+-            itsItemsToRefresh.clear();
++            emit renameItems(itsItemsToRename);
++            itsItemsToRename.clear();
+         }
+ 
+         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+@@ -97,10 +97,10 @@
+         itsAutoUpdate=on;
+         if(on && itsUpdateRequired)
+         {
+-            if(itsItemsToRefresh.count())
++            if(itsItemsToRename.count())
+             {
+-                emit refreshItems(itsItemsToRefresh);
+-                itsItemsToRefresh.clear();
++                emit renameItems(itsItemsToRename);
++                itsItemsToRename.clear();
+             }
+             itsUpdateRequired=false;
+             scan();
+@@ -110,13 +110,17 @@
+ 
+ void CFontLister::fileRenamed(const QString &from, const QString &to)
+ {
+-    KUrl          fromU(from);
+-    KFileItemList refresh;
++    KUrl       fromU(from);
++    RenameList rename;
+ 
+     if(KFI_KIO_FONTS_PROTOCOL==fromU.protocol())
+     {
+         ItemCont::Iterator it(itsItems.find(fromU));
+ 
++#ifdef KFI_FONTLISTER_DEBUG
++        kDebug() << "fileRenamed from: " << from << " to: " << to;
++#endif
++
+         if(it!=itsItems.end())
+         {
+             KFileItem item(*it);
+@@ -124,6 +128,7 @@
+ 
+             item.setUrl(toU);
+             itsItems.erase(it);
++
+             if(itsItems.contains(toU))
+             {
+                 KFileItemList items;
+@@ -134,18 +139,22 @@
+             else
+             {
+                 itsItems[toU]=item;
+-                refresh.append(item);
++                rename.append(Rename(fromU, toU));
+             }
+         }
++#ifdef KFI_FONTLISTER_DEBUG
++        else
++            kDebug() << "Item not found???";
++#endif
+     }
+ 
+-    if(refresh.count())
++    if(rename.count())
+         if(itsAutoUpdate)
+-            emit refreshItems(refresh);
++            emit renameItems(rename);
+         else
+         {
+             itsUpdateRequired=true;
+-            itsItemsToRefresh+=refresh;
++            itsItemsToRename+=rename;
+         }
+ }
+ 
+@@ -273,14 +282,14 @@
+                 KFileItem item(*it, url);
+ 
+ #ifdef KFI_FONTLISTER_DEBUG
+-                kDebug() << "New item:" << item->url().prettyUrl();
++                kDebug() << "New item:" << item.url().prettyUrl();
+ #endif
+                 itsItems[url]=item;
+                 newFonts.append(item);
+             }
+             itsItems[url].mark();
+ #ifdef KFI_FONTLISTER_DEBUG
+-            kDebug() << "Marking:" << itsItems[url]->url().prettyUrl();
++            kDebug() << "Marking:" << itsItems[url].url().prettyUrl() << " [" << url << ']';
+ #endif
+         }
+     }
+--- a/kcontrol/kfontinst/kcmfontinst/fontinst.desktop
++++ b/kcontrol/kfontinst/kcmfontinst/fontinst.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell fontinst
++Exec=kcmshell4 fontinst
+ Icon=preferences-desktop-font-installer
+ Type=Service
+ ServiceTypes=KCModule
+@@ -80,11 +80,12 @@
+ Comment[bg]=Инсталиране и преглед на шрифтове
+ Comment[de]=Schriftarten installieren, verwalten und betrachten
+ Comment[el]=Εγκατάσταση, διαχείριση και προεπισκόπηση γραμματοσειρών
++Comment[et]=Fontide haldamine, paigaldamine ja eelvaatlus
+ Comment[ga]=Suiteáil, bainisteoireacht, agus réamhamharc na gclónna
+ Comment[it]=Installa, gestisce e mostra anteprime dei caratteri
+ Comment[ja]=フォントのインストール、管理とプレビュー
+ Comment[kk]=Қаріптерді орнату, басқару және қарау
+-Comment[km]=ដំឡើង, គ្រប់គ្រង, និង​មើល​ពុម្ពអក្សរ​ជា​មុន
++Comment[km]=ដំឡើង គ្រប់គ្រង និង​មើល​ពុម្ពអក្សរ​ជា​មុន
+ Comment[ko]=글꼴 설치, 미리보기, 관리
+ Comment[nb]=Installer, styr og forhåndsvis skrifttyper
+ Comment[nds]=Schriftoorden installeren, plegen un ankieken
+@@ -105,12 +106,13 @@
+ Keywords[de]=Schrift,Fonts,Schriftarten,Installation,TrueType,Type1,Speedo,Bitmapschriften
+ Keywords[el]=γραμματοσειρά,γραμματοσειρές,εγκαταστάτης,εγκατάσταση,truetype,type1,bitmap
+ Keywords[es]=tipo de letra,tipos de letra,instalador,truetype,type1,mapa de bits
++Keywords[et]=font,fondid,paigaldaja,truetype,type1,bitmap
+ Keywords[fa]=قلم، قلمها، نصب‌کننده، قلم حقیقی، نوع۱، نگاشت بیت
+ Keywords[ga]=cló,clónna,clófhoirne,suiteálaí,truetype,type1,mapa giotán,giotánmhapach
+ Keywords[he]=גופן,גופנים,מתקין,התקנה,מפת סיביות,font,fonts,installer,truetype,type1,bitmap
+ Keywords[it]=font,caratteri,installatore,truetype,type1,bitmap,tipi di carattere
+ Keywords[ja]=フォント,インストーラ,truetype,type1,bitmap,ビットマップ
+-Keywords[km]=ពុម្ព​អក្សរ,ពុម្ព​អក្សរ,កម្មវិធី​ដំឡើង,truetype,ប្រភេទ ១,រូបភាព
++Keywords[km]=ពុម្ព​អក្សរ ពុម្ព​អក្សរ កម្មវិធី​ដំឡើង truetype ប្រភេទ ១ រូបភាព
+ Keywords[ko]=글꼴,트루타입,타입 1,비트맵,type1,bitmap
+ Keywords[nb]=skrift,skrifter,skrifttype,skrifttyper,installer,truetype,type1,bitmap
+ Keywords[nds]=Schriftoort,Schriftoorden,Installeren,TrueType,Type1,Bitmap
+--- a/kcontrol/kfontinst/viewpart/kfontviewpart.desktop
++++ b/kcontrol/kfontinst/viewpart/kfontviewpart.desktop
+@@ -15,7 +15,7 @@
+ Name[el]=Προβολέας γραμματοσειρών
+ Name[eo]=Tiparorigardilo
+ Name[es]=Visor del tipo de letra
+-Name[et]=Fontide vaataja
++Name[et]=Fontide näitaja
+ Name[eu]=Letra-tipo ikustailea
+ Name[fa]=مشاهده‌گر قلم
+ Name[fi]=Kirjasinten näytin
+--- a/kcontrol/kfontinst/kio/KioFonts.h
++++ b/kcontrol/kfontinst/kio/KioFonts.h
+@@ -97,7 +97,7 @@
+     struct TFolder
+     {
+         TFolder() : disabled(NULL) { }
+-        void  setLocation(const QString &l, const QString &d, bool sys);
++        void  setLocation(const QString &l, bool sys);
+ 
+         QString        location;
+         CDirList       modified;
+--- a/kcontrol/kfontinst/kio/KioFonts.cpp
++++ b/kcontrol/kfontinst/kio/KioFonts.cpp
+@@ -830,7 +830,7 @@
+             dir=defaultDir;
+         }
+         mainFolder=FOLDER_USER;
+-        itsFolders[FOLDER_USER].setLocation(dir, dir, false);
++        itsFolders[FOLDER_USER].setLocation(dir, false);
+     }
+ 
+     QString sysDefault("/usr/local/share/fonts/"),
+@@ -850,7 +850,7 @@
+         sysDir=sysDefault;
+     }
+ 
+-    itsFolders[FOLDER_SYS].setLocation(sysDir, KFI_ROOT_CFG_DIR, true);
++    itsFolders[FOLDER_SYS].setLocation(sysDir, true);
+ 
+     //
+     // Ensure exists
+@@ -3406,11 +3406,11 @@
+             : DEFAULT_TIMEOUT;
+ }
+ 
+-void CKioFonts::TFolder::setLocation(const QString &l, const QString &d, bool sys)
++void CKioFonts::TFolder::setLocation(const QString &l, bool sys)
+ {
+     location=l;
+     delete disabled;
+-    disabled=new CDisabledFonts(d.isEmpty() ? l : d, sys);
++    disabled=new CDisabledFonts(sys);
+ }
+ 
+ }
+--- a/kcontrol/kfontinst/apps/Viewer.cpp
++++ b/kcontrol/kfontinst/apps/Viewer.cpp
+@@ -25,7 +25,8 @@
+ #include <kcmdlineargs.h>
+ #include <kaboutdata.h>
+ #include <kapplication.h>
+-#include <klibloader.h>
++#include <kpluginloader.h>
++#include <kpluginfactory.h>
+ #include <klocale.h>
+ #include <kglobal.h>
+ #include <kfiledialog.h>
+@@ -42,7 +43,7 @@
+ 
+ CViewer::CViewer()
+ {
+-    KPluginFactory *factory=KLibLoader::self()->factory("libkfontviewpart");
++    KPluginFactory *factory=KPluginLoader("libkfontviewpart").factory();
+ 
+     if(factory)
+     {
+--- a/kcontrol/kfontinst/apps/kfontview.desktop
++++ b/kcontrol/kfontinst/apps/kfontview.desktop
+@@ -35,7 +35,7 @@
+ GenericName[el]=Προβολέας γραμματοσειρών
+ GenericName[eo]=Tipara rigardilo
+ GenericName[es]=Visor del tipo de letra
+-GenericName[et]=Fontide vaataja
++GenericName[et]=Fontide näitaja
+ GenericName[eu]=Letra-tipoen ikusgailua
+ GenericName[fa]=مشاهده‌گر قلم
+ GenericName[fi]=Kirjasinten näytin
+--- a/kcontrol/kfontinst/apps/Printer.cpp
++++ b/kcontrol/kfontinst/apps/Printer.cpp
+@@ -27,7 +27,8 @@
+ #include <QFontDatabase>
+ #include <QWidget>
+ #include <QFile>
+-#include <kprinter.h>
++#include <QPrinter>
++#include <QPrintDialog>
+ #include <kcmdlineargs.h>
+ #include <kaboutdata.h>
+ #include <kapplication.h>
+@@ -88,11 +89,12 @@
+             appFont[(*it).family]=-1;
+     }
+ #endif
+-    KPrinter printer;
++    QPrinter     printer;
++    QPrintDialog dialog(&printer, parent);
+ 
+-    printer.setFullPage(true);
++    dialog.setWindowTitle(i18n("Print"));
+ 
+-    if(printer.setup(parent))
++    if(dialog.exec())
+     {
+         QPainter   painter;
+         QFont      sans("sans", 12, QFont::Bold);
+--- a/kcontrol/kfontinst/apps/installfont.desktop
++++ b/kcontrol/kfontinst/apps/installfont.desktop
+@@ -2,6 +2,7 @@
+ Encoding=UTF-8
+ ServiceTypes=application/x-font-ttf,application/x-font-type1,application/x-font-bdf,application/x-font-pcf,application/x-font-otf,application/x-font-afm,fonts/package
+ Actions=installFont;
++Type=Service
+ 
+ [Desktop Action installFont]
+ Name=Install...
+@@ -9,6 +10,7 @@
+ Name[bg]=Инсталиране...
+ Name[de]=Installieren ...
+ Name[el]=Εγκατάσταση...
++Name[et]=Paigalda...
+ Name[ga]=Suiteáil...
+ Name[it]=Installa...
+ Name[ja]=インストール...
+--- a/kcontrol/kfontinst/apps/CMakeLists.txt
++++ b/kcontrol/kfontinst/apps/CMakeLists.txt
+@@ -17,7 +17,7 @@
+ set_target_properties(kfontview_bin PROPERTIES OUTPUT_NAME kfontview)
+ 
+ target_link_libraries(kfontinst_bin ${KDE4_KIO_LIBS} ${KDE4_KDESU_LIBS} kfontinst )
+-target_link_libraries(kfontprint_bin ${KDE4_KDEPRINT_LIBS} kfontinstui kfontinst )
++target_link_libraries(kfontprint_bin kfontinstui kfontinst )
+ target_link_libraries(kfontview_bin ${KDE4_KPARTS_LIBS} kfontinstui kfontinst )
+ 
+ install(TARGETS kfontinst_bin DESTINATION ${BIN_INSTALL_DIR} )
+@@ -26,6 +26,5 @@
+ install(FILES kfontviewui.rc DESTINATION ${DATA_INSTALL_DIR}/kfontview )
+ install(FILES kfontview.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
+ install(FILES installfont.desktop DESTINATION ${DATA_INSTALL_DIR}/konqueror/servicemenus )
+-install(FILES installfont.desktop DESTINATION ${DATA_INSTALL_DIR}/dolphin/servicemenus )
+ 
+ kde4_install_icons( ${ICON_INSTALL_DIR} )
+--- a/kcontrol/kfontinst/lib/DisabledFonts.cpp
++++ b/kcontrol/kfontinst/lib/DisabledFonts.cpp
+@@ -33,6 +33,7 @@
+ #include <klockfile.h>
+ #include <ksavefile.h>
+ #include <klocale.h>
++#include <kstandarddirs.h>
+ #include <fontconfig/fontconfig.h>
+ #include <stdio.h>
+ 
+@@ -185,51 +186,30 @@
+                     ((qulonglong)1)<<theirLanguageForWritingSystem[i].ws;
+ }
+ 
+-CDisabledFonts::CDisabledFonts(const QString &path, bool sys)
++CDisabledFonts::CDisabledFonts(bool sys)
+               : itsTimeStamp(0),
+                 itsModified(false),
+                 itsMods(0)
+ {
+-    QString p;
++    QString path;
+ 
+     createWritingSystemMap();
+ 
+-    if(path.isEmpty())
++    if(Misc::root() || sys)
++        path=KFI_ROOT_CFG_DIR;
++    else
+     {
+-        if(Misc::root() || sys)
+-            p=KFI_ROOT_CFG_DIR;
+-        else
+-        {
+-            FcStrList *list=FcConfigGetFontDirs(FcInitLoadConfig());
+-            FcChar8   *dir;
+-            QString   home(QDir::homePath()),
+-                      defaultDir(home+"/.fonts");
+-
+-            while((dir=FcStrListNext(list)))
+-            {
+-                QString d((const char *)dir);
+-
+-                if(0==d.indexOf(home))
+-                    if(d==defaultDir)
+-                    {
+-                        p=defaultDir;
+-                        break;
+-                    }
+-                    else if(p.isEmpty())
+-                        p=d;
+-            }
++        path=KGlobal::dirs()->localxdgconfdir();
+ 
+-            if(p.isEmpty())
+-                p=defaultDir;
+-        }
++        if(!Misc::dExists(path))
++            Misc::createDir(path);
+     }
+-    else
+-        p=path;
+ 
+-    itsFileName=p+'/'+FILE_NAME".xml";
++    itsFileName=path+'/'+FILE_NAME".xml";
+ 
+     itsModifiable=Misc::fWritable(itsFileName) ||
+                   (!Misc::fExists(itsFileName) && Misc::dWritable(Misc::getDir(itsFileName)));
++
+     load();
+     if(itsModified)
+         save();
+--- a/kcontrol/kfontinst/lib/DisabledFonts.h
++++ b/kcontrol/kfontinst/lib/DisabledFonts.h
+@@ -96,7 +96,7 @@
+         void     add(const TFont &t) const;
+     };
+ 
+-    explicit CDisabledFonts(const QString &path=QString(), bool sys=false);
++    explicit CDisabledFonts(bool sys=false);
+     ~CDisabledFonts()          { save(); }
+ 
+     static const LangWritingSystemMap * languageForWritingSystemMap() { return theirLanguageForWritingSystem; }
+--- a/kcontrol/screensaver/advanceddialogimpl.ui
++++ b/kcontrol/screensaver/advanceddialogimpl.ui
+@@ -6,7 +6,7 @@
+     <x>0</x>
+     <y>0</y>
+     <width>403</width>
+-    <height>495</height>
++    <height>311</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" >
+@@ -16,18 +16,6 @@
+       <string>Screen Corner Actions</string>
+      </property>
+      <layout class="QGridLayout" >
+-      <property name="leftMargin" >
+-       <number>0</number>
+-      </property>
+-      <property name="topMargin" >
+-       <number>0</number>
+-      </property>
+-      <property name="rightMargin" >
+-       <number>0</number>
+-      </property>
+-      <property name="bottomMargin" >
+-       <number>0</number>
+-      </property>
+       <item rowspan="2" row="3" column="0" colspan="2" >
+        <widget class="QLabel" name="qlMonitorLabel" >
+         <property name="text" >
+@@ -299,15 +287,15 @@
+         <item>
+          <spacer>
+           <property name="orientation" >
+-           <enum>Qt::Vertical</enum>
++           <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeType" >
+-           <enum>QSizePolicy::Expanding</enum>
++           <enum>QSizePolicy::MinimumExpanding</enum>
+           </property>
+           <property name="sizeHint" >
+            <size>
+-            <width>21</width>
+-            <height>20</height>
++            <width>10</width>
++            <height>10</height>
+            </size>
+           </property>
+          </spacer>
+@@ -325,15 +313,15 @@
+         <item>
+          <spacer>
+           <property name="orientation" >
+-           <enum>Qt::Vertical</enum>
++           <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeType" >
+-           <enum>QSizePolicy::Expanding</enum>
++           <enum>QSizePolicy::MinimumExpanding</enum>
+           </property>
+           <property name="sizeHint" >
+            <size>
+-            <width>31</width>
+-            <height>20</height>
++            <width>10</width>
++            <height>10</height>
+            </size>
+           </property>
+          </spacer>
+@@ -351,7 +339,7 @@
+         <property name="sizeHint" >
+          <size>
+           <width>20</width>
+-          <height>20</height>
++          <height>10</height>
+          </size>
+         </property>
+        </spacer>
+@@ -367,7 +355,7 @@
+         <property name="sizeHint" >
+          <size>
+           <width>20</width>
+-          <height>20</height>
++          <height>10</height>
+          </size>
+         </property>
+        </spacer>
+@@ -414,7 +402,7 @@
+      <property name="sizeHint" >
+       <size>
+        <width>20</width>
+-       <height>40</height>
++       <height>5</height>
+       </size>
+      </property>
+     </spacer>
+--- a/kcontrol/screensaver/screensaver.desktop
++++ b/kcontrol/screensaver/screensaver.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell screensaver
++Exec=kcmshell4 screensaver
+ Icon=preferences-desktop-wallpaper
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/screensaver/scrnsave.cpp
++++ b/kcontrol/screensaver/scrnsave.cpp
+@@ -19,7 +19,6 @@
+ 
+ #include <kservicetypetrader.h>
+ #include <kstandarddirs.h>
+-#include <Qt3Support/Q3ButtonGroup>
+ #include <QCheckBox>
+ #include <Qt3Support/Q3Header>
+ #include <QLabel>
+@@ -121,23 +120,16 @@
+ 
+     QBoxLayout *topLayout = new QHBoxLayout(this);
+     topLayout->setSpacing(KDialog::spacingHint());
+-    topLayout->setMargin(0);
+ 
+     // left column
+     QVBoxLayout *leftColumnLayout = new QVBoxLayout( );
+     topLayout->addItem( leftColumnLayout );
+     leftColumnLayout->setSpacing( KDialog::spacingHint() );
+-    QBoxLayout *vLayout = new QVBoxLayout();
+-    leftColumnLayout->addItem( vLayout );
+-    vLayout->setSpacing( KDialog::spacingHint() );
+-
+-    mSaverGroup = new Q3GroupBox(i18n("Screen Saver"), this );
+-    mSaverGroup->setColumnLayout( 0, Qt::Horizontal );
+-    vLayout->addWidget(mSaverGroup);
+-    vLayout->setStretchFactor( mSaverGroup, 10 );
+-    QBoxLayout *groupLayout = new QVBoxLayout();
+-    mSaverGroup->layout()->addItem( groupLayout );
+-    groupLayout->setSpacing( KDialog::spacingHint() );
++
++    mSaverGroup = new QGroupBox(i18n("Screen Saver"), this );
++    QVBoxLayout *groupLayout = new QVBoxLayout( mSaverGroup );
++    leftColumnLayout->addWidget(mSaverGroup);
++    leftColumnLayout->setStretchFactor( mSaverGroup, 10 );
+ 
+     mSaverListView = new Q3ListView( mSaverGroup );
+     mSaverListView->setMinimumHeight( 120 );
+@@ -150,8 +142,7 @@
+     mSaverListView->setWhatsThis( i18n("Select the screen saver to use.") );
+ 
+     QBoxLayout* hlay = new QHBoxLayout();
+-    groupLayout->addItem(hlay);
+-    hlay->setSpacing(KDialog::spacingHint());
++    groupLayout->addLayout(hlay);
+     mSetupBt = new QPushButton( i18n("&Setup..."), mSaverGroup );
+     connect( mSetupBt, SIGNAL( clicked() ), SLOT( slotSetup() ) );
+     mSetupBt->setEnabled(false);
+@@ -164,12 +155,9 @@
+     hlay->addWidget( mTestBt );
+     mTestBt->setWhatsThis( i18n("Show a full screen preview of the screen saver.") );
+ 
+-    mSettingsGroup = new Q3GroupBox( i18n("Settings"), this );
+-    mSettingsGroup->setColumnLayout( 0, Qt::Vertical );
++    mSettingsGroup = new QGroupBox( i18n("Settings"), this );
++    groupLayout = new QVBoxLayout( mSettingsGroup );
+     leftColumnLayout->addWidget( mSettingsGroup );
+-    groupLayout = new QVBoxLayout();
+-    mSettingsGroup->layout()->addItem( groupLayout );
+-    groupLayout->setSpacing( KDialog::spacingHint() );
+ 
+     mEnabledCheckBox = new QCheckBox(i18n(
+         "Start a&utomatically"), mSettingsGroup);
+@@ -441,6 +429,7 @@
+     slotTimeoutChanged( 5 );
+     slotLockTimeoutChanged( 60 );
+     slotLock( false );
++    mEnabledCheckBox->setChecked(false);
+ 
+     updateValues();
+ 
+--- a/kcontrol/screensaver/scrnsave.h
++++ b/kcontrol/screensaver/scrnsave.h
+@@ -93,8 +93,8 @@
+     KService::List mSaverServices;
+     SaverList   mSaverList;
+     QTimer      *mLoadTimer;
+-    Q3GroupBox   *mSaverGroup;
+-    Q3GroupBox   *mSettingsGroup;
++    QGroupBox   *mSaverGroup;
++    QGroupBox   *mSettingsGroup;
+ 
+     int         mSelected;
+     int         mPrevSelected;
+--- a/kcontrol/smartcard/smartcard.desktop
++++ b/kcontrol/smartcard/smartcard.desktop
+@@ -3,7 +3,7 @@
+ Icon=preferences-desktop-user-smartcard
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+-Exec=kcmshell smartcard
++Exec=kcmshell4 smartcard
+ DocPath=kcontrol/smartcard.html
+ 
+ X-KDE-Library=kcm_smartcard
+@@ -153,7 +153,7 @@
+ Keywords[is]=Snjallkort,PKCS,SSL,reader,smart,card,snjall,kort
+ Keywords[it]=smartcard,PKCS,SSL,lettore
+ Keywords[ja]=スマートカード,PKCS,SSL,リーダー,スマート,カード
+-Keywords[km]=Smartcard,PKCS SSL,កម្មវិធី​​អាន,smart,កាត​
++Keywords[km]=Smartcard PKCS SSL កម្មវិធី​​អាន smart កាត​
+ Keywords[ko]=스마트카드,PKCS,SSL,리더,스마트,카드
+ Keywords[lt]=Smartcard,PKCS,SSL,reader,smart,card, gudri kortelė,skaitytuvas,gudri,kortelė
+ Keywords[mk]=Smartcard,PKCS,SSL,reader,smart,card,паметна картичка,читач,паметна,картичка
+--- a/kcontrol/krdb/ad/WPerfect.ad
++++ b/kcontrol/krdb/ad/WPerfect.ad
+@@ -41,8 +41,7 @@
+ XWp*XmDialogShell*background: BACKGROUND
+ XWp*XmDialogShell*XmScrolledWindow*XmDrawingArea.background: WINDOW_BACKGROUND
+ WPFMShell*XmDialogShell*background: WINDOW_BACKGROUND
+-WPFMShell*XmDialogShell*XmScrolledWindow*XmDrawingArea.background:
+-WINDOW_BACKGROUND
++WPFMShell*XmDialogShell*XmScrolledWindow*XmDrawingArea.background: WINDOW_BACKGROUND
+ XWp*XmDialogShell*XmDrawingArea.background: WINDOW_BACKGROUND
+ XWp*XmDialogShell*XmList*background: WINDOW_BACKGROUND
+ XWp*XmDialogShell*XmText*background: WINDOW_BACKGROUND
+--- a/kcontrol/accessibility/accessibility.desktop
++++ b/kcontrol/accessibility/accessibility.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell accessibility
++Exec=kcmshell4 accessibility
+ Icon=preferences-desktop-accessibility
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/accessibility/CMakeLists.txt
++++ b/kcontrol/accessibility/CMakeLists.txt
+@@ -13,7 +13,7 @@
+ kde4_add_plugin(kcm_accessibility ${kcm_accessibility_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_accessibility  ${KDE4_KDE3SUPPORT_LIBS}) 
++target_link_libraries(kcm_accessibility  ${KDE4_KIO_LIBS} ${QT_QT3SUPPORT_LIBRARY}) 
+ 
+ install(TARGETS kcm_accessibility  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kcontrol/taskbar/kcmtaskbar.desktop
++++ b/kcontrol/taskbar/kcmtaskbar.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kcmtaskbar
++Exec=kcmshell4 kcmtaskbar
+ Icon=preferences-desktop-panel-taskbar
+ Type=Service
+ ServiceTypes=KCModule
+@@ -167,7 +167,7 @@
+ Keywords[is]=spjald,kspjald,tækjaslá,forritaslá,gluggar,ræsingarslá
+ Keywords[it]=kicker,pannello,kpanel,barra delle applicazioni,barra di avvio,finestre
+ Keywords[ja]=kicker,パネル,kpanel,タスクバー,スタートバー,ラウンチバー,ウィンドウ
+-Keywords[km]=kicker,បន្ទះ,kpanel,របារ​ភារកិច្ច,របារ​ចាប់ផ្ដើម,របារ​ចាប់ផ្ដើម,វីនដូ
++Keywords[km]=kicker បន្ទះ kpanel របារ​ភារកិច្ច របារ​ចាប់ផ្ដើម របារ​ចាប់ផ្ដើម វីនដូ
+ Keywords[ko]=kicker,패널,kpanel,작업 표시줄,창
+ Keywords[lt]=kicker,pultas,kpanel,užduočių juosta,startavimo juosta,paleisties juosta
+ Keywords[lv]=kikers,panelis,kpanelis,uzdevumjosla,startjosla,palaišanasjosla,logi
+--- a/kcontrol/fonts/fonts.desktop
++++ b/kcontrol/fonts/fonts.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell fonts
++Exec=kcmshell4 fonts
+ Icon=preferences-desktop-font
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/energy/energy.desktop
++++ b/kcontrol/energy/energy.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell energy
++Exec=kcmshell4 energy
+ Icon=preferences-system-power-management
+ DocPath=kcontrol/energy/index.html
+ Type=Service
+@@ -94,7 +94,7 @@
+ Comment[el]=Ρυθμίσεις για την προβολή της διαχείρισης ενέργειας
+ Comment[eo]=Agordo por de la elektrouzado de via ekrano
+ Comment[es]=Preferencias para la pantalla de control de energía
+-Comment[et]=Ekraani voolutarbe juhtimise seaded
++Comment[et]=Monitori voolutarbe juhtimise seaded
+ Comment[eu]=Pantailaren energia kudeatzeko ezarpenak
+ Comment[fa]=تنظیمات برای نمایش مدیریت توان
+ Comment[fi]=Asetukset näytön virranhallinnalle
+@@ -155,7 +155,7 @@
+ Keywords[el]=ενέργεια,εξοικονόμηση,apm,acpi,dpms,χρονικό όριο,blanking,αναμονή,παύση,ισχύς
+ Keywords[eo]=energio,sekurigo,APM,ACPI,tempolimo,ekrano,kurteno,nigrigo, dormigo,malŝalto
+ Keywords[es]=energía,ahorro,APM,ACPI,tiempo límite,apagar monitor,modo de espera,suspender
+-Keywords[et]=energia,säästja,apm,acpi,dpms,taimaut,energiasääst,passiivne
++Keywords[et]=energia,säästja,apm,acpi,dpms,taimaut,aegumine,energiasääst,passiivne
+ Keywords[eu]=energia,babeslea,apm,acpi,dpms,denbora-muga,monitorea itzali, zain,suspenditu,indarra
+ Keywords[fa]=انرژی، محافظ، apm، acpi، dpms، اتمام وقت، فاصله‌گذاری، نیمه روشن، معلق، توان
+ Keywords[fi]=energia,säästö,apm,acpi,dpms,aikavalvonta,sammutus,valmiustila,teho
+--- a/kcontrol/infocenter/usbview/kcmusb.desktop
++++ b/kcontrol/infocenter/usbview/kcmusb.desktop
+@@ -4,7 +4,7 @@
+ Type=Service
+ ServiceTypes=KCModule
+ DocPath=kinfocenter/usb/index.html
+-Exec=kcmshell kcmusb
++Exec=kcmshell4 kcmusb
+ 
+ X-KDE-Library=kcm_usb
+ X-KDE-ParentApp=kinfocenter
+@@ -155,7 +155,7 @@
+ Keywords[el]=USB,συσκευές,προβολέας,έλεγχος
+ Keywords[eo]=USB,aparatoj,rigardilo,stirado
+ Keywords[es]=USB,dispositivos,visor,control
+-Keywords[et]=USB,seadmed,vaataja,juhtimine
++Keywords[et]=USB,seadmed,näitaja,juhtimine
+ Keywords[eu]=USB,gailuak,ikustailua,kontrola
+ Keywords[fa]=USB، دستگاهها، مشاهده‌گر، کنترل
+ Keywords[fi]=USB,laitteet,näyttää,ohjaus
+@@ -169,7 +169,7 @@
+ Keywords[is]=USB,tæki,skoðari,stilling
+ Keywords[it]=USB,dispositivi,controllo
+ Keywords[ja]=USB,デバイス,ビューア,コントロール
+-Keywords[km]=យូអេសប៊ី,ឧបករណ៍,កម្មវិធី​មើល,វត្ថុ​បញ្ជា
++Keywords[km]=យូអេសប៊ី ឧបករណ៍ កម្មវិធី​មើល វត្ថុ​បញ្ជា
+ Keywords[ko]=USB,장치,USB 장치,제어
+ Keywords[lt]=USB,devices,viewer,control, įrengimai, žiūriklis, kontrolė
+ Keywords[lv]=USB,iekārtas,skatītājs,vadība
+--- a/kcontrol/infocenter/info/processor.desktop
++++ b/kcontrol/infocenter/info/processor.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell processor
++Exec=kcmshell4 processor
+ Icon=kcmprocessor
+ Type=Service
+ ServiceTypes=KCModule
+@@ -171,7 +171,7 @@
+ Keywords[it]=processore,CPU,FPU,MHz,informazioni sul sistema
+ Keywords[ja]=プロセッサ,CPU,FPU,MHz,システムの情報
+ Keywords[ka]=პროცესორი,CPU,FPU,MHz,ინფორმაცია სისტემის შესახებ
+-Keywords[km]=ប្រព័ន្ធ​ដំណើរការ,ស៊ីភីយូ,FPU,MHz,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=ប្រព័ន្ធ​ដំណើរការ ស៊ីភីយូ FPU MHz ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=Processor,프로세서,CPU,FPU,MHz,시스템 정보
+ Keywords[lt]=Procesorius,CPU,FPU,MHz,Sistemos Informacija
+ Keywords[lv]=Procesors,CPU,FPU,MHz,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/devices.desktop
++++ b/kcontrol/infocenter/info/devices.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell devices
++Exec=kcmshell4 devices
+ Icon=kcmdevices
+ Type=Service
+ ServiceTypes=KCModule
+@@ -173,7 +173,7 @@
+ Keywords[is]=dev,tæki,jaðartæki,upplýsingar,kerfi
+ Keywords[it]=dev,dispositivi,periferiche,informazioni sul sistema,informazioni
+ Keywords[ja]=dev,デバイスシステム,システムの情報,情報
+-Keywords[km]=ឧបករណ៍,ព័ត៌មាន​ប្រព័ន្ធ,ព័ត៌មាន
++Keywords[km]=dev ឧបករណ៍ ព័ត៌មាន​ប្រព័ន្ធ ព័ត៌មាន
+ Keywords[ko]=장치,시스템 정보,정보
+ Keywords[lt]=dev,Įrenginiai,Sistemos Informacija,Informacija
+ Keywords[lv]=iek,Iekārtas,Sistēmas Informācija,Informācija
+--- a/kcontrol/infocenter/info/sound.desktop
++++ b/kcontrol/infocenter/info/sound.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell sound
++Exec=kcmshell4 sound
+ Icon=kcmsound
+ Type=Service
+ ServiceTypes=KCModule
+@@ -173,7 +173,7 @@
+ Keywords[it]=suono,audio,scheda sonora,MIDI,OSS,informazioni sul sistema
+ Keywords[ja]=サウンド,オーディオ,サウンドカード,MIDI,OSS,システムの情報
+ Keywords[ka]=ხმა,აუდიო,აუდიოდაბა,MIDI,OSS,ინფორმაცია სისტემის შესახებ
+-Keywords[km]=សំឡេង,អូឌីយ៉ូ,កាត​សំឡេង,មីឌី,OSS,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=សំឡេង អូឌីយ៉ូ កាត​សំឡេង មីឌី OSS ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=사운드,소리,오디오,사운드 카드,MIDI,OSS,시스템 정보
+ Keywords[lt]=Garsas,Audio,Garso korta,Midi,OSS,Sistemos informacija
+ Keywords[lv]=Skaņa,Audio,Skaņaskarte,MIDI,OSS,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/partitions.desktop
++++ b/kcontrol/infocenter/info/partitions.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell partitions
++Exec=kcmshell4 partitions
+ Icon=kcmpartitions
+ Type=Service
+ ServiceTypes=KCModule
+@@ -172,7 +172,7 @@
+ Keywords[is]=Sneiðar,Disksneiðar,Harðir diskar,Harður diskur,kerfi,upplýsingar
+ Keywords[it]=partizioni,disco rigido,hard disk,HD,informazioni sul sistema
+ Keywords[ja]=パーティション,ハードドライブ,HD,システムの情報
+-Keywords[km]=ភាគថាស,ដ្រាយរឹង,HD,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=ភាគថាស ដ្រាយរឹង HD ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=파티션,하드 디스크,하드디스크,시스템 정보Partitions,Harddrive,HD,System Information,파티션,분할 영역,하드 디스크,하드 드라이브,시스템 정보,하드,나눠진 공간
+ Keywords[lt]=Skirsniai,Kietasis diskas,HD,Sistemos Informacija
+ Keywords[lv]=Partīcijas,CietaisDisks,HD,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/xserver.desktop
++++ b/kcontrol/infocenter/info/xserver.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell xserver
++Exec=kcmshell4 xserver
+ Icon=kcmx
+ Type=Service
+ ServiceTypes=KCModule
+@@ -164,7 +164,7 @@
+ Keywords[it]=X,Server X,XServer,XFree86,display,schermo,informazioni sul sistema,SchedaVideo
+ Keywords[ja]=X,X-サーバ,Xサーバ,XFree86,ディスプレイ,システム情報
+ Keywords[ka]=X,X-სერვერი,Xსერვერი,XFree86,დსიპლეი, ვიდეოდაფა,ინფორმაცია სისტების შესახებ
+-Keywords[km]=X,ម៉ាស៊ីន​បម្រើ X,ម៉ាស៊ីន​បម្រើ X,XFree86,ការ​បង្ហាញ,កាត​វីដេអូ,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=X ម៉ាស៊ីន​បម្រើ X ម៉ាស៊ីន​បម្រើ X XFree86 ការ​បង្ហាញ កាត​វីដេអូ ព័័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=X,X 서버,XFree86,디스플레이,비디오 카드,시스템 정보
+ Keywords[lt]=X,X-Serveris,XServer,XFree86,Displėjus,Video plokštė,Sistemos informacija
+ Keywords[lv]=X,X-Serveris,XServeris,XFree86,Ekrāns,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/ioports.desktop
++++ b/kcontrol/infocenter/info/ioports.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell ioports
++Exec=kcmshell4 ioports
+ Icon=kcmmemory
+ Type=Service
+ ServiceTypes=KCModule
+@@ -173,7 +173,7 @@
+ Keywords[is]=Inntak,úttak,I/O,Port,upplýsingar,kerfi
+ Keywords[it]=IO,I/O,porte di IO,porte di I/O,porte,intervallo di IO,intervallo di I/O,informazioni sul sistema
+ Keywords[ja]=IO,I/O,IO-ポート,I/O-ポート,ポート,IO-レンジ,I/O-レンジ,システムの情報
+-Keywords[km]=IO,I/O,ច្រក IO,ច្រក I/O,ច្រក,ជួរ IO,ជួរ I/O,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=IO I/O ច្រក IO ច្រក I/O ច្រក ជួរ IO ជួរ I/O ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=IO,I/O,IO 포트,I/O 포트,IO 범위,I/O 범위,시스템 정보
+ Keywords[lt]=IO,I/O,IO-Ports,IO-portai,I/O-Ports,I/O-prievadai,Ports,prievadai,IO-Range,IO zona,I/O-Range,I/O zona,System Information,sisteminė informacija
+ Keywords[lv]=IO,I/O,IO-Porti,I/O-Porti,Porti,IO-Diapazons,I/O-Diapazons,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/dma.desktop
++++ b/kcontrol/infocenter/info/dma.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell dma
++Exec=kcmshell4 dma
+ Icon=kcmmemory
+ Type=Service
+ ServiceTypes=KCModule
+@@ -94,7 +94,7 @@
+ Comment[el]=Πληροφορίες για τα DMA
+ Comment[eo]=DMA-informo
+ Comment[es]=Información sobre DMA
+-Comment[et]=DMA kanalite info
++Comment[et]=DMA-kanalite info
+ Comment[eu]=DMAri buruzko informazioa
+ Comment[fa]=اطلاعات دسترسی مستقیم به حافظه
+ Comment[fi]=DMA-tietoja
+@@ -160,7 +160,7 @@
+ Keywords[el]=dma,Κανάλια DMA,Πληροφορίες συστήματος
+ Keywords[eo]=DMA,kanaloj,sistemo,operaciumo,informo
+ Keywords[es]=DMA,Canales DMA,Información del sistema
+-Keywords[et]=dma,DMA kanalid,süsteemi informatsioon
++Keywords[et]=dma,DMA-kanalid,süsteemi informatsioon
+ Keywords[eu]=dma,DMA-Kanalak,Sistemaren informazioa
+ Keywords[fa]=dma ،مجراهای دستیابی مستقیم به حافظه، اطلاعات سیستم
+ Keywords[fi]=dma,DMA-kanavat,Järjestelmätiedot
+@@ -175,7 +175,7 @@
+ Keywords[it]=DMA,canali DMA,informazioni sul sistema
+ Keywords[ja]=dma,DMA-チャンネル,システムの情報
+ Keywords[ka]=dma,DMA-არხები,ინფორმაცია სისტემის შესახებ
+-Keywords[km]=dma, ឆានែល DMA,​ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=dma ឆានែល DMA ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=dma,DMA-채널,채널,시스템 정보
+ Keywords[lt]=dma,DMA-Kanalai,Sistemos Informacija
+ Keywords[lv]=dma,DMA-Kanāli,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/memory.desktop
++++ b/kcontrol/infocenter/info/memory.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell memory
++Exec=kcmshell4 memory
+ Icon=kcmmemory
+ Type=Service
+ ServiceTypes=KCModule
+@@ -173,7 +173,7 @@
+ Keywords[it]=memoria,RAM,memoria virtuale,memoria fisica,memoria condivisa,swap,informazioni sul sistema
+ Keywords[ja]=メモリ,RAM,仮想メモリ,物理メモリ,共有メモリ, スワップ, システム情報
+ Keywords[ka]=მეხსიერება,RAM,ვირტუალური მეხსეირება,ფიზიკური მეხსიერება,საერთო მეხსიერება,მიმოცვლის ფაილია,ინფორმაცია სისტემის შესახებ
+-Keywords[km]=សតិ,RAM,សតិ​និម្មិត,សតិពិត,សតិ​ដែល​បាន​ចែករំលែក,ស្វប,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=សតិ RAM សតិ​និម្មិត សតិពិត សតិ​ដែល​បាន​ចែករំលែក ស្វប ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=메모리,RAM,가상 메모리,물리 메모리,공유 메모리,스왑,시스템 정보
+ Keywords[lt]=Memory,atmintis,RAM,atmintinė,Virtual memory,virtuali atmintis,Physical memory,fizinė atmintis,Shared memory,bendro naudojimo atmintis,Swap,System Information,sisteminė informacija
+ Keywords[lv]=Atmiņa,RAM,Virtuālā atmiņa,Fiziskā atmiņa,Koplietošanas atmiņa,Svaps,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/pci.desktop
++++ b/kcontrol/infocenter/info/pci.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell pci
++Exec=kcmshell4 pci
+ Icon=kcmpci
+ Type=Service
+ ServiceTypes=KCModule
+@@ -116,7 +116,7 @@
+ Keywords[is]=PCI-tæki,PCI-braut,kerfi,upplýsingar
+ Keywords[it]=PCI,dispositivi PCI,bus PCI,informazioni sul sistema
+ Keywords[ja]=PCI,PCI-デバイス,PCI-バス,システムの情報
+-Keywords[km]=PCI,ឧបករណ៍ PCI,ខ្សែ​បញ្ជូន PCI,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=PCI ឧបករណ៍ PCI ខ្សែ​បញ្ជូន PCI ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=PCI,PCI 장치,PCI 버스,시스템 정보
+ Keywords[lt]=PCI,PCI-įrenginiai,PCI-Bus,Sistemos Informacija
+ Keywords[lv]=PCI,PCI-Iekārtas,PCI-Šina,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/interrupts.desktop
++++ b/kcontrol/infocenter/info/interrupts.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell interrupts
++Exec=kcmshell4 interrupts
+ Icon=kcmmemory
+ Type=Service
+ ServiceTypes=KCModule
+@@ -153,7 +153,7 @@
+ Keywords[el]=Διακοπές,IRQ,Πληροφορίες συστήματος
+ Keywords[eo]=Interrompoj,IRQ,sistemo,informo,operaciumo
+ Keywords[es]=Interrupciones,IRQ,Información del sistema
+-Keywords[et]=Katkestused,IRQ,Süsteemi informatsioon
++Keywords[et]=Katkestused,IRQ,Süsteemi info
+ Keywords[eu]=Etenaldiak,IRQ,Sistemaren informazioa
+ Keywords[fa]=وقفه‌ها، IRQ، اطلاعات سیستم
+ Keywords[fi]=Keskeytykset,IRQ,Järjestelmätiedot
+@@ -168,7 +168,7 @@
+ Keywords[it]=interrupt,IRQ,informazioni sul sistema
+ Keywords[ja]=割り込み,IRQ,システムの情報
+ Keywords[ka]=წყვიტავს,IRQ,ინფორმაცია სისტემის შესახებ
+-Keywords[km]=ផ្អាក,IRQ,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=ផ្អាក IRQ ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=인터럽트,IRQ,시스템 정보
+ Keywords[lt]=Pertrauktys,IRQ,Sistemos Informacija
+ Keywords[lv]=Pārtraukumi,IRQ,Sistēmas Informācija
+--- a/kcontrol/infocenter/info/opengl.desktop
++++ b/kcontrol/infocenter/info/opengl.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell opengl
++Exec=kcmshell4 opengl
+ Icon=kcmopengl
+ Type=Service
+ ServiceTypes=KCModule
+@@ -104,7 +104,7 @@
+ Keywords[is]=OpenGL,DRI,GLX,3D,VideoCard,Hardware Acceleration,vélbúnaðarhröðun,Graphics,grafík,X,X11,Xserver,Xþjónn, X-Server,X-þjónn,XFree86,Display,skjár
+ Keywords[it]=OpenGL,DRI,GLX,3D,SchedaVideo,Video,Accelerazione Hardware,Grafica,X,X11,Xserver,X-Server,XFree86,Display,Server X
+ Keywords[ka]=OpenGL,DRI,GLX,3D,ვიდეოდაფა,Hardware Acceleration,Graphics,X,X11,Xserver,X-Server,XFree86,Display
+-Keywords[km]=OpenGL,DRI,GLX,3D,កាត​វីដេអូ,ការ​បង្កើន​ល្បឿន​ផ្នែក​រឹង,ក្រាហ្វិក,X,X11,Xserver,ម៉ាស៊ីន​បម្រើ X,XFree86,ការ​បង្ហាញ
++Keywords[km]=OpenGL DRI GLX ត្រីមាត្រ កាាត​វីដេអ ,ការ​បង្កើន​ល្បឿន​ផ្នែក​រឹ ,ក្រាហ្វិ , ,X1 ,Xserve ,ម៉ាស៊ីន​បម្រើ  XFree8 ,ការ​បង្ហាញ
+ Keywords[ko]=OpenGL,DRI,GLX,3D,비디오 카드,하드웨어 가속,그래픽,X11,X 서버,디스플레이
+ Keywords[lt]=OpenGL,DRI,GLX,3D,VideoCard,Hardware Acceleration,Graphics,X,X11,Xserver,X-Server,XFree86,Display,Video plokštė,aparatūros greitinimas,grafika
+ Keywords[lv]=OpenGL,DRI,GLX,3D,VideoKarte,Dzelžu paātrināšana,Grafika,X,X11,Xserveris,X-Serveris,XFree86,Ekrāns
+--- a/kcontrol/infocenter/info/scsi.desktop
++++ b/kcontrol/infocenter/info/scsi.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell scsi
++Exec=kcmshell4 scsi
+ Icon=kcmscsi
+ Type=Service
+ ServiceTypes=KCModule
+@@ -115,7 +115,7 @@
+ Keywords[is]=SCSI-braut,kerfi,upplýsingar
+ Keywords[it]=SCSI,bus SCSI,informazioni sul sistema
+ Keywords[ja]=SCSI,SCSI-バス,システムの情報
+-Keywords[km]=SCSI,ខ្សែ​បញ្ជូន SCSI,ព័ត៌មាន​ប្រព័ន្ធ
++Keywords[km]=SCSI​ ខ្សែ​បញ្ជូន SCSI ព័ត៌មាន​ប្រព័ន្ធ
+ Keywords[ko]=SCSI,SCSI 버스,시스템 정보
+ Keywords[lt]=SCSI,SCSI-Bus,Sistemos Informacija
+ Keywords[lv]=SCSI,SCSI-Šina,Sistēmas Informācija
+--- a/kcontrol/infocenter/view1394/CMakeLists.txt
++++ b/kcontrol/infocenter/view1394/CMakeLists.txt
+@@ -11,7 +11,7 @@
+ kde4_add_plugin(kcm_view1394 ${kcm_view1394_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_view1394  ${KDE4_KDE3SUPPORT_LIBS} ${RAW1394_LIBRARIES} )
++target_link_libraries(kcm_view1394 ${QT_QT3SUPPORT_LIBRARY} ${KDE4_KDEUI_LIBS} ${RAW1394_LIBRARIES} )
+ 
+ install(TARGETS kcm_view1394  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kcontrol/infocenter/view1394/kcmview1394.desktop
++++ b/kcontrol/infocenter/view1394/kcmview1394.desktop
+@@ -4,7 +4,7 @@
+ Type=Service
+ ServiceTypes=KCModule
+ DocPath=kinfocenter/view1394/index.html
+-Exec=kcmshell kcmview1394
++Exec=kcmshell4 kcmview1394
+ 
+ X-KDE-Library=kcm_view1394
+ X-KDE-ParentApp=kinfocenter
+@@ -152,7 +152,7 @@
+ Keywords[el]=1394,Firewire,συσκευές,προβολέας,έλεγχος
+ Keywords[eo]=1394,aparatoj,rigardilo,stirado
+ Keywords[es]=1394,Firewire,dispositivos,visor,control
+-Keywords[et]=1394,Firewire,seadmed,vaataja,juhtimine
++Keywords[et]=1394,Firewire,seadmed,näitaja,juhtimine
+ Keywords[eu]=1394,Firewire,gailuak,ikustailua,kontrola
+ Keywords[fa]=۱۳۹۴، Firewire، دستگاهها، مشاهده‌گر، کنترل
+ Keywords[fi]=1394,Firewire,laitteet,katselija,hallinta
+@@ -166,7 +166,7 @@
+ Keywords[is]=1394,Firewire,tæki,skoðari,stilling
+ Keywords[it]=1394,dispositivi,controllo,visualizza,firewire
+ Keywords[ja]=1394,Firewire,デバイス,ビューア,コントロール
+-Keywords[km]=1394,ខ្សែ​ភ្លើង,ឧបករណ៍,កម្មវិធី​មើល,វត្ថុ​បញ្ជា
++Keywords[km]=1394 ខ្សែ​ភ្លើង ឧបករណ៍ កម្មវិធី​មើល វត្ថុ​បញ្ជា
+ Keywords[ko]=1394,Firewire,장치,제어
+ Keywords[lt]=1394,Firewire,devices,viewer,control,žiūryklė,kontrolė,įrenginiai
+ Keywords[lv]=1394,Fireware,iekārtas,skatītājs,vadība
+--- a/kcontrol/infocenter/nics/nic.h
++++ b/kcontrol/infocenter/nics/nic.h
+@@ -24,7 +24,7 @@
+ #include <kcmodule.h>
+ 
+ class QPushButton;
+-class Q3ListView;
++class QTreeWidget;
+ 
+ class KCMNic:public KCModule
+ {
+@@ -36,7 +36,7 @@
+       void update();
+ 
+    protected:
+-      Q3ListView *m_list;
++      QTreeWidget *m_list;
+       QPushButton *m_updateButton;
+ };
+ 
+--- a/kcontrol/infocenter/nics/nic.desktop
++++ b/kcontrol/infocenter/nics/nic.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell nic
++Exec=kcmshell4 nic
+ Type=Service
+ ServiceTypes=KCModule
+ DocPath=kinfocenter/nics/index.html
+--- a/kcontrol/infocenter/nics/nic.cpp
++++ b/kcontrol/infocenter/nics/nic.cpp
+@@ -36,13 +36,13 @@
+ #include <kglobal.h>
+ 
+ #include <QLayout>
+-#include <Qt3Support/Q3CheckListItem>
+ #include <QPushButton>
+ #include <QTabWidget>
+ #include <QTimer>
+ #include <QVBoxLayout>
+ #include <QHBoxLayout>
+ #include <Q3PtrList>
++#include <QTreeWidget>
+ 
+ #include "nic.h"
+ 
+@@ -97,15 +97,12 @@
+    QVBoxLayout *box=new QVBoxLayout(this);
+    box->setMargin(0);
+    box->setSpacing(KDialog::spacingHint());
+-   m_list=new Q3ListView(this);
++   m_list=new QTreeWidget(this);
++   m_list->setRootIsDecorated(false);
+    box->addWidget(m_list);
+-   m_list->addColumn(i18n("Name"));
+-   m_list->addColumn(i18n("IP Address"));
+-   m_list->addColumn(i18n("Network Mask"));
+-   m_list->addColumn(i18n("Type"));
+-   m_list->addColumn(i18n("State"));
+-   m_list->addColumn(i18n("HWAddr"));
+-   m_list->setAllColumnsShowFocus(true);
++   QStringList columns;
++   columns<<i18n("Name")<<i18n("IP Address")<<i18n("Network Mask")<<i18n("Type")<<i18n("State")<<i18n("HWAddr");
++   m_list->setHeaderLabels(columns);
+    QHBoxLayout *hbox=new QHBoxLayout();
+    box->addItem(hbox);
+    m_updateButton=new QPushButton(i18n("&Update"),this);
+@@ -132,8 +129,11 @@
+    m_list->clear();
+    NICList *nics=findNICs();
+    nics->setAutoDelete(true);
+-   for (MyNIC* tmp=nics->first(); tmp!=0; tmp=nics->next())
+-      new Q3ListViewItem(m_list,tmp->name, tmp->addr, tmp->netmask, tmp->type, tmp->state, tmp->HWaddr);
++   for (MyNIC* tmp=nics->first(); tmp!=0; tmp=nics->next()) {
++      QStringList lst;
++      lst << tmp->name<<tmp->addr<<tmp->netmask<<tmp->type<<tmp->state<<tmp->HWaddr;
++      new QTreeWidgetItem(m_list,lst);
++   }
+    delete nics;
+ }
+ 
+--- a/kcontrol/infocenter/nics/CMakeLists.txt
++++ b/kcontrol/infocenter/nics/CMakeLists.txt
+@@ -18,7 +18,7 @@
+ kde4_add_plugin(kcm_nic ${kcm_nic_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_nic  ${KDE4_KIO_LIBS} ${QT_QT3SUPPORT_LIBRARY} ${QT_QTGUI_LIBRARY})
++target_link_libraries(kcm_nic  ${KDE4_KIO_LIBS} ${QT_QT3SUPPORT_LIBRARY} )
+ 
+ install(TARGETS kcm_nic  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kcontrol/hardware/joystick/joystick.desktop
++++ b/kcontrol/hardware/joystick/joystick.desktop
+@@ -60,7 +60,7 @@
+ Comment[x-test]=xxjoystick - a kcontrol module to test joysticksxx
+ Comment[zh_CN]=joystick - 测试游戏杆的 kcontrol 模块
+ Comment[zh_TW]=搖桿 - 用來測試搖桿的 kcontrol 模組
+-Exec=kcmshell joystick
++Exec=kcmshell4 joystick
+ Keywords=joystick,gamepad
+ Keywords[ar]=وسادة اللعبة,عصا الألعاب
+ Keywords[be]=Джойстык,joystick,gamepad
+--- a/kcontrol/hardware/display/display.desktop
++++ b/kcontrol/hardware/display/display.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell display
++Exec=kcmshell4 display
+ Icon=preferences-desktop-display
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/input/mouse.desktop
++++ b/kcontrol/input/mouse.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell mouse
++Exec=kcmshell4 mouse
+ Icon=preferences-desktop-mouse
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+@@ -168,7 +168,7 @@
+ Keywords[is]=Næmni músar,bendill,inntakstæki,hröðun,örvhentur,rétthentur,smella,tákn,bendill,tvísmella
+ Keywords[it]=mouse,accelerazione del mouse,soglia del mouse,tasti del mouse,selezione,forma del cursore,dispositivi di input,mappatura dei tasti,clic,icone,puntatori,trascinamento,doppio clic,mouse per mancini,mancini
+ Keywords[ja]=マウス,マウスの加速,マウスのしきい,マウスボタン,選択,カーソルの形,入力デバイス,入力デバイス,ボタンの割り当て,クリック,アイコン,フィードバック,ポインタ,ドラッグ,ダブルクリック,割り当て,右利き,左利き
+-Keywords[km]=កណ្ដុរ,ការ​បង្កើន​ល្បឿន,កម្រិត​ពន្លឺ​កណ្ដុរ,ប៊ូតុង​កណ្ដុរ,ការជ្រើស,រូបរាង​ទស្សន៍​ទ្រនិច,ឧបករណ៍​បញ្ចូល,ការ​ផ្គូផ្គង​ប៊ូតុង,ចុច,រូបតំណាង,មតិ​អ្នក​ប្រើ,ទ្រនិច​,អូស,ចុច​ទ្វេដង,ការ​ផ្គូផ្គង,ខាង​ស្ដាំ,ខាង​ឆ្វេង
++Keywords[km]=កណ្ដុរ ការ​បង្កើន​ល្បឿន កម្រិត​ពន្លឺ​កណ្ដុរ ប៊ូតុង​កណ្ដុរ ការជ្រើស រូបរាង​ទស្សន៍​ទ្រនិច ឧបករណ៍​បញ្ចូល ការ​ផ្គូផ្គង​ប៊ូតុង ចុច រូបតំណាង មតិ​អ្នក​ប្រើ ទ្រនិច អូស ចុច​ទ្វេដង ការ​ផ្គូផ្គង ខាង​ស្ដាំ ខាង​ឆ្វេង
+ Keywords[ko]=마우스,마우스 가속,마우스 단추,선택,커서,입력 장치,단추 할당,아이콘,피드백,포인터,드래그,더블클릭
+ Keywords[lt]=Mouse,pelė,Mouse acceleration,pelės pagreitinimas,Mouse threshold,Mouse buttons,pelės mygtukai,Selection,pažymėjimas,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,DoubleClick,right handed,left handed,kairiarankė
+ Keywords[lv]=Pele,Peles paātrinājums,Peles slieksnis,Peles taustiņi,Izvēle,Kursora Forma,Ievades Iekārtas,Pogu Sasaiste,Klikšķis,ikonas,atpakaļsaite,Rādītāji,Vilkt,Dubultklikšķis,sasaiste,labās rokas,kreisās rokas
+--- a/kcontrol/input/CMakeLists.txt
++++ b/kcontrol/input/CMakeLists.txt
+@@ -41,7 +41,8 @@
+ 
+ kde4_add_executable(kapplymousetheme ${kapplymousetheme_SRCS})
+ 
+-target_link_libraries(kapplymousetheme  ${KDE4_KDE3SUPPORT_LIBS} ${X11_Xrender_LIB})
++target_link_libraries(kapplymousetheme  ${QT_QT3SUPPORT_LIBRARY}
++${KDE4_KDEUI_LIBS} ${X11_Xrender_LIB})
+ if (X11_Xcursor_FOUND)
+    target_link_libraries(kapplymousetheme ${X11_Xcursor_LIB})
+ endif (X11_Xcursor_FOUND)
+--- a/kcontrol/kxkb/rules.h
++++ b/kcontrol/kxkb/rules.h
+@@ -41,15 +41,12 @@
+ 
+   bool isSingleGroup(const QString& layout);
+ 
+-//  static bool areLayoutsClean() { return m_layoutsClean; }
+-
+ private:
+ 
+   QHash<QString, QString> m_models;
+   QHash<QString, QString> m_layouts;
+   QHash<QString, XkbOptionGroup> m_optionGroups;
+   QHash<QString, XkbOption> m_options;
+-  QMap<QString, unsigned int> m_initialGroups;
+   QHash<QString, QStringList*> m_varLists;
+ 
+   QString X11_DIR;	// pseudo-constant
+--- a/kcontrol/kxkb/xklavier_adaptor.cpp
++++ b/kcontrol/kxkb/xklavier_adaptor.cpp
+@@ -22,8 +22,6 @@
+ #include <klocale.h>
+ #include <kdebug.h>
+ 
+-#include <QtGui/QWidget>
+-
+ #include <libxklavier/xklavier.h>
+ 
+ #include "rules.h"
+@@ -202,6 +200,7 @@
+ {
+     QList<LayoutUnit> list;
+ 
++    kDebug() << "retrieving active layout from server...";
+     XklConfigRec configRec;
+     xkl_config_rec_get_from_server(&configRec, priv->engine);
+ 
+--- a/kcontrol/kxkb/kxkb_applet.cpp
++++ b/kcontrol/kxkb/kxkb_applet.cpp
+@@ -17,6 +17,7 @@
+  */
+ 
+ #include <QWidget>
++#include <QSizeF>
+ 
+ #include <kglobal.h>
+ #include <klocale.h>
+@@ -28,25 +29,16 @@
+ #include "kxkb_applet.moc"
+ 
+ 
+-extern "C"
++KxkbApplet::KxkbApplet(QObject *parent, const QVariantList &args)
++    : Plasma::Applet(parent, args)
+ {
+-    KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
+-    {
+-        KGlobal::locale()->insertCatalog("kxkb");
+-        int actions = Plasma::Preferences | Plasma::About | Plasma::Help;
+-        return new KxkbApplet(configFile, Plasma::Normal, actions, parent);
+-    }
+-}
+-
+-
+-KxkbApplet::KxkbApplet(const QString& configFile, Plasma::Type type,
+-                 int actions, QWidget *parent, Qt::WFlags f)
+-    : KPanelApplet(configFile, type, actions, parent, f)
+-{
+-    move( 0, 0 );
+-    kxkbWidget = new KxkbLabel( this );
+-	KxkbCore* kxkbCore = new KxkbCore(kxkbWidget);
+-	kxkbCore->newInstance();
++//    move( 0, 0 );
++    m_kxkbCore = new KxkbCore(NULL, KxkbCore::KXKB_COMPONENT, KxkbWidget::MENU_FULL, KxkbWidget::WIDGET_LABEL);
++    m_kxkbCore->newInstance();
++
++    setDrawStandardBackground(true);
++//    connect(m_systemTrayWidget, SIGNAL(sizeChanged()), SLOT(updateLayout()));
++    //m_kxkbWidget->show();
+     //setCustomMenu(widget->history()->popup());
+     //centerWidget();
+     //kxkbWidget->show();
+@@ -54,14 +46,21 @@
+ 
+ KxkbApplet::~KxkbApplet()
+ {
++    if (failedToLaunch()) {
++        // Do some cleanup here
++    } else {
++        // Save settings
++    }
+ }
+ 
+-int KxkbApplet::widthForHeight(int height) const
++QSizeF KxkbApplet::contentSizeHint() const
+ {
+-	return 32;//kxkbWidget->width();
++//    return QSizeF(m_kxkbCore->size());
++    return QSizeF(32,32);
+ }
+ 
+-int KxkbApplet::heightForWidth(int width) const
++void KxkbApplet::paintInterface(QPainter *painter,
++                    const QStyleOptionGraphicsItem *option,
++                                    const QRect& contentsRect)
+ {
+-	return 32;//kxkbWidget->height();
+ }
+--- a/kcontrol/kxkb/kxkbapp.h
++++ b/kcontrol/kxkb/kxkbapp.h
+@@ -27,7 +27,6 @@
+ #define __K_XKBAPP_H__
+ 
+ 
+-
+ #include <kuniqueapplication.h>
+ 
+ #include "kxkbcore.h"
+@@ -42,17 +41,18 @@
+     Q_OBJECT
+ 
+ public:
+-	explicit KXKBApp(bool allowStyles=true, bool GUIenabled=true);
+-	~KXKBApp();
++    explicit KXKBApp(bool allowStyles=true, bool GUIenabled=true);
++    ~KXKBApp();
+ 
+-	virtual int newInstance();
++    virtual int newInstance();
+ 
+-	bool setLayout(const LayoutUnit& layoutUnit, int group=-1);
++    bool isError() { return m_kxkbCore->getStatus() != 0; }
++    bool setLayout(const LayoutUnit& layoutUnit, int group=-1);
+ // External API:
+ public slots:
+- 	bool setLayout(const QString& layoutPair) { return m_kxkbCore->setLayout(layoutPair); }
+-	QString getCurrentLayout() { return m_kxkbCore->getCurrentLayout(); }
+-	QStringList getLayoutsList() { return m_kxkbCore->getLayoutsList(); }
++    bool setLayout(const QString& layoutPair) { return m_kxkbCore->setLayout(layoutPair); }
++    QString getCurrentLayout() { return m_kxkbCore->getCurrentLayout(); }
++    QStringList getLayoutsList() { return m_kxkbCore->getLayoutsList(); }
+ 
+ protected slots:
+     void slotSettingsChanged(int category);
+@@ -63,7 +63,7 @@
+     void layoutApply();
+ 
+ private:
+-	KxkbCore* m_kxkbCore;
++    KxkbCore* m_kxkbCore;
+ };
+ 
+ #endif
+--- a/kcontrol/kxkb/kcmmisc/kcmmiscwidget.ui
++++ b/kcontrol/kxkb/kcmmisc/kcmmiscwidget.ui
+@@ -135,16 +135,13 @@
+     </widget>
+    </item>
+    <item>
+-    <widget class="Q3ButtonGroup" name="numlockGroup" >
++    <widget class="KButtonGroup" name="numlockGroup" >
+      <property name="whatsThis" >
+       <string>If supported, this option allows you to setup the state of NumLock after KDE startup.&lt;p>You can configure NumLock to be turned on or off, or configure KDE not to set NumLock state.</string>
+      </property>
+      <property name="title" >
+       <string>NumLock on KDE Startup</string>
+      </property>
+-     <property name="orientation" >
+-      <enum>Qt::Vertical</enum>
+-     </property>
+      <layout class="QGridLayout" >
+       <item row="1" column="0" >
+        <widget class="QRadioButton" name="RadioButton1_2" >
+@@ -210,12 +207,6 @@
+  <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+  <customwidgets>
+   <customwidget>
+-   <class>Q3ButtonGroup</class>
+-   <extends>Q3GroupBox</extends>
+-   <header>Qt3Support/Q3ButtonGroup</header>
+-   <container>1</container>
+-  </customwidget>
+-  <customwidget>
+    <class>KDoubleNumInput</class>
+    <extends>QWidget</extends>
+    <header>knuminput.h</header>
+--- a/kcontrol/kxkb/kcmmisc/kcmmisc.cpp
++++ b/kcontrol/kxkb/kcmmisc/kcmmisc.cpp
+@@ -35,7 +35,7 @@
+ 
+ #include <QLayout>
+ #include <QWhatsThis>
+-#include <Q3ButtonGroup>
++#include <KButtonGroup>
+ #include <QRadioButton>
+ 
+ #include <klocale.h>
+@@ -123,18 +123,15 @@
+ 
+ int KeyboardConfig::getNumLockState()
+ {
+-    QAbstractButton* selected = ui->numlockGroup->selected();
+-    if( selected == NULL )
++    int selected = ui->numlockGroup->selected();
++    if( selected < 0 )
+         return 2;
+-    int ret = ui->numlockGroup->id( selected );
+-    if( ret == -1 )
+-        ret = 2;
+-    return ret;
++    return selected;
+ }
+ 
+ void KeyboardConfig::setNumLockState( int s )
+ {
+-    ui->numlockGroup->setButton( s );
++    ui->numlockGroup->setSelected( s );
+ }
+ 
+ void KeyboardConfig::load()
+--- a/kcontrol/kxkb/kcmmisc/keyboard.desktop
++++ b/kcontrol/kxkb/kcmmisc/keyboard.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell keyboard
++Exec=kcmshell4 keyboard
+ Icon=preferences-desktop-keyboard
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+@@ -170,7 +170,7 @@
+ Keywords[is]=Lyklaborð,inntakstæki,endurtekning,útlit,alþjóðlegt
+ Keywords[it]=tastiera,ripetizione dei tasti,volume del clic,dispositivi di input,layout,volume
+ Keywords[ja]=キーボード,キーボードリピート,クリック音量,入力デバイス,リピート,音量
+-Keywords[km]=ក្ដារ​ចុច,ការ​ធ្វើ​តាម​ក្ដារចុច,សំឡេង​ចុច,ឧបករណ៍​បញ្ចូល,ធ្វើ​ម្ដង​ទៀត,សំឡេង
++Keywords[km]=ក្ដារ​ចុច ការ​ធ្វើ​តាម​ក្ដារចុច សំឡេង​ចុច ឧបករណ៍​បញ្ចូល ធ្វើ​ម្ដង​ទៀត សំឡេង
+ Keywords[ko]=키보드,키보드 반복,입력 음량,입력 장치,반복,음량
+ Keywords[lt]=Klaviatūra,Klaviatūros kartojimai,Paspaudimo garsas,Įvedimo įrenginiai,kartojimas, garsas
+ Keywords[lv]=Tastatūra,Tastatūras atkārtošanās,Klikšķu līmenis,Ievades Iekārtas,atkārtošanās,līmenis,Izkārtojums
+--- a/kcontrol/kxkb/kcmmisc/CMakeLists.txt
++++ b/kcontrol/kxkb/kcmmisc/CMakeLists.txt
+@@ -1,5 +1,3 @@
+-#add_definitions (-DQT3_SUPPORT)
+-
+ # TODO: add this piece to kdeinit
+ 
+ ########### KCM ###############
+@@ -16,7 +14,7 @@
+ 
+ 
+ target_link_libraries(kcm_keyboard
+-    ${KDE4_KIO_LIBS} xkbfile ${QT_QT3SUPPORT_LIBRARY}
++    ${KDE4_KIO_LIBS} xkbfile
+     ${XKB_SUPPORT_LIB}
+ )
+ if(X11_XTest_FOUND)
+--- a/kcontrol/kxkb/kcmlayoutwidget.ui
++++ b/kcontrol/kxkb/kcmlayoutwidget.ui
+@@ -5,7 +5,7 @@
+    <rect>
+     <x>0</x>
+     <y>0</y>
+-    <width>625</width>
++    <width>630</width>
+     <height>538</height>
+    </rect>
+   </property>
+@@ -25,255 +25,428 @@
+       </size>
+      </property>
+      <property name="currentIndex" >
+-      <number>0</number>
++      <number>2</number>
+      </property>
+      <widget class="QWidget" name="tabLayout" >
+       <attribute name="title" >
+        <string>Layout</string>
+       </attribute>
+-      <layout class="QGridLayout" >
+-       <item row="0" column="0" >
+-        <widget class="QCheckBox" name="chkEnable" >
++      <widget class="QGroupBox" name="grpLayouts" >
++       <property name="geometry" >
++        <rect>
++         <x>10</x>
++         <y>60</y>
++         <width>590</width>
++         <height>431</height>
++        </rect>
++       </property>
++       <property name="whatsThis" >
++        <string>&lt;h1>Keyboard Layout&lt;/h1> Here you can choose your keyboard layout and model. The 'model' refers to the type of keyboard that is connected to your computer, while the keyboard layout defines "which key does what" and may be different for different countries.</string>
++       </property>
++       <property name="title" >
++        <string/>
++       </property>
++       <widget class="QLabel" name="textLabel1_4" >
++        <property name="geometry" >
++         <rect>
++          <x>10</x>
++          <y>100</y>
++          <width>189</width>
++          <height>16</height>
++         </rect>
++        </property>
++        <property name="text" >
++         <string>Available layouts:</string>
++        </property>
++       </widget>
++       <widget class="QLabel" name="textLabel1_4_2" >
++        <property name="geometry" >
++         <rect>
++          <x>210</x>
++          <y>100</y>
++          <width>368</width>
++          <height>16</height>
++         </rect>
++        </property>
++        <property name="text" >
++         <string>Active layouts:</string>
++        </property>
++       </widget>
++       <widget class="QTableView" name="srcTableView" >
++        <property name="geometry" >
++         <rect>
++          <x>11</x>
++          <y>120</y>
++          <width>211</width>
++          <height>271</height>
++         </rect>
++        </property>
++        <property name="selectionMode" >
++         <enum>QAbstractItemView::SingleSelection</enum>
++        </property>
++        <property name="selectionBehavior" >
++         <enum>QAbstractItemView::SelectRows</enum>
++        </property>
++        <property name="cornerButtonEnabled" >
++         <bool>false</bool>
++        </property>
++       </widget>
++       <widget class="QTableView" name="dstTableView" >
++        <property name="geometry" >
++         <rect>
++          <x>223</x>
++          <y>120</y>
++          <width>351</width>
++          <height>171</height>
++         </rect>
++        </property>
++        <property name="selectionMode" >
++         <enum>QAbstractItemView::SingleSelection</enum>
++        </property>
++        <property name="selectionBehavior" >
++         <enum>QAbstractItemView::SelectRows</enum>
++        </property>
++        <property name="showGrid" >
++         <bool>false</bool>
++        </property>
++        <property name="wordWrap" >
++         <bool>false</bool>
++        </property>
++       </widget>
++       <widget class="QLabel" name="textLabel1_3" >
++        <property name="geometry" >
++         <rect>
++          <x>10</x>
++          <y>400</y>
++          <width>92</width>
++          <height>22</height>
++         </rect>
++        </property>
++        <property name="text" >
++         <string>Command:</string>
++        </property>
++        <property name="buddy" >
++         <cstring>editCmdLine</cstring>
++        </property>
++       </widget>
++       <widget class="QLineEdit" name="editCmdLine" >
++        <property name="geometry" >
++         <rect>
++          <x>108</x>
++          <y>400</y>
++          <width>465</width>
++          <height>22</height>
++         </rect>
++        </property>
++        <property name="whatsThis" >
++         <string>This is the command which is executed when switching to the selected layout. It may help you if you want to debug layout switching, or if you want to switch layouts without the help of KDE.</string>
++        </property>
++        <property name="readOnly" >
++         <bool>true</bool>
++        </property>
++       </widget>
++       <widget class="Line" name="line" >
++        <property name="geometry" >
++         <rect>
++          <x>10</x>
++          <y>390</y>
++          <width>571</width>
++          <height>10</height>
++         </rect>
++        </property>
++        <property name="orientation" >
++         <enum>Qt::Horizontal</enum>
++        </property>
++       </widget>
++       <widget class="QWidget" name="layoutWidget" >
++        <property name="geometry" >
++         <rect>
++          <x>223</x>
++          <y>297</y>
++          <width>351</width>
++          <height>28</height>
++         </rect>
++        </property>
++        <layout class="QHBoxLayout" >
++         <property name="spacing" >
++          <number>6</number>
++         </property>
++         <property name="leftMargin" >
++          <number>0</number>
++         </property>
++         <property name="topMargin" >
++          <number>0</number>
++         </property>
++         <property name="rightMargin" >
++          <number>0</number>
++         </property>
++         <property name="bottomMargin" >
++          <number>0</number>
++         </property>
++         <item>
++          <widget class="QPushButton" name="btnAdd" >
++           <property name="text" >
++            <string>Add >></string>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <widget class="QPushButton" name="btnRemove" >
++           <property name="text" >
++            <string>&lt;&lt; Remove</string>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <widget class="QPushButton" name="btnUp" >
++           <property name="sizePolicy" >
++            <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
++             <horstretch>0</horstretch>
++             <verstretch>0</verstretch>
++            </sizepolicy>
++           </property>
++           <property name="text" >
++            <string/>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <widget class="QPushButton" name="btnDown" >
++           <property name="sizePolicy" >
++            <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
++             <horstretch>0</horstretch>
++             <verstretch>0</verstretch>
++            </sizepolicy>
++           </property>
++           <property name="text" >
++            <string/>
++           </property>
++          </widget>
++         </item>
++        </layout>
++       </widget>
++       <widget class="QWidget" name="layoutWidget" >
++        <property name="geometry" >
++         <rect>
++          <x>226</x>
++          <y>332</y>
++          <width>351</width>
++          <height>30</height>
++         </rect>
++        </property>
++        <layout class="QHBoxLayout" >
++         <item>
++          <widget class="QLabel" name="textLabel1" >
++           <property name="text" >
++            <string>Layout variant:</string>
++           </property>
++           <property name="buddy" >
++            <cstring>comboVariant</cstring>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <widget class="QComboBox" name="comboVariant" >
++           <property name="whatsThis" >
++            <string>Here you can choose a variant of selected keyboard layout. Layout variants usually represent different key maps for the same language. For example, Ukrainian layout might have four variants: basic, winkeys (as in Windows), typewriter (as in typewriters) and phonetic (each Ukrainian letter is placed on a transliterated latin one).
++</string>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <spacer>
++           <property name="orientation" >
++            <enum>Qt::Horizontal</enum>
++           </property>
++           <property name="sizeType" >
++            <enum>QSizePolicy::Expanding</enum>
++           </property>
++           <property name="sizeHint" >
++            <size>
++             <width>210</width>
++             <height>20</height>
++            </size>
++           </property>
++          </spacer>
++         </item>
++        </layout>
++       </widget>
++       <widget class="QWidget" name="layoutWidget" >
++        <property name="geometry" >
++         <rect>
++          <x>230</x>
++          <y>360</y>
++          <width>351</width>
++          <height>30</height>
++         </rect>
++        </property>
++        <layout class="QHBoxLayout" >
++         <item>
++          <widget class="QLabel" name="textLabel1_6" >
++           <property name="text" >
++            <string>Label:</string>
++           </property>
++           <property name="buddy" >
++            <cstring>editDisplayName</cstring>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <widget class="QLineEdit" name="editDisplayName" >
++           <property name="enabled" >
++            <bool>false</bool>
++           </property>
++           <property name="maxLength" >
++            <number>3</number>
++           </property>
++          </widget>
++         </item>
++         <item>
++          <spacer>
++           <property name="orientation" >
++            <enum>Qt::Horizontal</enum>
++           </property>
++           <property name="sizeType" >
++            <enum>QSizePolicy::Expanding</enum>
++           </property>
++           <property name="sizeHint" >
++            <size>
++             <width>210</width>
++             <height>20</height>
++            </size>
++           </property>
++          </spacer>
++         </item>
++        </layout>
++       </widget>
++       <widget class="QGroupBox" name="groupBox_2" >
++        <property name="geometry" >
++         <rect>
++          <x>309</x>
++          <y>20</y>
++          <width>261</width>
++          <height>61</height>
++         </rect>
++        </property>
++        <property name="title" >
++         <string/>
++        </property>
++        <widget class="QLabel" name="textLabel1_2" >
++         <property name="geometry" >
++          <rect>
++           <x>10</x>
++           <y>0</y>
++           <width>111</width>
++           <height>20</height>
++          </rect>
++         </property>
+          <property name="text" >
+-          <string>&amp;Enable keyboard layouts</string>
++          <string>Keyboard &amp;model:</string>
+          </property>
+-         <property name="checked" >
+-          <bool>true</bool>
++         <property name="buddy" >
++          <cstring>comboModel</cstring>
+          </property>
+         </widget>
+-       </item>
+-       <item row="1" column="0" >
+-        <widget class="Q3GroupBox" name="grpLayouts" >
++        <widget class="QComboBox" name="comboModel" >
++         <property name="geometry" >
++          <rect>
++           <x>10</x>
++           <y>30</y>
++           <width>241</width>
++           <height>21</height>
++          </rect>
++         </property>
++         <property name="sizePolicy" >
++          <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
++           <horstretch>0</horstretch>
++           <verstretch>0</verstretch>
++          </sizepolicy>
++         </property>
+          <property name="whatsThis" >
+-          <string>&lt;h1>Keyboard Layout&lt;/h1> Here you can choose your keyboard layout and model. The 'model' refers to the type of keyboard that is connected to your computer, while the keyboard layout defines "which key does what" and may be different for different countries.</string>
++          <string>Here you can choose a keyboard model. This setting is independent of your keyboard layout and refers to the "hardware" model, i.e. the way your keyboard is manufactured. Modern keyboards that come with your computer usually have two extra keys and are referred to as "104-key" models, which is probably what you want if you do not know what kind of keyboard you have.
++</string>
+          </property>
+-         <property name="title" >
+-          <string/>
++        </widget>
++       </widget>
++       <widget class="QGroupBox" name="grpOptions" >
++        <property name="geometry" >
++         <rect>
++          <x>10</x>
++          <y>10</y>
++          <width>291</width>
++          <height>71</height>
++         </rect>
++        </property>
++        <property name="title" >
++         <string>Indicator Options</string>
++        </property>
++        <widget class="QCheckBox" name="chkShowFlag" >
++         <property name="geometry" >
++          <rect>
++           <x>10</x>
++           <y>40</y>
++           <width>261</width>
++           <height>22</height>
++          </rect>
+          </property>
+-         <property name="orientation" >
+-          <enum>Qt::Vertical</enum>
++         <property name="whatsThis" >
++          <string>Shows country flag on background of layout name in tray icon</string>
++         </property>
++         <property name="text" >
++          <string>Show country flag</string>
++         </property>
++         <property name="checked" >
++          <bool>true</bool>
+          </property>
+-         <layout class="QGridLayout" >
+-          <item row="0" column="2" colspan="3" >
+-           <widget class="QLabel" name="textLabel1_2" >
+-            <property name="text" >
+-             <string>Keyboard &amp;model:</string>
+-            </property>
+-            <property name="buddy" >
+-             <cstring>comboModel</cstring>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="1" column="2" colspan="3" >
+-           <widget class="QComboBox" name="comboModel" >
+-            <property name="sizePolicy" >
+-             <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+-              <horstretch>0</horstretch>
+-              <verstretch>0</verstretch>
+-             </sizepolicy>
+-            </property>
+-            <property name="whatsThis" >
+-             <string>Here you can choose a keyboard model. This setting is independent of your keyboard layout and refers to the "hardware" model, i.e. the way your keyboard is manufactured. Modern keyboards that come with your computer usually have two extra keys and are referred to as "104-key" models, which is probably what you want if you do not know what kind of keyboard you have.
+-</string>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="2" column="0" colspan="2" >
+-           <widget class="QLabel" name="textLabel1_4" >
+-            <property name="text" >
+-             <string>Available layouts:</string>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="2" column="2" colspan="3" >
+-           <widget class="QLabel" name="textLabel1_4_2" >
+-            <property name="text" >
+-             <string>Active layouts:</string>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="3" column="0" colspan="2" >
+-           <widget class="QTableView" name="srcTableView" >
+-            <property name="selectionMode" >
+-             <enum>QAbstractItemView::SingleSelection</enum>
+-            </property>
+-            <property name="selectionBehavior" >
+-             <enum>QAbstractItemView::SelectRows</enum>
+-            </property>
+-            <property name="cornerButtonEnabled" >
+-             <bool>false</bool>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="3" column="2" colspan="3" >
+-           <widget class="QTableView" name="dstTableView" >
+-            <property name="selectionMode" >
+-             <enum>QAbstractItemView::SingleSelection</enum>
+-            </property>
+-            <property name="selectionBehavior" >
+-             <enum>QAbstractItemView::SelectRows</enum>
+-            </property>
+-            <property name="showGrid" >
+-             <bool>false</bool>
+-            </property>
+-            <property name="wordWrap" >
+-             <bool>false</bool>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="4" column="2" colspan="3" >
+-           <layout class="QHBoxLayout" >
+-            <property name="spacing" >
+-             <number>6</number>
+-            </property>
+-            <property name="leftMargin" >
+-             <number>0</number>
+-            </property>
+-            <property name="topMargin" >
+-             <number>0</number>
+-            </property>
+-            <property name="rightMargin" >
+-             <number>0</number>
+-            </property>
+-            <property name="bottomMargin" >
+-             <number>0</number>
+-            </property>
+-            <item>
+-             <widget class="QPushButton" name="btnAdd" >
+-              <property name="text" >
+-               <string>Add >></string>
+-              </property>
+-             </widget>
+-            </item>
+-            <item>
+-             <widget class="QPushButton" name="btnRemove" >
+-              <property name="text" >
+-               <string>&lt;&lt; Remove</string>
+-              </property>
+-             </widget>
+-            </item>
+-            <item>
+-             <widget class="QPushButton" name="btnUp" >
+-              <property name="sizePolicy" >
+-               <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+-                <horstretch>0</horstretch>
+-                <verstretch>0</verstretch>
+-               </sizepolicy>
+-              </property>
+-              <property name="text" >
+-               <string/>
+-              </property>
+-             </widget>
+-            </item>
+-            <item>
+-             <widget class="QPushButton" name="btnDown" >
+-              <property name="sizePolicy" >
+-               <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+-                <horstretch>0</horstretch>
+-                <verstretch>0</verstretch>
+-               </sizepolicy>
+-              </property>
+-              <property name="text" >
+-               <string/>
+-              </property>
+-             </widget>
+-            </item>
+-           </layout>
+-          </item>
+-          <item row="5" column="2" >
+-           <widget class="QLabel" name="textLabel1" >
+-            <property name="text" >
+-             <string>Layout variant:</string>
+-            </property>
+-            <property name="buddy" >
+-             <cstring>comboVariant</cstring>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="5" column="3" >
+-           <widget class="QComboBox" name="comboVariant" >
+-            <property name="whatsThis" >
+-             <string>Here you can choose a variant of selected keyboard layout. Layout variants usually represent different key maps for the same language. For example, Ukrainian layout might have four variants: basic, winkeys (as in Windows), typewriter (as in typewriters) and phonetic (each Ukrainian letter is placed on a transliterated latin one).
+-</string>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="5" column="4" >
+-           <spacer>
+-            <property name="orientation" >
+-             <enum>Qt::Horizontal</enum>
+-            </property>
+-            <property name="sizeType" >
+-             <enum>QSizePolicy::Expanding</enum>
+-            </property>
+-            <property name="sizeHint" >
+-             <size>
+-              <width>210</width>
+-              <height>20</height>
+-             </size>
+-            </property>
+-           </spacer>
+-          </item>
+-          <item row="6" column="2" >
+-           <widget class="QLabel" name="textLabel1_6" >
+-            <property name="text" >
+-             <string>Label:</string>
+-            </property>
+-            <property name="buddy" >
+-             <cstring>editDisplayName</cstring>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="6" column="3" >
+-           <widget class="QLineEdit" name="editDisplayName" >
+-            <property name="enabled" >
+-             <bool>false</bool>
+-            </property>
+-            <property name="maxLength" >
+-             <number>3</number>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="6" column="4" >
+-           <spacer>
+-            <property name="orientation" >
+-             <enum>Qt::Horizontal</enum>
+-            </property>
+-            <property name="sizeType" >
+-             <enum>QSizePolicy::Expanding</enum>
+-            </property>
+-            <property name="sizeHint" >
+-             <size>
+-              <width>210</width>
+-              <height>20</height>
+-             </size>
+-            </property>
+-           </spacer>
+-          </item>
+-          <item row="7" column="0" >
+-           <widget class="QLabel" name="textLabel1_3" >
+-            <property name="text" >
+-             <string>Command:</string>
+-            </property>
+-            <property name="buddy" >
+-             <cstring>editCmdLine</cstring>
+-            </property>
+-           </widget>
+-          </item>
+-          <item row="7" column="1" colspan="4" >
+-           <widget class="QLineEdit" name="editCmdLine" >
+-            <property name="whatsThis" >
+-             <string>This is the command which is executed when switching to the selected layout. It may help you if you want to debug layout switching, or if you want to switch layouts without the help of KDE.</string>
+-            </property>
+-            <property name="readOnly" >
+-             <bool>true</bool>
+-            </property>
+-           </widget>
+-          </item>
+-         </layout>
+         </widget>
+-       </item>
+-      </layout>
++        <widget class="QCheckBox" name="chkShowSingle" >
++         <property name="geometry" >
++          <rect>
++           <x>10</x>
++           <y>20</y>
++           <width>241</width>
++           <height>22</height>
++          </rect>
++         </property>
++         <property name="text" >
++          <string>Show indicator for single layout</string>
++         </property>
++        </widget>
++       </widget>
++      </widget>
++      <widget class="KButtonGroup" name="grpEnableKxkb" >
++       <property name="geometry" >
++        <rect>
++         <x>10</x>
++         <y>10</y>
++         <width>591</width>
++         <height>44</height>
++        </rect>
++       </property>
++       <layout class="QHBoxLayout" >
++        <item>
++         <widget class="QRadioButton" name="radioButton" >
++          <property name="text" >
++           <string>&amp;Enable keyboard layouts</string>
++          </property>
++         </widget>
++        </item>
++        <item>
++         <widget class="QRadioButton" name="radioButton_2" >
++          <property name="text" >
++           <string>Indicator only</string>
++          </property>
++         </widget>
++        </item>
++        <item>
++         <widget class="QRadioButton" name="radioButton_3" >
++          <property name="text" >
++           <string>Disable keyboard layouts</string>
++          </property>
++         </widget>
++        </item>
++       </layout>
++      </widget>
+      </widget>
+      <widget class="QWidget" name="tab" >
+       <attribute name="title" >
+@@ -291,257 +464,254 @@
+          <property name="lineWidth" >
+           <number>0</number>
+          </property>
+-         <layout class="QGridLayout" >
+-          <item row="0" column="0" colspan="2" >
+-           <widget class="QGroupBox" name="grpOptions" >
+-            <property name="title" >
+-             <string>Options</string>
+-            </property>
+-            <widget class="QCheckBox" name="chkShowFlag" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>10</x>
+-               <y>70</y>
+-               <width>556</width>
+-               <height>22</height>
+-              </rect>
+-             </property>
+-             <property name="whatsThis" >
+-              <string>Shows country flag on background of layout name in tray icon</string>
+-             </property>
++         <widget class="KButtonGroup" name="grpSwitching" >
++          <property name="geometry" >
++           <rect>
++            <x>11</x>
++            <y>10</y>
++            <width>276</width>
++            <height>146</height>
++           </rect>
++          </property>
++          <property name="whatsThis" >
++           <string>If you select "Application" or "Window" switching policy, changing the keyboard layout will only affect the current application or window.</string>
++          </property>
++          <property name="title" >
++           <string>Switching Policy</string>
++          </property>
++          <layout class="QGridLayout" >
++           <item row="0" column="0" >
++            <widget class="QRadioButton" name="rdBtnSwitchGlobal" >
+              <property name="text" >
+-              <string>Show country flag</string>
++              <string>&amp;Global</string>
+              </property>
+              <property name="checked" >
+               <bool>true</bool>
+              </property>
+             </widget>
+-            <widget class="QCheckBox" name="chkIndicatorOnly" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>9</x>
+-               <y>16</y>
+-               <width>341</width>
+-               <height>22</height>
+-              </rect>
+-             </property>
++           </item>
++           <item row="1" column="0" >
++            <widget class="QRadioButton" name="rdBtnSwitchPerDesktop" >
+              <property name="text" >
+-              <string>Indicator only</string>
++              <string>Desktop</string>
+              </property>
+             </widget>
+-            <widget class="QCheckBox" name="chkShowSingle" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>10</x>
+-               <y>40</y>
+-               <width>556</width>
+-               <height>22</height>
+-              </rect>
+-             </property>
++           </item>
++           <item row="2" column="0" >
++            <widget class="QRadioButton" name="rdBtnSwitchPerApp" >
+              <property name="text" >
+-              <string>Show indicator for single layout</string>
++              <string>Application</string>
+              </property>
+             </widget>
+-           </widget>
+-          </item>
+-          <item row="1" column="0" >
+-           <widget class="Q3ButtonGroup" name="grpSwitching" >
+-            <property name="whatsThis" >
+-             <string>If you select "Application" or "Window" switching policy, changing the keyboard layout will only affect the current application or window.</string>
+-            </property>
+-            <property name="title" >
+-             <string>Switching Policy</string>
+-            </property>
+-            <property name="orientation" >
+-             <enum>Qt::Vertical</enum>
+-            </property>
+-            <property name="exclusive" >
+-             <bool>true</bool>
+-            </property>
+-            <layout class="QGridLayout" >
+-             <item row="0" column="0" >
+-              <widget class="QRadioButton" name="rdBtnSwitchGlobal" >
+-               <property name="text" >
+-                <string>&amp;Global</string>
+-               </property>
+-               <property name="checked" >
+-                <bool>true</bool>
+-               </property>
+-              </widget>
+-             </item>
+-             <item row="1" column="0" >
+-              <widget class="QRadioButton" name="rdBtnSwitchPerDesktop" >
+-               <property name="text" >
+-                <string>Desktop</string>
+-               </property>
+-              </widget>
+-             </item>
+-             <item row="2" column="0" >
+-              <widget class="QRadioButton" name="rdBtnSwitchPerApp" >
+-               <property name="text" >
+-                <string>Application</string>
+-               </property>
+-              </widget>
+-             </item>
+-             <item row="3" column="0" >
+-              <widget class="QRadioButton" name="rdBtnSwitchPerWin" >
+-               <property name="text" >
+-                <string>&amp;Window</string>
+-               </property>
+-              </widget>
+-             </item>
+-            </layout>
+-           </widget>
+-          </item>
+-          <item row="1" column="1" >
+-           <widget class="QGroupBox" name="grpBoxStickySwitching" >
+-            <property name="title" >
+-             <string>Sticky Switching</string>
+-            </property>
+-            <layout class="QGridLayout" >
+-             <property name="leftMargin" >
+-              <number>11</number>
+-             </property>
+-             <property name="topMargin" >
+-              <number>11</number>
+-             </property>
+-             <property name="rightMargin" >
+-              <number>11</number>
+-             </property>
+-             <property name="bottomMargin" >
+-              <number>11</number>
+-             </property>
+-             <property name="horizontalSpacing" >
+-              <number>6</number>
+-             </property>
+-             <property name="verticalSpacing" >
+-              <number>6</number>
+-             </property>
+-             <item row="0" column="0" colspan="2" >
+-              <widget class="QCheckBox" name="chkEnableSticky" >
+-               <property name="whatsThis" >
+-                <string>If you have more than two layouts and turn this option on, switching with the keyboard shortcut or clicking on the kxkb indicator will only cycle through the last few layouts. You can specify the number of layouts to rotate below. You can still access all layouts by right-clicking on the kxkb indicator.</string>
+-               </property>
+-               <property name="text" >
+-                <string>Enable sticky switching</string>
+-               </property>
+-              </widget>
+-             </item>
+-             <item row="1" column="0" >
+-              <widget class="QLabel" name="textLabel1_5" >
+-               <property name="enabled" >
+-                <bool>false</bool>
+-               </property>
+-               <property name="text" >
+-                <string>Number of layouts to rotate:</string>
+-               </property>
+-               <property name="buddy" >
+-                <cstring>spinBox1</cstring>
+-               </property>
+-              </widget>
+-             </item>
+-             <item row="1" column="1" >
+-              <widget class="QSpinBox" name="spinStickyDepth" >
+-               <property name="enabled" >
+-                <bool>false</bool>
+-               </property>
+-               <property name="minimum" >
+-                <number>2</number>
+-               </property>
+-               <property name="maximum" >
+-                <number>10</number>
+-               </property>
+-              </widget>
+-             </item>
+-            </layout>
+-           </widget>
+-          </item>
+-          <item row="2" column="0" >
+-           <widget class="QGroupBox" name="grpShortcuts" >
+-            <property name="title" >
+-             <string>Shortcuts</string>
+-            </property>
+-            <widget class="QRadioButton" name="rdCtrlShift" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>10</x>
+-               <y>20</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
+-             </property>
++           </item>
++           <item row="3" column="0" >
++            <widget class="QRadioButton" name="rdBtnSwitchPerWin" >
+              <property name="text" >
+-              <string>Ctrl+Shift</string>
++              <string>&amp;Window</string>
+              </property>
+             </widget>
+-            <widget class="QRadioButton" name="rdAltShift" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>10</x>
+-               <y>80</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
++           </item>
++          </layout>
++         </widget>
++         <widget class="QGroupBox" name="grpBoxStickySwitching" >
++          <property name="geometry" >
++           <rect>
++            <x>10</x>
++            <y>170</y>
++            <width>276</width>
++            <height>146</height>
++           </rect>
++          </property>
++          <property name="title" >
++           <string>Sticky Switching</string>
++          </property>
++          <layout class="QGridLayout" >
++           <property name="leftMargin" >
++            <number>11</number>
++           </property>
++           <property name="topMargin" >
++            <number>11</number>
++           </property>
++           <property name="rightMargin" >
++            <number>11</number>
++           </property>
++           <property name="bottomMargin" >
++            <number>11</number>
++           </property>
++           <property name="horizontalSpacing" >
++            <number>6</number>
++           </property>
++           <property name="verticalSpacing" >
++            <number>6</number>
++           </property>
++           <item row="0" column="0" colspan="2" >
++            <widget class="QCheckBox" name="chkEnableSticky" >
++             <property name="whatsThis" >
++              <string>If you have more than two layouts and turn this option on, switching with the keyboard shortcut or clicking on the kxkb indicator will only cycle through the last few layouts. You can specify the number of layouts to rotate below. You can still access all layouts by right-clicking on the kxkb indicator.</string>
+              </property>
+              <property name="text" >
+-              <string>Alt+Shift</string>
++              <string>Enable sticky switching</string>
+              </property>
+             </widget>
+-            <widget class="QRadioButton" name="rdCtrlCtrl" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>140</x>
+-               <y>20</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
++           </item>
++           <item row="1" column="0" >
++            <widget class="QLabel" name="textLabel1_5" >
++             <property name="enabled" >
++              <bool>false</bool>
+              </property>
+              <property name="text" >
+-              <string>Ctrl+Ctrl</string>
++              <string>Number of layouts to rotate:</string>
+              </property>
+-            </widget>
+-            <widget class="QRadioButton" name="rdShiftShift" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>140</x>
+-               <y>50</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
+-             </property>
+-             <property name="text" >
+-              <string>Shift+Shift</string>
++             <property name="buddy" >
++              <cstring>spinBox1</cstring>
+              </property>
+             </widget>
+-            <widget class="QRadioButton" name="rdAltAlt" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>140</x>
+-               <y>80</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
++           </item>
++           <item row="1" column="1" >
++            <widget class="QSpinBox" name="spinStickyDepth" >
++             <property name="enabled" >
++              <bool>false</bool>
+              </property>
+-             <property name="text" >
+-              <string>Alt+Alt</string>
++             <property name="minimum" >
++              <number>2</number>
+              </property>
+-            </widget>
+-            <widget class="QRadioButton" name="rdAltCtrl" >
+-             <property name="geometry" >
+-              <rect>
+-               <x>10</x>
+-               <y>50</y>
+-               <width>100</width>
+-               <height>23</height>
+-              </rect>
+-             </property>
+-             <property name="text" >
+-              <string>Alt+Ctrl</string>
++             <property name="maximum" >
++              <number>10</number>
+              </property>
+             </widget>
+-           </widget>
+-          </item>
+-         </layout>
++           </item>
++          </layout>
++         </widget>
++         <widget class="QGroupBox" name="groupBox" >
++          <property name="geometry" >
++           <rect>
++            <x>300</x>
++            <y>10</y>
++            <width>261</width>
++            <height>141</height>
++           </rect>
++          </property>
++          <property name="title" >
++           <string>Shortcuts for switching layout</string>
++          </property>
++          <widget class="QLabel" name="label" >
++           <property name="geometry" >
++            <rect>
++             <x>10</x>
++             <y>50</y>
++             <width>51</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>X.org</string>
++           </property>
++          </widget>
++          <widget class="QLabel" name="xkbShortcut" >
++           <property name="geometry" >
++            <rect>
++             <x>74</x>
++             <y>50</y>
++             <width>81</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>Not defined</string>
++           </property>
++          </widget>
++          <widget class="QPushButton" name="btnXkbShortcut" >
++           <property name="geometry" >
++            <rect>
++             <x>170</x>
++             <y>50</y>
++             <width>75</width>
++             <height>26</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>...</string>
++           </property>
++          </widget>
++          <widget class="QLabel" name="label_2" >
++           <property name="geometry" >
++            <rect>
++             <x>10</x>
++             <y>20</y>
++             <width>51</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>KDE</string>
++           </property>
++          </widget>
++          <widget class="QPushButton" name="btnKdeShortcut" >
++           <property name="geometry" >
++            <rect>
++             <x>170</x>
++             <y>20</y>
++             <width>75</width>
++             <height>26</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>...</string>
++           </property>
++          </widget>
++          <widget class="QLabel" name="kdeShortcut" >
++           <property name="geometry" >
++            <rect>
++             <x>74</x>
++             <y>20</y>
++             <width>81</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>Not defined</string>
++           </property>
++          </widget>
++          <widget class="QPushButton" name="btnXkbShortcut3d" >
++           <property name="geometry" >
++            <rect>
++             <x>171</x>
++             <y>80</y>
++             <width>74</width>
++             <height>26</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>...</string>
++           </property>
++          </widget>
++          <widget class="QLabel" name="label_3" >
++           <property name="geometry" >
++            <rect>
++             <x>10</x>
++             <y>80</y>
++             <width>51</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>3d level</string>
++           </property>
++          </widget>
++          <widget class="QLabel" name="xkbShortcut3d" >
++           <property name="geometry" >
++            <rect>
++             <x>75</x>
++             <y>80</y>
++             <width>80</width>
++             <height>20</height>
++            </rect>
++           </property>
++           <property name="text" >
++            <string>Not defined</string>
++           </property>
++          </widget>
++         </widget>
+         </widget>
+        </item>
+       </layout>
+@@ -562,16 +732,13 @@
+         </widget>
+        </item>
+        <item>
+-        <widget class="Q3GroupBox" name="groupBox3_2" >
++        <widget class="QGroupBox" name="groupBox3_2" >
+          <property name="whatsThis" >
+           <string>Here you can set xkb extension options instead of, or in addition to, specifying them in the X11 configuration file.</string>
+          </property>
+          <property name="title" >
+           <string>Xkb Options</string>
+          </property>
+-         <property name="orientation" >
+-          <enum>Qt::Vertical</enum>
+-         </property>
+          <layout class="QGridLayout" >
+           <item row="0" column="0" colspan="2" >
+            <widget class="QCheckBox" name="checkResetOld" >
+@@ -580,29 +747,27 @@
+             </property>
+            </widget>
+           </item>
+-          <item row="2" column="0" >
++          <item row="2" column="0" colspan="2" >
++           <widget class="QTreeView" name="xkbOptionsTreeView" >
++            <property name="selectionMode" >
++             <enum>QAbstractItemView::NoSelection</enum>
++            </property>
++           </widget>
++          </item>
++          <item row="3" column="0" >
+            <widget class="QLabel" name="textLabel1_3_2" >
+             <property name="text" >
+              <string>Command:</string>
+             </property>
+            </widget>
+           </item>
+-          <item row="2" column="1" >
++          <item row="3" column="1" >
+            <widget class="QLineEdit" name="editCmdLineOpt" >
+             <property name="readOnly" >
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+-          <item row="1" column="0" colspan="2" >
+-           <widget class="Q3ListView" name="listOptions" >
+-            <column>
+-             <property name="text" >
+-              <string>Options</string>
+-             </property>
+-            </column>
+-           </widget>
+-          </item>
+          </layout>
+         </widget>
+        </item>
+@@ -617,42 +782,15 @@
+  <pixmapfunction>SmallIcon</pixmapfunction>
+  <customwidgets>
+   <customwidget>
+-   <class>Q3GroupBox</class>
++   <class>KButtonGroup</class>
+    <extends>QGroupBox</extends>
+-   <header>Qt3Support/Q3GroupBox</header>
+-   <container>1</container>
+-  </customwidget>
+-  <customwidget>
+-   <class>Q3ButtonGroup</class>
+-   <extends>Q3GroupBox</extends>
+-   <header>Qt3Support/Q3ButtonGroup</header>
++   <header>kbuttongroup.h</header>
+    <container>1</container>
+   </customwidget>
+-  <customwidget>
+-   <class>Q3ListView</class>
+-   <extends>Q3Frame</extends>
+-   <header>q3listview.h</header>
+-  </customwidget>
+  </customwidgets>
+  <resources/>
+  <connections>
+   <connection>
+-   <sender>chkEnable</sender>
+-   <signal>toggled(bool)</signal>
+-   <receiver>grpLayouts</receiver>
+-   <slot>setEnabled(bool)</slot>
+-   <hints>
+-    <hint type="sourcelabel" >
+-     <x>20</x>
+-     <y>20</y>
+-    </hint>
+-    <hint type="destinationlabel" >
+-     <x>20</x>
+-     <y>20</y>
+-    </hint>
+-   </hints>
+-  </connection>
+-  <connection>
+    <sender>chkEnableOptions</sender>
+    <signal>toggled(bool)</signal>
+    <receiver>groupBox3_2</receiver>
+@@ -700,21 +838,5 @@
+     </hint>
+    </hints>
+   </connection>
+-  <connection>
+-   <sender>chkEnable</sender>
+-   <signal>toggled(bool)</signal>
+-   <receiver>optionsFrame</receiver>
+-   <slot>setEnabled(bool)</slot>
+-   <hints>
+-    <hint type="sourcelabel" >
+-     <x>20</x>
+-     <y>20</y>
+-    </hint>
+-    <hint type="destinationlabel" >
+-     <x>20</x>
+-     <y>20</y>
+-    </hint>
+-   </hints>
+-  </connection>
+  </connections>
+ </ui>
+--- a/kcontrol/kxkb/kxkbwidget.h
++++ b/kcontrol/kxkb/kxkbwidget.h
+@@ -41,12 +41,12 @@
+ */
+ class KxkbWidget : public QObject
+ {
+- 	Q_OBJECT
++    Q_OBJECT
+ 			
+ public:
+-	enum { INDICATOR_ONLY=1, NO_MENU = 2, MENU_LAYOUTS_ONLY = 3, MENU_FULL=4 };
+-
+-	enum { START_MENU_ID = 100, CONFIG_MENU_ID = 130, HELP_MENU_ID = 131 };
++    enum { START_MENU_ID = 100, CONFIG_MENU_ID = 130, HELP_MENU_ID = 131 };
++    enum { INDICATOR_ONLY=1, NO_MENU = 2, MENU_LAYOUTS_ONLY = 3, MENU_FULL=4 };
++    enum { WIDGET_TRAY=0, WIDGET_LABEL=1 };
+ 
+     void initLayoutList(const QList<LayoutUnit>& layouts, const XkbRules& rule);
+     void setCurrentLayout(const LayoutUnit& layout);
+@@ -55,22 +55,22 @@
+     void setShowFlag(bool showFlag) { m_showFlag = showFlag; }
+ 	
+ signals:
+-	void menuTriggered(QAction*);
+-	void iconToggled();
++    void menuTriggered(QAction*);
++    void iconToggled();
+ 
+ protected:
+-	KxkbWidget(int controlType = MENU_FULL);
+-	virtual QMenu* contextMenu() = 0;
+-	virtual void setToolTip(const QString& tip) = 0;
+-	virtual void setPixmap(const QPixmap& pixmap) = 0;
+-	virtual void setText(const QString& text) = 0;
+-
+-private:
+-	int m_controlType;
+-	bool m_showFlag;
+-	QMap<QString, QString> m_descriptionMap;
+-	QList<QAction*> m_actions;
+-	QAction* m_configSeparator;
++    KxkbWidget(int controlType = MENU_FULL);
++    virtual QMenu* contextMenu() = 0;
++    virtual void setToolTip(const QString& tip) = 0;
++    virtual void setPixmap(const QPixmap& pixmap) = 0;
++    virtual void setText(const QString& text) = 0;
++
++private:    
++    int m_controlType;
++    bool m_showFlag;
++    QMap<QString, QString> m_descriptionMap;
++    QList<QAction*> m_actions;
++    QAction* m_configSeparator;
+ };
+ 
+ 
+@@ -79,20 +79,20 @@
+ */
+ class KxkbSysTrayIcon : public KxkbWidget
+ {
+-	Q_OBJECT
++    Q_OBJECT
+ 
+ public:
+-	KxkbSysTrayIcon(int controlType=MENU_FULL);
+-	~KxkbSysTrayIcon() { delete m_indicatorWidget; }
++    KxkbSysTrayIcon(int controlType=MENU_FULL);
++    ~KxkbSysTrayIcon() { delete m_indicatorWidget; }
+ 
+ protected:
+-	QMenu* contextMenu() { return m_indicatorWidget->contextMenu(); }
+-	void setToolTip(const QString& tip) { m_indicatorWidget->setToolTip(tip); }
+-	void setPixmap(const QPixmap& pixmap);
+-	void setText(const QString& text) { } //m_indicatorWidget->setText(text); }
++    QMenu* contextMenu() { return m_indicatorWidget->contextMenu(); }
++    void setToolTip(const QString& tip) { m_indicatorWidget->setToolTip(tip); }
++    void setPixmap(const QPixmap& pixmap);
++    void setText(const QString& /*text*/) { } //m_indicatorWidget->setText(text); }
+ 
+ protected slots:
+-	void trayActivated(QSystemTrayIcon::ActivationReason);
++    void trayActivated(QSystemTrayIcon::ActivationReason);
+ 
+ private:
+     KSystemTrayIcon* m_indicatorWidget;
+--- a/kcontrol/kxkb/x11helper.cpp
++++ b/kcontrol/kxkb/x11helper.cpp
+@@ -16,10 +16,8 @@
+  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+  */
+ 
+-#include <QtGui/QWidgetList>
+ #include <QDir>
+ 
+-
+ #include <QHash>
+ #include <QRegExp>
+ #include <QTextStream>
+@@ -293,7 +291,7 @@
+ const QString X11Helper::X11_WIN_CLASS_UNKNOWN = "<unknown>";
+ 
+ QString
+-X11Helper::getWindowClass(WId winId, Display* dpy)
++X11Helper::getWindowClass(Window winId, Display* dpy)
+ {
+   unsigned long nitems_ret, bytes_after_ret;
+   unsigned char* prop_ret;
+--- a/kcontrol/kxkb/kxkb_part.desktop
++++ b/kcontrol/kxkb/kxkb_part.desktop
+@@ -4,9 +4,10 @@
+ Name=Keyboard Layout Switcher
+ Name[be]=Змена раскладкі клавіятуры
+ Name[el]=Εναλλαγή διάταξης πληκτρολογίου
++Name[et]=Klaviatuuripaigutuse vahetaja
+ Name[ga]=Athraitheoir Leagan Amach Méarchláir
+ Name[ja]=キーボード配列切り替えツール
+-Name[km]=ឧបករណ៍​ប្ដូរ​ប្លង់​ក្ដារចុច
++Name[km]=កម្មវិធី​ប្ដូរ​ប្លង់​ក្ដារចុច
+ Name[nb]=Veksler mellom tastaturoppsett
+ Name[nds]=Tasttoornen-Wesselschalter
+ Name[nl]=Toetsenbordindeling wisselen
+--- a/kcontrol/kxkb/kxkbcore.h
++++ b/kcontrol/kxkb/kxkbcore.h
+@@ -27,17 +27,17 @@
+ #define __KXKBCORE_H__
+ 
+ 
+-
+ #include <QHash>
+ #include <QQueue>
+ 
+ #include "kxkbconfig.h"
++#include "kxkbwidget.h"
+ 
+ class XKBExtension;
+ class XkbRules;
+ class KActionCollection;
+ class LayoutMap;
+-class KxkbWidget;
++//class KxkbWidget;
+ class QAction;
+ 
+ /* This is the main Kxkb class responsible for reading options
+@@ -49,13 +49,14 @@
+     Q_OBJECT
+ 
+ public:
+-    enum { NORMAL=1, NO_INIT=2 };
++    enum { KXKB_MAIN=1, KXKB_COMPONENT=2 };
+ 
+-    KxkbCore(KxkbWidget* kxkbWidget, int mode=NORMAL);
++    KxkbCore(QWidget* parentWidget, int mode=KXKB_MAIN, int controlType=KxkbWidget::MENU_FULL, int widgetType=KxkbWidget::WIDGET_TRAY);
+     ~KxkbCore();
+ 
+     virtual int newInstance();
+     bool setLayout(int layout);
++    int getStatus() { return m_status; }
+     bool x11EventFilter ( XEvent * event );
+ 
+ // DBUS:
+@@ -66,13 +67,13 @@
+ 
+ protected slots:
+     void iconMenuTriggered(QAction*);
+-    void iconToggled();
++    void toggled();
+     void windowChanged(WId winId);
++    void desktopChanged(int desktop);
+ 
+     void slotSettingsChanged(int category);
+ 
+ protected:
+-    // Read settings, and apply them.
+     bool settingsRead();
+     void layoutApply();
+     
+@@ -80,22 +81,27 @@
+     void quit();
+ 		
+ private:
+-    KxkbConfig m_kxkbConfig;
+-
+-//     WId m_prevWinId;	// for tricky part of saving xkb group
+-    LayoutMap* m_layoutOwnerMap;
+-    
+     int m_mode;
+     int m_currentLayout;
++    int m_controlType;
++    int m_widgetType;
++    int m_status;
+ 
++    KxkbConfig m_kxkbConfig;
++    LayoutMap* m_layoutOwnerMap;
++    
+     XKBExtension *m_extension;
+     XkbRules *m_rules;
++    QWidget *m_parentWidget;
+     KxkbWidget *m_kxkbWidget;
+-    KActionCollection *m_keys;
++    KActionCollection *m_actions;
+     
+     void updateIndicator(int layout, int res);
+     void initTray();
+-    void setLayoutGroups();
++    void initKeys();
++    void initWidget();
++    void initLayoutGroups();
++    void initSwitchingPolicy();
+     int updateGroupsFromServer();
+ };
+ 
+--- a/kcontrol/kxkb/kcmlayout.h
++++ b/kcontrol/kxkb/kcmlayout.h
+@@ -20,24 +20,19 @@
+ #define __KCM_LAYOUT_H__
+ 
+ 
+-#include <kcmodule.h>
+-
+ #include <QHash>
+-
+-#include <QtGui/QListView>
++#include <kcmodule.h>
+ 
+ #include "kxkbconfig.h"
+ 
+ 
+ class QWidget;
+-class OptionListItem;
+-class Q3ListViewItem;
+ class Ui_LayoutConfigWidget;
+ class XkbRules;
+ 
+-
+ class SrcLayoutModel;
+ class DstLayoutModel;
++class XkbOptionsModel;
+ 
+ class LayoutConfig : public KCModule
+ {
+@@ -53,15 +48,20 @@
+   void initUI();
+ 
+ protected:
+-  QString createOptionString();
+-  void updateIndicator();
++    QString createOptionString();
++    void updateIndicator();
+ 
+ protected slots:
+-  void moveUp();
+-  void moveDown();
+-  void variantChanged();
++    void moveUp();
++    void moveDown();
++    void variantChanged();
++    void xkbShortcutPressed();
++    void xkbShortcut3dPressed();
++    void kdeShortcutPressed();
++    void updateShortcutsLabels();
++    void xkbOptionsChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);
++    void enableChanged();
+   void displayNameChanged(const QString& name);
+-//  void latinChanged();
+   void layoutSelChanged();
+   void loadRules();
+   void refreshRulesUI();
+@@ -77,11 +77,11 @@
+ 
+   XkbRules *m_rules;
+   KxkbConfig m_kxkbConfig;
+-  QHash<QString, OptionListItem*> m_optionGroups;
+   SrcLayoutModel* m_srcModel;
+   DstLayoutModel* m_dstModel;
++  XkbOptionsModel* m_xkbOptModel;
+ 
+-  QWidget* makeOptionsTab();
++  void makeOptionsTab();
+   void updateStickyLimit();
+   void updateAddButton();
+   void updateDisplayName();
+--- a/kcontrol/kxkb/layoutmap.h
++++ b/kcontrol/kxkb/layoutmap.h
+@@ -45,7 +45,7 @@
+ 	int getNextLayout();
+ 	int getCurrentLayout();
+ 	
+-	void setCurrentWindow(WId winId);
++	void ownerChanged();
+ 	void reset();
+ 	
+ private:
+--- a/kcontrol/kxkb/extension.h
++++ b/kcontrol/kxkb/extension.h
+@@ -21,43 +21,32 @@
+ 
+ #include <X11/Xlib.h>
+ 
++class QString;
+ 
+ class XKBExtension
+ {
+ public:
+-	XKBExtension(Display *display=NULL);
+-	~XKBExtension();
+-	bool init();
+-	void reset();
+-
+-	static bool setXkbOptions(const QString& options, bool resetOldOptions);
+-	bool setLayout(const QString& model,
+-					const QString& layout, const QString& variant,
+-					const QString& includeGroup, bool useCompiledLayouts=true);
+-	bool setLayoutGroups(const QString& layouts, const QString& variants);
+-	bool setGroup(unsigned int group);
+-	unsigned int getGroup() const;
++    XKBExtension(Display *display=NULL);
++    ~XKBExtension();
++    bool init();
++
++    static bool setXkbOptions(const QString& options, bool resetOldOptions);
++    bool setLayoutGroups(const QString& layouts, const QString& variants);
++    bool setGroup(unsigned int group);
++    unsigned int getGroup() const;
+ 
+-	static bool isGroupSwitchEvent(XEvent* event);
+-	static bool isLayoutSwitchEvent(XEvent* event);	
++    static bool isGroupSwitchEvent(XEvent* event);
++    static bool isLayoutSwitchEvent(XEvent* event);	
+ 
+-	bool isXkbEvent(XEvent* event) { return event->type == xkb_opcode; }
++    bool isXkbEvent(XEvent* event) { return event->type == xkb_opcode; }
+ 
+ private:
+     int xkb_opcode;
+ 
+     Display *m_dpy;
+-/*	QString m_tempDir;
+-	static QMap<QString, FILE*> fileCache;*/
+-	
+-	bool setLayoutInternal(const QString& model,
++    bool setLayoutInternal(const QString& model,
+ 				   const QString& layout, const QString& variant,
+ 				   const QString& includeGroup);
+-// 	bool compileCurrentLayout(const QString& layoutKey);
+-// 	bool setCompiledLayout(const QString& layoutKey);
+-	
+-// 	QString getPrecompiledLayoutFilename(const QString& layoutKey);
+-//	void deletePrecompiledLayouts();
+ };
+ 
+ #endif
+--- a/kcontrol/kxkb/keyboard_layout.desktop
++++ b/kcontrol/kxkb/keyboard_layout.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell keyboard_layout
++Exec=kcmshell4 keyboard_layout
+ Icon=preferences-desktop-keyboard-layout
+ Type=Service
+ ServiceTypes=KCModule
+@@ -170,7 +170,7 @@
+ Keywords[is]=Lyklaborð,inntakstæki,alþjóðlegt
+ Keywords[it]=tastiera,mappatura,internazionale
+ Keywords[ja]=キーボード,キーボードレイアウト,国際化
+-Keywords[km]=ក្ដារចុច,ប្លង់,អន្តរជាតិ
++Keywords[km]=ក្ដារចុច ប្លង់ អន្តរជាតិ
+ Keywords[ko]=키보드,레이아웃,국제
+ Keywords[lt]=Klaviatūra,Klaviatūros išdėstymas,klaviatūros maketas,tarptautinis
+ Keywords[lv]=Tastatūra,Tastatūras izkārtojums, Ievada Iekārtas
+--- a/kcontrol/kxkb/kxkbconfig.cpp
++++ b/kcontrol/kxkb/kxkbconfig.cpp
+@@ -30,6 +30,7 @@
+ #include "x11helper.h"
+ 
+ 
++static const char* OPTIONS_SEPARATOR = ",";
+ 
+ static const char* switchModes[SWITCH_POLICY_COUNT] = {
+   "Global", "Desktop", "WinClass", "Window"
+@@ -61,7 +62,8 @@
+ 
+ 	if( m_enableXkbOptions == true || loadMode == LOAD_ALL ) {
+ 		m_resetOldOptions = config.readEntry("ResetOldOptions", false);
+-		m_options = config.readEntry("Options", "");
++		QString options = config.readEntry("Options", "");
++                m_options = options.split(OPTIONS_SEPARATOR);
+ 		kDebug() << "Xkb options (enabled=" << m_enableXkbOptions << "): " << m_options;
+ 	}
+ 
+@@ -142,6 +144,7 @@
+ 
+ 	kDebug() << "Layout owner mode " << layoutOwner;
+ 
++#ifdef STICKY_SWITCHING
+ 	m_stickySwitching = config.readEntry("StickySwitching", false);
+ 	m_stickySwitchingDepth = config.readEntry("StickySwitchingDepth", "2").toInt();
+ 	if( m_stickySwitchingDepth < 2 )
+@@ -158,14 +161,18 @@
+ 			m_stickySwitchingDepth = m_layouts.count() - 1;
+ 		}
+ 	}
++#else
++        m_stickySwitching = false; //TODO: so far we can't do sticky with xkb switching...
++#endif
+ 
+ 	return true;
+ }
+ 
+-static QString addNum(QString& str, int n)
++static QString addNum(const QString& str, int n)
+ {
+-  if( str.length() >= 3 ) return str.left(2) + n;
+-  return str + n;
++    QString format("%1%2");
++    if( str.length() >= 3 ) return format.arg(str.left(2)).arg(n);
++    return format.arg(str).arg(n);
+ }
+ 
+ void KxkbConfig::updateDisplayNames()
+@@ -174,8 +181,8 @@
+ 	LayoutUnit& lu = m_layouts[i];
+ 	int cnt = 1;
+ 	for(int j=i; j<m_layouts.count(); j++) {
+-	  LayoutUnit& lu2 = m_layouts[i];
+-	  if( lu.layout == lu2.layout ) {
++	  LayoutUnit& lu2 = m_layouts[j];
++	  if( i != j && lu.layout == lu2.layout ) {
+ 		++cnt;
+ 		lu.displayName = addNum(lu.layout, 1);
+ 		lu2.displayName = addNum(lu2.layout, cnt);
+@@ -201,7 +208,7 @@
+ 	config.writeEntry("EnableXkbOptions", m_enableXkbOptions );
+ 	config.writeEntry("IndicatorOnly", m_indicatorOnly );
+ 	config.writeEntry("ResetOldOptions", m_resetOldOptions);
+-	config.writeEntry("Options", m_options );
++	config.writeEntry("Options", m_options.join(OPTIONS_SEPARATOR) );
+ 
+ 	QStringList layoutList;
+ 	QStringList includeList;
+@@ -213,11 +220,6 @@
+ 
+ 		layoutList.append( layoutUnit.toPair() );
+ 
+-// 		if( layoutUnit.includeGroup.isEmpty() == false ) {
+-// 			QString incGroupUnit = QString("%1:%2").arg(layoutUnit.toPair(), layoutUnit.includeGroup);
+-// 			includeList.append( incGroupUnit );
+-// 		}
+-
+ 		QString displayName( layoutUnit.displayName );
+ 		kDebug() << " displayName " << layoutUnit.toPair() << " : " << displayName;
+ 		if( displayName.isEmpty() == false && displayName != layoutUnit.layout ) {
+@@ -243,8 +245,10 @@
+ 
+ 	config.writeEntry("SwitchMode", switchModes[m_switchingPolicy]);
+ 
++#ifdef STICKY_SWITCHING
+ 	config.writeEntry("StickySwitching", m_stickySwitching);
+ 	config.writeEntry("StickySwitchingDepth", m_stickySwitchingDepth);
++#endif
+ 
+ 	// remove old options
+  	config.deleteEntry("Variants");
+@@ -263,7 +267,7 @@
+ 
+ 	m_enableXkbOptions = false;
+ 	m_resetOldOptions = false;
+-	m_options = "";
++	m_options.clear();
+ 
+ 	m_layouts.clear();
+ 	m_layouts.append( DEFAULT_LAYOUT_UNIT );
+--- a/kcontrol/kxkb/kxkb_part.h
++++ b/kcontrol/kxkb/kxkb_part.h
+@@ -19,18 +19,18 @@
+ #ifndef __kxkb_part_h
+ #define __kxkb_part_h
+ 
+-#include <kparts/part.h>
++#include <QWidget>
++#include <QList>
++#include <QVariant>
+ 
+-class QWidget;
+ class QString;
+ class KxkbCore;
+ 
+-class KxkbPart : public KParts::Part
++class KxkbPart : public QWidget
+ {
+   Q_OBJECT
+  public:
+-  KxkbPart( QWidget* parentWidget,
+-               QObject* parent,
++  KxkbPart( QWidget* parent,
+                const QList<QVariant>& args = QList<QVariant>() );
+   virtual ~KxkbPart() {}
+ 
+--- a/kcontrol/kxkb/rules.cpp
++++ b/kcontrol/kxkb/rules.cpp
+@@ -74,36 +74,48 @@
+ 
+ void XkbRules::loadNewRules(bool layoutsOnly)
+ {
+-	XKlavierAdaptor* xklAdaptor = XKlavierAdaptor::getInstance(QX11Info::display());
+-	xklAdaptor->loadXkbConfig(layoutsOnly);
++    XKlavierAdaptor* xklAdaptor = XKlavierAdaptor::getInstance(QX11Info::display());
++    xklAdaptor->loadXkbConfig(layoutsOnly);
+ 
+-	m_layouts = xklAdaptor->getLayouts();
+-	if( layoutsOnly == false ) {
+-	  m_models = xklAdaptor->getModels();
+-	  m_optionGroups = xklAdaptor->getOptionGroups();
+-	  m_options = xklAdaptor->getOptions();
+-	  m_varLists = xklAdaptor->getVariants();
+-	}
++    m_layouts = xklAdaptor->getLayouts();
++    if( layoutsOnly == false ) {
++	m_models = xklAdaptor->getModels();
++        m_varLists = xklAdaptor->getVariants();
++	m_optionGroups = xklAdaptor->getOptionGroups();
++	m_options = xklAdaptor->getOptions();
++	
++        QHashIterator<QString, XkbOption> it( m_options );
++        for (; it.hasNext(); ) {
++            const XkbOption& option = it.next().value();
++            option.group->options.append(option);
++        }
++    }
+ }
+ 
+ #else
+ 
+ void XkbRules::loadRules(const QString &file, bool layoutsOnly)
+ {
+-	RulesInfo* rules = X11Helper::loadRules(file, layoutsOnly);
++    RulesInfo* rules = X11Helper::loadRules(file, layoutsOnly);
+ 
+-	if (rules == NULL) {
+-		kDebug() << "Unable to load rules";
+-		return;
+-	}
+-
+-	m_layouts= rules->layouts;
+-
+-	if( layoutsOnly == false ) {
+-		m_models = rules->models;
+-		m_options = rules->options;
+-		m_optionGroups = rules->optionGroups;
+-	}
++    if (rules == NULL) {
++	kDebug() << "Unable to load rules";
++	return;
++    }
++
++    m_layouts= rules->layouts;
++
++    if( layoutsOnly == false ) {
++	m_models = rules->models;
++	m_options = rules->options;
++	m_optionGroups = rules->optionGroups;
++
++        QHashIterator<QString, XkbOption> it( m_options );
++        for (; it.hasNext(); ) {
++            const XkbOption& option = it.next().value();
++            option.group->options.append(option);
++        }
++    }
+ }
+ 
+ 
+--- a/kcontrol/kxkb/CMakeLists.txt
++++ b/kcontrol/kxkb/CMakeLists.txt
+@@ -2,7 +2,6 @@
+ add_subdirectory( kcmmisc )
+ #add_subdirectory( tests ) 
+ KDE4_NO_ENABLE_FINAL(kxkb)
+-#add_definitions (-DQT3_SUPPORT)
+ 
+ OPTION(USE_XKLAVIER "Use libxklavier to get keyboard layouts configuration" ON)
+ 
+@@ -14,21 +13,22 @@
+   macro_optional_find_package(GObject)
+ 
+   if(LIBXKLAVIER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND)
+-
+-#MESSAGE("xklav:: ${LIBXKLAVIER_DEFINITIONS}")
+-#MESSAGE("xklav:: ${LIBXKLAVIER_LIBRARIES}")
+-	SET(CMAKE_REQUIRED_DEFINITIONS ${LIBXKLAVIER_DEFINITIONS})
+-	SET(CMAKE_REQUIRED_LIBRARIES ${LIBXKLAVIER_LIBRARIES})
+-
+-	SET(XKB_SUPPORT_SRC xklavier_adaptor.cpp)
+-	SET(XKB_SUPPORT_LIB ${LIBXKLAVIER_LIBRARIES} ${GOBJECT_LIBRARIES})
+-	ADD_DEFINITIONS(-DHAVE_XKLAVIER=1 ${LIBXKLAVIER_DEFINITIONS} ${_LibGLIB2Cflags})
+-	include_directories(${GLIB2_INCLUDE_DIR})
++    #MESSAGE("xklav:: ${LIBXKLAVIER_DEFINITIONS}")
++    #MESSAGE("xklav:: ${LIBXKLAVIER_LIBRARIES}")
++    SET(CMAKE_REQUIRED_DEFINITIONS ${LIBXKLAVIER_DEFINITIONS})
++    SET(CMAKE_REQUIRED_LIBRARIES ${LIBXKLAVIER_LIBRARIES})
++
++    SET(XKB_SUPPORT_SRC xklavier_adaptor.cpp)
++    SET(XKB_SUPPORT_LIB ${LIBXKLAVIER_LIBRARIES} ${GOBJECT_LIBRARIES})
++    ADD_DEFINITIONS(-DHAVE_XKLAVIER=1 ${LIBXKLAVIER_DEFINITIONS} ${_LibGLIB2Cflags})
++    include_directories(${GLIB2_INCLUDE_DIR})
+   else(LIBXKLAVIER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND)
+-	MESSAGE ("Could not find glib, gobject or libxklavier >= 2.91 - old xkbfile code will be used to get keyboard layout configuration!")
++    MESSAGE ("Could not find glib, gobject or libxklavier >= 3.0 - old "xkbfile" code will be used to get keyboard layout configuration!")
+   endif(LIBXKLAVIER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND)
+ endif( USE_XKLAVIER STREQUAL ON )
+ 
++find_package(Plasma)
++
+ 
+ ########### common sources ############
+ 
+@@ -54,18 +54,15 @@
+ 
+ kde4_add_plugin(kcm_keyboard_layout ${kcm_keyboard_layout_PART_SRCS})
+ 
+-SET_TARGET_PROPERTIES(kcm_keyboard_layout PROPERTIES COMPILE_FLAGS "-DQT3_SUPPORT")
+-
+-target_link_libraries(kcm_keyboard_layout
+-    ${KDE4_KIO_LIBS} xkbfile ${QT_QT3SUPPORT_LIBRARY}
+-    ${XKB_SUPPORT_LIB}
++target_link_libraries(kcm_keyboard_layout ${KDE4_KIO_LIBS}
++    xkbfile ${XKB_SUPPORT_LIB}
+ )
++
+ if(X11_XTest_FOUND)
+   target_link_libraries(kcm_keyboard_layout ${X11_XTest_LIB})
+ endif(X11_XTest_FOUND)
+ 
+ install(TARGETS kcm_keyboard_layout DESTINATION ${PLUGIN_INSTALL_DIR} )
+-
+ install( FILES keyboard_layout.desktop DESTINATION  ${SERVICES_INSTALL_DIR} )
+ 
+ 
+@@ -76,52 +73,55 @@
+   kxkbapp.cpp
+   kxkbwidget.cpp
+   kxkb_adaptor.cpp
++  kxkb_part.cpp
+ )
+ 
+ kde4_add_kdeinit_executable( kxkb ${kxkb_KDEINIT_SRCS})
+ 
+-target_link_libraries(kdeinit_kxkb ${X11_X11_LIB} ${X11_Xext_LIB} ${KDE4_KDEUI_LIBS} xkbfile ${XKB_SUPPORT_LIB})
++target_link_libraries(kdeinit_kxkb ${X11_X11_LIB} ${X11_Xext_LIB} ${KDE4_KDEUI_LIBS}
++     xkbfile ${XKB_SUPPORT_LIB})
+ 
+ install(TARGETS kdeinit_kxkb  DESTINATION ${LIB_INSTALL_DIR} )
+ 
+ target_link_libraries( kxkb kdeinit_kxkb )
+ install(TARGETS kxkb DESTINATION ${BIN_INSTALL_DIR})
+-install(FILES kxkb_component.h DESTINATION ${INCLUDE_INSTALL_DIR})
++#install(FILES kxkb_component.h DESTINATION ${INCLUDE_INSTALL_DIR})
+ 
+ 
+-########### KXKB Applet ###############
++########### KXKB Plasma Applet ###############
+ 
+-if(BUILD_KICKER)
+-set(kxkb_panelapplet_PART_SRCS kxkb_applet.cpp)
++if(PLASMA_FOUND)
+ 
+-kde4_add_plugin(kxkb_panelapplet ${kxkb_panelapplet_PART_SRCS})
++    set(plasma_applet_kxkb_SRCS kxkb_applet.cpp ${kxkb_COMMON_SRCS}
++        kxkbcore.cpp
++        kxkbwidget.cpp
++    )
+ 
+-target_link_libraries(kxkb_panelapplet kworkspace kickermain kdeinit_kxkb
+-    ${KDE4_KIO_LIBS} xkbfile
+-    ${XKB_SUPPORT_LIB}
+-)
+-if(X11_XTest_FOUND)
+-  target_link_libraries(kxkb_panelapplet ${X11_XTest_LIB})
+-endif(X11_XTest_FOUND)
++    kde4_add_plugin(plasma_applet_kxkb ${plasma_applet_kxkb_SRCS})
++
++    target_link_libraries(plasma_applet_kxkb plasma
++        ${KDE4_KDEUI_LIBS} xkbfile ${XKB_SUPPORT_LIB})
++        
++    if(X11_XTest_FOUND)
++        target_link_libraries(plasma_applet_kxkb ${X11_XTest_LIB})
++    endif(X11_XTest_FOUND)
+ 
+-install(TARGETS kxkb_panelapplet  DESTINATION ${PLUGIN_INSTALL_DIR} )
++    install(TARGETS plasma_applet_kxkb  DESTINATION ${PLUGIN_INSTALL_DIR} )
++    #install(FILES plasma-applet-kxkb.desktop  DESTINATION  ${SERVICES_INSTALL_DIR})
+ 
+-install(FILES kxkb.desktop  DESTINATION  ${DATA_INSTALL_DIR}/kicker/applets)
+-endif(BUILD_KICKER)
++    ADD_DEPENDENCIES(plasma_applet_kxkb kdeinit_kxkb)
++
++endif(PLASMA_FOUND)
+ 
+ 
+ ########### KXKB KPart ###############
++# we're not using KPart for now - it's too heavy
+ #
+-#set(kxkb_part_PART_SRCS
+-#	kxkb_part.cpp
+-#	kxkbwidget.cpp
+-#	kxkbcore.cpp
+-#	${kxkb_COMMON_SRCS})
+-#
++#set(kxkb_part_PART_SRCS kxkb_part.cpp)
+ #
+ #kde4_add_plugin(kxkb_part ${kxkb_part_PART_SRCS})
+ #
+-#target_link_libraries(kxkb_part ${KDE4_KPARTS_LIBS} 
++#target_link_libraries(kxkb_part kdeinit_kxkb
+ #    ${KDE4_KIO_LIBS} xkbfile
+ #    ${XKB_SUPPORT_LIB}
+ #)
+@@ -133,9 +133,3 @@
+ #install( FILES kxkb_part.desktop DESTINATION  ${SERVICES_INSTALL_DIR} )
+ ##install( FILES kxkb_part.rc DESTINATION  ${DATA_INSTALL_DIR}/kxkb_part )
+ 
+-
+-########### install files ###############
+-
+-install( FILES keyboard_layout.desktop  DESTINATION  ${SERVICES_INSTALL_DIR} )
+-
+-kde4_install_icons( ${ICON_INSTALL_DIR}  )
+--- a/kcontrol/kxkb/kxkbapp.cpp
++++ b/kcontrol/kxkb/kxkbapp.cpp
+@@ -23,12 +23,12 @@
+ 
+     KDE Keyboard Tool. Manages XKB keyboard mappings.
+ */
+-#include <assert.h>
+ 
+ #include <kaboutdata.h>
+ #include <kcmdlineargs.h>
+ #include <klocale.h>
+ #include <kglobal.h>
++#include <kdebug.h>
+ 
+ #include "kxkb_adaptor.h"
+ 
+@@ -41,10 +41,13 @@
+ KXKBApp::KXKBApp(bool allowStyles, bool GUIenabled)
+     : KUniqueApplication(allowStyles, GUIenabled)
+ {
+-	KxkbSysTrayIcon* kxkbWidget = new KxkbSysTrayIcon();
+-	m_kxkbCore = new KxkbCore( kxkbWidget );
+-// 	kxkbWidget->show();
+-    //TODO: don't do this if kxkb does not become a daemon
++    m_kxkbCore = new KxkbCore( NULL, KxkbCore::KXKB_MAIN, KxkbWidget::MENU_FULL, KxkbWidget::WIDGET_TRAY );
++
++    if( isError() ) {
++        exit(2);        // failed XKB
++        return;
++    }
++
+     new KXKBAdaptor( this );
+ }
+ 
+@@ -55,7 +58,12 @@
+ 
+ int KXKBApp::newInstance()
+ {
+-	return m_kxkbCore->newInstance();
++    int res = m_kxkbCore->newInstance();
++    if( isError() ) {
++        exit(0);        // not using kxkb from settings
++    }
++
++    return res;
+ }
+ 
+ bool KXKBApp::settingsRead()
+@@ -93,7 +101,9 @@
+         return 0;
+ 
+     KXKBApp app;
+-    app.disableSessionManagement();
+-    app.exec();
++    if( ! app.isError() ) {
++        app.disableSessionManagement();
++        app.exec();
++    }
+     return 0;
+ }
+--- a/kcontrol/kxkb/xklavier_adaptor.h
++++ b/kcontrol/kxkb/xklavier_adaptor.h
+@@ -18,6 +18,7 @@
+ 
+ #ifndef XKLAVIER_ADAPTOR_H
+ #define XKLAVIER_ADAPTOR_H
++
+ #include <X11/Xlib.h>
+ 
+ #include <QHash>
+--- a/kcontrol/kxkb/kxkbcore.cpp
++++ b/kcontrol/kxkb/kxkbcore.cpp
+@@ -45,8 +45,6 @@
+ #include <kactioncollection.h>
+ #include <kapplication.h>
+ 
+-//#include "kxkb_adaptor.h"
+-
+ #include "x11helper.h"
+ #include "extension.h"
+ #include "rules.h"
+@@ -59,7 +57,7 @@
+ 
+ #include "kxkbcore.h"
+ 
+-#include "kxkb_component.h"
++//#include "kxkb_component.h"
+ 
+ #include "kxkbcore.moc"
+ 
+@@ -78,51 +76,79 @@
+     bool x11Event( XEvent * e) { return kxkb->x11EventFilter(e); }
+ };
+ 
+-KxkbCore::KxkbCore(KxkbWidget* kxkbWidget, int mode):
+-//     m_prevWinId(X11Helper::UNKNOWN_WINDOW_ID),
++
++KxkbCore::KxkbCore(QWidget* parent, int mode, int controlType, int widgetType):
+     m_mode(mode),
++    m_controlType(controlType),
++    m_widgetType(widgetType),
++    m_layoutOwnerMap(NULL),
+     m_rules(NULL),
+-    m_kxkbWidget(kxkbWidget)
++    m_parentWidget(parent),
++    m_kxkbWidget(NULL)
+ {
++    m_status = 0;
++
+     m_extension = new XKBExtension();
+     if( !m_extension->init() ) {
+-        kDebug() << "xkb initialization failed, exiting...";
+-        ::exit(1);
++        kError() << "xkb initialization failed, exiting...";
++	m_status = -2;
++//        emit quit();
++        return;
+     }
+ 
+-    KApplication::kApplication()->installX11EventFilter(new DummyWidget(this));
++    m_layoutOwnerMap = new LayoutMap(m_kxkbConfig);
++}
++
++
++void KxkbCore::initWidget()
++{
++    if( ! m_kxkbWidget )
++    {
++        if( m_widgetType == KxkbWidget::WIDGET_TRAY )
++            m_kxkbWidget = new KxkbSysTrayIcon();
++        else
++            m_kxkbWidget = new KxkbLabel(m_controlType, m_parentWidget);
++            
++        kDebug() << "Created kxkb widget" << m_kxkbWidget;
++        
++ 	connect(m_kxkbWidget, SIGNAL(menuTriggered(QAction*)), this, SLOT(iconMenuTriggered(QAction*)));
++	connect(m_kxkbWidget, SIGNAL(iconToggled()), this, SLOT(toggled()));
++
++        if( m_mode == KXKB_MAIN ) {
++	    KApplication::kApplication()->installX11EventFilter(new DummyWidget(this));
+     
+ #ifdef HAVE_XKLAVIER
+-    XKlavierAdaptor::getInstance(QX11Info::display())->startListening();
++	    XKlavierAdaptor::getInstance(QX11Info::display())->startListening();
+ #endif
++    
++	    initKeys();
++        }
++    }
++}
++
++void KxkbCore::initKeys()
++{
++    m_actions = new KActionCollection( this );
++        QAction* a = m_actions->addAction( I18N_NOOP("Switch keyboard layout") );
++        a->setText( i18n( I18N_NOOP( "Switch keyboard layout" ) ) );
++        qobject_cast<KAction*>( a )->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_K));
++        connect( a, SIGNAL(triggered(bool)), this, SLOT(toggled()) );
+ 
+   // TODO: keyboard bindings
+     //globalKeys = KGlobalAccel::self();
+-    //KActionCollection* actionCollection = collection;
+-    //QAction* a = 0L;
++//    m_keys* = new KActionCollection(this);
+ 
+ //	#include "kxkbbindings.cpp"
+     //keys->readSettings();
+     //keys->updateConnections();
+ 
+-    m_layoutOwnerMap = new LayoutMap(m_kxkbConfig);
+-
+ //    connect( KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
+ //             this, SLOT(slotSettingsChanged(int)) );
+-
+-    //TODO: don't do this if kxkb does not become a daemon
+-//     new KXKBAdaptor( this );
+-//	if( !m_kxkbWidget )
+-//	{
+- 		connect(m_kxkbWidget, SIGNAL(menuTriggered(QAction*)), this, SLOT(iconMenuTriggered(QAction*)));
+-		connect(m_kxkbWidget, SIGNAL(iconToggled()), this, SLOT(iconToggled()));
+-//	}
+ }
+ 
+-
+ KxkbCore::~KxkbCore()
+ {
+-    delete m_keys;
++    delete m_actions;
+     delete m_kxkbWidget;
+     delete m_rules;
+     delete m_extension;
+@@ -131,33 +157,86 @@
+ 
+ int KxkbCore::newInstance()
+ {
+-    m_extension->reset();
++    if( m_status == 0 && settingsRead() ) {
++        initWidget();
+ 
+-    if( settingsRead() )
+-		layoutApply();
++        initSwitchingPolicy();
+ 
+-    return 0;
++        m_layoutOwnerMap->reset();
++        initTray();
++
++        layoutApply();
++        return 0;
++    }
++
++    return -1;
++}
++
++void KxkbCore::slotSettingsChanged(int category)
++{
++    if ( category != KGlobalSettings::SETTINGS_SHORTCUTS)
++		return;
++
++#ifdef __GNUC__
++#warning TODO PORT ME (KGlobalAccel related)
++#endif
++
++    KGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
++//    m_keys->readSettings();
++	//TODO:
++	//keys->updateConnections();
+ }
+ 
+ bool KxkbCore::settingsRead()
+ {
+     m_kxkbConfig.load( KxkbConfig::LOAD_ACTIVE_OPTIONS );
+ 
+-    if( m_kxkbConfig.m_enableXkbOptions ) {
+-	kDebug() << "Setting XKB options " << m_kxkbConfig.m_options;
+-	if( !m_extension->setXkbOptions(m_kxkbConfig.m_options, m_kxkbConfig.m_resetOldOptions) ) {
+-            kDebug() << "Setting XKB options failed!";
+-        }
++    if( m_mode == KXKB_MAIN ) {
++	if( m_kxkbConfig.m_enableXkbOptions ) {
++            QString options = m_kxkbConfig.m_options.join(",");
++	    if( !m_extension->setXkbOptions(options, m_kxkbConfig.m_resetOldOptions) ) {
++        	kDebug() << "Setting XKB options failed!";
++	    }
++	}
+     }
+ 
+     if ( m_kxkbConfig.m_useKxkb == false ) {
+ 	kWarning() << "Kxkb is disabled, exiting...";
+-        emit quit(); //qApp->quit();
++	m_status = -1;
++//        emit quit();
+         return false;
+     }
+ 
+-// 	m_prevWinId = X11Helper::UNKNOWN_WINDOW_ID;
++    if( m_rules == NULL )
++	m_rules = new XkbRules(false);
++
++    if( m_mode == KXKB_MAIN && ! m_kxkbConfig.m_indicatorOnly ) {
++	m_currentLayout = m_kxkbConfig.getDefaultLayout();
++	initLayoutGroups();
++    }
++    else {
++	updateGroupsFromServer();
++    }
++	
++    if( m_kxkbConfig.m_layouts.count() == 1 ) {
++	if( m_kxkbConfig.m_showSingle == false ) {
++	    kWarning() << "Kxkb is disabled for single layout";
++	    m_status = -1;
++//	    emit quit();
++	    return false;
++	}
++    }
++
++//	KGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
++	//TODO:
++//	keys->readSettings();
++	//keys->updateConnections();
++
++    return true;
++}
+ 
++void KxkbCore::initSwitchingPolicy()
++{
+ 	if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_GLOBAL ) {
+ 		disconnect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(windowChanged(WId)));
+ 		disconnect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(windowChanged(WId)));
+@@ -170,50 +249,17 @@
+ 		}
+ 		
+ 		if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_DESKTOP ) {
+-		    disconnect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(windowChanged(WId)));
+-		    connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(windowChanged(WId)));
+-//		}
+-//		else {
++		    disconnect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(desktopChanged(int)));
++		    connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(desktopChanged(int)));
++		}
++		else {
+ 		    disconnect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(windowChanged(WId)));
+ 		    connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(windowChanged(WId)));
+-/*		int m_prevWinId = kWinModule->activeWindow();
+-		kDebug() << "Active window " << m_prevWinId;*/
+ 		}
+ 	}
+-
+-	m_layoutOwnerMap->reset();
+-	m_layoutOwnerMap->setCurrentWindow( X11Helper::UNKNOWN_WINDOW_ID ); //TODO
+-
+-	if( m_rules == NULL )
+-		m_rules = new XkbRules(false);
+-
+-	if( m_mode == NORMAL ) {
+-	    m_currentLayout = m_kxkbConfig.getDefaultLayout();
+-	    setLayoutGroups();
+-	}
+-	else {
+-	    updateGroupsFromServer();
+-	}
+-	
+-	if( m_kxkbConfig.m_layouts.count() == 1 ) {
+-	    if( m_kxkbConfig.m_showSingle == false ) {
+-		kWarning() << "Kxkb is disabled for single layout, exiting...";
+-		emit quit(); //qApp->quit();
+-		return false;
+-	    }
+-	}
+-
+-	initTray();
+-
+-//	KGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
+-	//TODO:
+-//	keys->readSettings();
+-	//keys->updateConnections();
+-
+-	return true;
+ }
+ 
+-void KxkbCore::setLayoutGroups()
++void KxkbCore::initLayoutGroups()
+ {
+ 	if( m_kxkbConfig.m_layouts.count() == 1 ) {
+ 		const LayoutUnit& currentLayout = m_kxkbConfig.m_layouts[0];
+@@ -247,6 +293,13 @@
+ 
+ void KxkbCore::initTray()
+ {
++    if( m_kxkbWidget == NULL ) {
++        if( m_kxkbConfig.m_layouts.count() > 1 || m_kxkbConfig.m_showSingle )
++            initWidget();
++        else
++            return;
++    }
++    
+     kDebug() << "initing tray";
+ 
+     m_kxkbWidget->setShowFlag(m_kxkbConfig.m_showFlag);
+@@ -276,15 +329,9 @@
+ // Activates the keyboard layout specified by 'layoutUnit'
+ bool KxkbCore::setLayout(int layout)
+ {
+-	bool res = false;
++    bool res = m_extension->setGroup(layout); // not checking for ret - not important
+ 
+-// 	res = m_extension->setLayout(kxkbConfig.m_model,
+-//  					layoutUnit.layout, layoutUnit.variant,
+-//  					layoutUnit.includeGroup);
+-
+-	res = m_extension->setGroup(layout); // not checking for ret - not important
+-
+-	updateIndicator(layout, res);
++    updateIndicator(layout, res);
+ 
+     return res;
+ }
+@@ -293,8 +340,7 @@
+ {
+     if( res ) {
+   	m_currentLayout = layout;
+-	int winId = KWindowSystem::activeWindow();
+- 	m_layoutOwnerMap->setCurrentWindow(winId);
++ 	m_layoutOwnerMap->ownerChanged();
+ 	m_layoutOwnerMap->setCurrentLayout(layout);
+     }
+ 
+@@ -307,23 +353,19 @@
+     }
+ }
+ 
+-void KxkbCore::iconToggled()
++void KxkbCore::toggled()
+ {
+-//    if ( reason != QSystemTrayIcon::Trigger )
+-//        return;
+-//     const LayoutUnit& layout = m_layoutOwnerMap->getNextLayout().layoutUnit;
+     int layout = m_layoutOwnerMap->getNextLayout();
+     setLayout(layout);
+ }
+ 
+ void KxkbCore::iconMenuTriggered(QAction* action)
+ {
+-	int id = action->data().toInt();
++    int id = action->data().toInt();
+ 
+     if( KxkbWidget::START_MENU_ID <= id
+         && id < KxkbWidget::START_MENU_ID + (int)m_kxkbConfig.m_layouts.count() )
+     {
+-//         const LayoutUnit& layout = kxkbConfig.m_layouts[id - KxkbWidget::START_MENU_ID];
+         int layout = id - KxkbWidget::START_MENU_ID;
+         m_layoutOwnerMap->setCurrentLayout( layout );
+         setLayout( layout );
+@@ -332,7 +374,7 @@
+     {
+         QStringList lst;
+         lst<< "keyboard_layout";
+-	QProcess::startDetached("kcmshell",lst);
++	QProcess::startDetached("kcmshell4",lst);
+     }
+     else if (id == KxkbWidget::HELP_MENU_ID)
+     {
+@@ -344,6 +386,12 @@
+     }
+ }
+ 
++void KxkbCore::desktopChanged(int desktop)
++{
++    kDebug() << "desktop changed" << desktop;
++    windowChanged(-1);
++}
++
+ // TODO: we also have to handle deleted windows
+ void KxkbCore::windowChanged(WId winId)
+ {
+@@ -357,7 +405,7 @@
+ 	if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_GLOBAL
+ 		    || winId != X11Helper::UNKNOWN_WINDOW_ID ) {
+ 
+-		m_layoutOwnerMap->setCurrentWindow(winId);
++		m_layoutOwnerMap->ownerChanged();
+ 		int layoutState = m_layoutOwnerMap->getCurrentLayout();
+ 
+ 		if( layoutState != m_currentLayout ) {
+@@ -367,17 +415,6 @@
+ }
+ 
+ 
+-void KxkbCore::slotSettingsChanged(int category)
+-{
+-    if ( category != KGlobalSettings::SETTINGS_SHORTCUTS)
+-		return;
+-
+-    KGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
+-    m_keys->readSettings();
+-	//TODO:
+-	//keys->updateConnections();
+-}
+-
+ 
+ bool KxkbCore::x11EventFilter ( XEvent * event )
+ {
+@@ -423,7 +460,6 @@
+ 	    if( lus != m_kxkbConfig.m_layouts ) {
+ 		m_kxkbConfig.setConfiguredLayouts(lus);
+ 		m_layoutOwnerMap->reset();
+-		m_layoutOwnerMap->setCurrentWindow( X11Helper::UNKNOWN_WINDOW_ID ); //TODO
+ 		initTray();
+ 	    }
+ 	    else {
+@@ -434,21 +470,9 @@
+ 	    kDebug() << "got group from server:" << group;
+ 	    updateIndicator(group, 1);
+ 	}
++#else
++	kDebug() << "updating layouts from server is not implemented w/out libxklavier";
+ #endif
+ 	
+     return 0;
+ }
+-
+-
+-extern "C" KDE_EXPORT
+-void* kxkb_create_component(int controlType, void* parentWidget)
+-{
+-    QObject* parentObj = (QObject*)parentWidget;
+-    QWidget* parent = dynamic_cast<QWidget*> (parentObj);
+-    
+-    KxkbLabel* kxkbWidget = new KxkbLabel(controlType, parent);
+-    KxkbCore* kxkbCore = new KxkbCore( kxkbWidget, 2 );	// 2 == NO_INIT
+-    kxkbCore->newInstance();
+-    //setWidget(kxkbWidget->widget());
+-    return kxkbWidget;
+-}
+--- a/kcontrol/kxkb/kcmlayout.cpp
++++ b/kcontrol/kxkb/kcmlayout.cpp
+@@ -21,9 +21,6 @@
+ #include <QTabWidget>
+ #include <QGroupBox>
+ #include <QPushButton>
+-#include <Q3ListView>
+-#include <Q3ListViewItem>
+-#include <Q3CheckListItem>
+ #include <QHeaderView>
+ #include <QCheckBox>
+ #include <QRadioButton>
+@@ -32,10 +29,11 @@
+ #include <QWidget>
+ #include <QtGui>
+ 
++#include <kicon.h>
+ #include <kshortcutsdialog.h>
++#include <kactioncollection.h>
+ #include <kglobal.h>
+ #include <kconfig.h>
+-#include <klocale.h>
+ #include <kdebug.h>
+ #include <kapplication.h>
+ #include <kiconloader.h>
+@@ -52,6 +50,9 @@
+ #include <KPluginLoader>
+ #include "kcmlayout.moc"
+ 
++#ifdef HAVE_XKLAVIER
++#include "xklavier_adaptor.h"
++#endif
+ 
+ 
+ K_PLUGIN_FACTORY(KeyboardLayoutFactory,
+@@ -72,51 +73,10 @@
+  DST_LAYOUT_COLUMN_COUNT = 5
+ };
+ 
+-static const QString DEFAULT_VARIANT_NAME("<default>");
+-
+-class OptionListItem : public Q3CheckListItem
+-{
+-	public:
+-
+-		OptionListItem(  OptionListItem *parent, const QString &text, Type tt,
+-						 const QString &optionName );
+-		OptionListItem(  Q3ListView *parent, const QString &text, Type tt,
+-						 const QString &optionName );
+-		~OptionListItem() {}
+-
+-		QString optionName() const { return m_OptionName; }
+-		OptionListItem *findChildItem(  const QString& text );
+-
+-	protected:
+-		QString m_OptionName;
+-};
+-
+-
+-OptionListItem::OptionListItem( OptionListItem *parent, const QString &text,
+-								Type tt, const QString &optionName )
+-	: Q3CheckListItem( parent, text, tt ), m_OptionName( optionName )
+-{
+-}
+-
+-OptionListItem::OptionListItem( Q3ListView *parent, const QString &text,
+-								Type tt, const QString &optionName )
+-	: Q3CheckListItem( parent, text, tt ), m_OptionName( optionName )
+-{
+-}
+-
+-OptionListItem * OptionListItem::findChildItem( const QString& optionName )
+-{
+-	OptionListItem *child = static_cast<OptionListItem *>( firstChild() );
+-
+-	while ( child )
+-	{
+-		if ( child->optionName() == optionName )
+-			break;
+-		child = static_cast<OptionListItem *>( child->nextSibling() );
+-	}
++enum { TAB_LAYOUTS=0, TAB_OPTIONS=1, TAB_XKB=2 };
++enum { BTN_XKB_ENABLE=0, BTN_XKB_INDICATOR=1, BTN_XKB_DISABLE=2 };
+ 
+-	return child;
+-}
++static const QString DEFAULT_VARIANT_NAME("<default>");
+ 
+ class SrcLayoutModel: public QAbstractTableModel {
+ public:
+@@ -191,7 +151,7 @@
+ 	: QAbstractTableModel(parent),
+ 	m_kxkbConfig(kxkbConfig)
+ 	{ setRules(rules); }
+-    int columnCount(const QModelIndex& parent) const { return DST_LAYOUT_COLUMN_COUNT; }
++    int columnCount(const QModelIndex& /*parent*/) const { return DST_LAYOUT_COLUMN_COUNT; }
+     int rowCount(const QModelIndex&) const { return m_kxkbConfig->m_layouts.count(); }
+     QVariant data(const QModelIndex& index, int role) const;
+     QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+@@ -206,17 +166,16 @@
+ 
+ QVariant DstLayoutModel::headerData(int section, Qt::Orientation orientation, int role) const
+ {
+-     if (role != Qt::DisplayRole)
+-              return QVariant();
++    if (role != Qt::DisplayRole)
++        return QVariant();
+ 	      
+-    QString colNames[] = {"", i18n("Layout Name"), i18n("Map"), i18n("Variant"), i18n("Display Name")};
++    QString colNames[] = {"", i18n("Layout Name"), i18n("Map"), i18n("Variant"), i18n("Label")};
+     if (orientation == Qt::Horizontal) {
+ 	return colNames[section];
+     }
+-              return QVariant();
++    return QVariant();
+ }
+ 
+-
+ QVariant
+ DstLayoutModel::data(const QModelIndex& index, int role) const
+ { 
+@@ -248,13 +207,137 @@
+ }
+ 
+ 
++class XkbOptionsModel: public QAbstractItemModel {
++public:
++    XkbOptionsModel(XkbRules* rules, KxkbConfig* kxkbConfig, QObject *parent)
++	: QAbstractItemModel(parent),
++	m_kxkbConfig(kxkbConfig)
++	{ setRules(rules); }
++
++    int columnCount(const QModelIndex& /*parent*/) const { return 1; }
++    int rowCount(const QModelIndex& parent) const { 
++        if( ! parent.isValid() )
++            return m_rules->optionGroups().count();
++        if( ! parent.parent().isValid() )
++            return m_rules->optionGroups().values()[parent.row()].options.count();
++        return 0; 
++    }
++    QModelIndex parent(const QModelIndex& index) const {
++        if (!index.isValid() )
++            return QModelIndex();
++//        kDebug() << index;
++        if( index.internalId() < 100 )
++            return QModelIndex();
++        return createIndex(((index.internalId() - index.row())/100) - 1, index.column());
++    }
++    QModelIndex index(int row, int column, const QModelIndex& parent) const {
++        if(!parent.isValid()) return createIndex(row, column);
++        return createIndex(row, column, (100 * (parent.row()+1)) + row);
++    }
++    Qt::ItemFlags flags ( const QModelIndex & index ) const {
++        if( ! index.isValid() )
++            return 0;
++        
++        if( !index.parent().isValid() )
++            return Qt::ItemIsEnabled;
++
++        return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
++    }
++    bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) {
++//    kDebug() << index << value;
++        int groupRow = index.parent().row();
++        if( groupRow < 0 ) return false;
++        
++        QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
++        const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
++	const XkbOption& option = xkbGroup.options[index.row()];
++
++        if( value.toInt() == Qt::Checked ) {
++                if( xkbGroup.exclusive ) {
++                // clear if exclusive (TODO: radiobutton)
++                    int idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*"));
++//                    kDebug() << "other idx to clear" << idx;
++                    if( idx >= 0 ) {
++                        for(int i=0; i<xkbGroup.options.count(); i++)
++                            if( xkbGroup.options[i].name == m_kxkbConfig->m_options[idx] ) {
++                                setData(createIndex(i, index.column(), (quint32)index.internalId()-index.row()+i), Qt::Unchecked, role);
++                                break;
++                            }
++                //    m_kxkbConfig->m_options.removeAt(idx);
++                //    idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*"));
++                    }
++                }
++            if( m_kxkbConfig->m_options.indexOf(option.name) < 0 ) {
++                m_kxkbConfig->m_options.append(option.name);
++            }
++        }
++        else {
++            m_kxkbConfig->m_options.removeAll(option.name);
++        }
++        emit dataChanged(index, index);
++        return true;
++    }
++    
++    QVariant data(const QModelIndex& index, int role) const;
++
++    void setRules(XkbRules* rules) { m_rules = rules; }
++    void reset() { QAbstractItemModel::reset(); }
++
++    void gotoGroup(const QString& group, QAbstractItemView* view) {
++        int index = m_rules->optionGroups().keys().indexOf(group);
++        kDebug() << "scrolling to group" << index << "-" << group;
++        if( index != -1 ) {
++//            view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::NoUpdate);
++            view->scrollTo(createIndex(index,0), QAbstractItemView::PositionAtTop);
++            view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::Current);
++            view->setFocus(Qt::OtherFocusReason);
++            kDebug() << "wdg:" << view->itemDelegate(createIndex(index, 0).child(0,0));
++        }
++        else
++            kDebug() << "can't scroll to group" << group;
++    }
++private:
++    XkbRules* m_rules;
++    KxkbConfig* m_kxkbConfig;
++};
++
++QVariant
++XkbOptionsModel::data(const QModelIndex& index, int role) const
++{ 
++    if (!index.isValid())
++	return QVariant();
++
++    int row = index.row();
++	
++    if (role == Qt::DisplayRole) {
++        if( ! index.parent().isValid() )
++	    return m_rules->optionGroups().values()[row].description;
++        else {
++            int groupRow = index.parent().row();
++            QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
++            const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
++	    return xkbGroup.options[row].description;
++        }
++    }
++    else if( role==Qt::CheckStateRole && index.parent().isValid() ) {
++        int groupRow = index.parent().row();
++        QString xkbGroupNm = m_rules->optionGroups().keys()[groupRow];
++        const XkbOptionGroup& xkbGroup = m_rules->optionGroups()[xkbGroupNm];
++
++        return m_kxkbConfig->m_options.indexOf(xkbGroup.options[row].name) == -1 ? Qt::Unchecked : Qt::Checked;
++    }
++    return QVariant();
++}
++
++
+ //K_PLUGIN_FACTORY_DECLARATION(KeyboardLayoutFactory)
+ 
+ LayoutConfig::LayoutConfig(QWidget *parent, const QVariantList &)
+   : KCModule(KeyboardLayoutFactory::componentData(), parent),
+     m_rules(NULL),
+     m_srcModel(NULL),
+-    m_dstModel(NULL)
++    m_dstModel(NULL),
++    m_xkbOptModel(NULL)
+ {
+     //Read rules - we _must_ read _before_ creating UIs
+     loadRules();
+@@ -265,12 +348,13 @@
+ 
+     m_srcModel = new SrcLayoutModel(m_rules, NULL);
+     m_srcModel->setHeaderData(LAYOUT_COLUMN_FLAG, Qt::Horizontal, "");
+-    m_srcModel->setHeaderData(LAYOUT_COLUMN_NAME, Qt::Horizontal, "Layout name", Qt::DisplayRole);
+-    m_srcModel->setHeaderData(LAYOUT_COLUMN_MAP, Qt::Horizontal, "Map", Qt::DisplayRole);
++    m_srcModel->setHeaderData(LAYOUT_COLUMN_NAME, Qt::Horizontal, i18n("Layout name"), Qt::DisplayRole);
++    m_srcModel->setHeaderData(LAYOUT_COLUMN_MAP, Qt::Horizontal, i18n("Map"), Qt::DisplayRole);
+ 
+     widget->srcTableView->setModel(m_srcModel);
+ //    widget->srcTableView->setSortingEnabled(true);
+     widget->srcTableView->setColumnWidth(LAYOUT_COLUMN_FLAG, 26);
++    widget->srcTableView->setColumnWidth(LAYOUT_COLUMN_MAP, 30);
+     widget->srcTableView->verticalHeader()->hide();
+     widget->srcTableView->setShowGrid(false);
+     widget->srcTableView->resizeRowsToContents();
+@@ -278,59 +362,71 @@
+     m_dstModel = new DstLayoutModel(m_rules, &m_kxkbConfig, NULL);
+     widget->dstTableView->setModel(m_dstModel);
+     widget->dstTableView->setColumnWidth(LAYOUT_COLUMN_FLAG, 26);
++    widget->dstTableView->setColumnWidth(LAYOUT_COLUMN_MAP, 30);
+     widget->dstTableView->verticalHeader()->hide();
+ 
+-
+-  connect( widget->chkEnable, SIGNAL( toggled( bool )), this, SLOT(changed()));
+-  connect( widget->chkIndicatorOnly, SIGNAL( toggled( bool )), this, SLOT(changed()));
+-  connect( widget->chkShowSingle, SIGNAL( toggled( bool )), this, SLOT(changed()));
+-  connect( widget->chkShowFlag, SIGNAL( toggled( bool )), this, SLOT(changed()));
+-  connect( widget->comboModel, SIGNAL(activated(int)), this, SLOT(changed()));
+-
+-  connect( widget->srcTableView, SIGNAL(doubleClicked(const QModelIndex & index)),
+-									this, SLOT(add()));
+-  connect( widget->btnAdd, SIGNAL(clicked()), this, SLOT(add()));
+-  connect( widget->btnRemove, SIGNAL(clicked()), this, SLOT(remove()));
++    m_xkbOptModel = new XkbOptionsModel(m_rules, &m_kxkbConfig, NULL);
++    widget->xkbOptionsTreeView->setModel(m_xkbOptModel);
++    widget->xkbOptionsTreeView->header()->hide();
++    widget->xkbOptionsTreeView->expandAll();
++
++    connect( m_xkbOptModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 
++        this, SLOT(xkbOptionsChanged(const QModelIndex &, const QModelIndex &)));
++
++    connect( widget->grpEnableKxkb, SIGNAL( clicked( int ) ), SLOT(enableChanged()));
++//    connect( widget->chkEnable, SIGNAL( toggled( bool )), this, SLOT(changed()));
++//    connect( widget->chkIndicatorOnly, SIGNAL( toggled( bool )), this, SLOT(changed()));
++    connect( widget->chkShowSingle, SIGNAL( toggled( bool )), this, SLOT(changed()));
++    connect( widget->chkShowFlag, SIGNAL( toggled( bool )), this, SLOT(changed()));
++    connect( widget->comboModel, SIGNAL(activated(int)), this, SLOT(changed()));
++
++    connect( widget->srcTableView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(add()));
++    connect( widget->btnAdd, SIGNAL(clicked()), this, SLOT(add()));
++    connect( widget->btnRemove, SIGNAL(clicked()), this, SLOT(remove()));
+ 
+ //  connect( widget->comboVariant, SIGNAL(activated(int)), this, SLOT(changed()));
+-  connect( widget->comboVariant, SIGNAL(activated(int)), this, SLOT(variantChanged()));
+-  connect( widget->dstTableView->selectionModel(), 
++    connect( widget->comboVariant, SIGNAL(activated(int)), this, SLOT(variantChanged()));
++    connect( widget->dstTableView->selectionModel(), 
+ 		SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ 		this, SLOT(layoutSelChanged()) );
+ 
+-//  connect( widget->editDisplayName, SIGNAL(textChanged(const QString&)), this, SLOT(displayNameChanged(const QString&)));
+-
+-  widget->btnUp->setIconSet(KIcon("arrow-up"));
+-//  connect( widget->btnUp, SIGNAL(clicked()), this, SLOT(changed()));
+-  connect( widget->btnUp, SIGNAL(clicked()), this, SLOT(moveUp()));
+-  widget->btnDown->setIconSet(KIcon("arrow-down"));
+-//  connect( widget->btnDown, SIGNAL(clicked()), this, SLOT(changed()));
+-  connect( widget->btnDown, SIGNAL(clicked()), this, SLOT(moveDown()));
++    connect( widget->btnXkbShortcut, SIGNAL(clicked()), this, SLOT(xkbShortcutPressed()));
++    connect( widget->btnXkbShortcut3d, SIGNAL(clicked()), this, SLOT(xkbShortcut3dPressed()));
++    connect( widget->btnKdeShortcut, SIGNAL(clicked()), this, SLOT(kdeShortcutPressed()));
+ 
+-  connect( widget->grpSwitching, SIGNAL( clicked( int ) ), SLOT(changed()));
+-
+-  connect( widget->chkEnableSticky, SIGNAL(toggled(bool)), this, SLOT(changed()));
+-  connect( widget->spinStickyDepth, SIGNAL(valueChanged(int)), this, SLOT(changed()));
++//  connect( widget->editDisplayName, SIGNAL(textChanged(const QString&)), this, SLOT(displayNameChanged(const QString&)));
+ 
++    widget->btnUp->setIcon(KIcon("arrow-up"));
++    connect( widget->btnUp, SIGNAL(clicked()), this, SLOT(moveUp()));
++    widget->btnDown->setIcon(KIcon("arrow-down"));
++    connect( widget->btnDown, SIGNAL(clicked()), this, SLOT(moveDown()));
++
++    connect( widget->grpSwitching, SIGNAL( clicked( int ) ), SLOT(changed()));
++    connect( widget->chkEnableSticky, SIGNAL(toggled(bool)), this, SLOT(changed()));
++
++#ifdef STICKY_SWITCHING
++    connect( widget->spinStickyDepth, SIGNAL(valueChanged(int)), this, SLOT(changed()));
++#else
++    widget->grpBoxStickySwitching->setVisible(false);
++#endif
+     refreshRulesUI();
+ 
+-  makeOptionsTab();
++    makeOptionsTab();
+ 
+-  load();
++    load();
+ }
+ 
+ 
+ LayoutConfig::~LayoutConfig()
+ {
+-	delete m_rules;
++    delete m_rules;
+ }
+ 
+ 
+ void LayoutConfig::load()
+ {
+-	m_kxkbConfig.load(KxkbConfig::LOAD_ALL);
+-
+-	initUI();
++    m_kxkbConfig.load(KxkbConfig::LOAD_ALL);
++    initUI();
+ }
+ 
+ void LayoutConfig::initUI()
+@@ -339,7 +435,8 @@
+ 	if( modelName.isEmpty() )
+ 		modelName = DEFAULT_MODEL;
+ 
+-	widget->comboModel->setCurrentText(i18n(modelName));
++        QString modelName_ = i18n(modelName);
++	widget->comboModel->setCurrentIndex( widget->comboModel->findText(modelName_) );
+ 
+ 	m_dstModel->reset();
+ 	widget->dstTableView->update();
+@@ -354,16 +451,16 @@
+ 	switch( m_kxkbConfig.m_switchingPolicy ) {
+ 		default:
+ 		case SWITCH_POLICY_GLOBAL:
+-			widget->grpSwitching->setButton(0);
++			widget->grpSwitching->setSelected(0);
+ 			break;
+ 		case SWITCH_POLICY_DESKTOP:
+-			widget->grpSwitching->setButton(1);
++			widget->grpSwitching->setSelected(1);
+ 			break;
+ 		case SWITCH_POLICY_WIN_CLASS:
+-			widget->grpSwitching->setButton(2);
++			widget->grpSwitching->setSelected(2);
+ 			break;
+ 		case SWITCH_POLICY_WINDOW:
+-			widget->grpSwitching->setButton(3);
++			widget->grpSwitching->setSelected(3);
+ 			break;
+ 	}
+ 
+@@ -373,35 +470,15 @@
+ 
+ 	updateStickyLimit();
+ 
+-	widget->chkEnable->setChecked( m_kxkbConfig.m_useKxkb );
++        int enableKxkb = 2;
++        if( m_kxkbConfig.m_indicatorOnly ) enableKxkb = 1;
++        if( m_kxkbConfig.m_useKxkb ) enableKxkb = 0;
++        widget->grpEnableKxkb->setSelected(enableKxkb);
++//	widget->chkEnable->setChecked( m_kxkbConfig.m_useKxkb );
+ 	widget->grpLayouts->setEnabled( m_kxkbConfig.m_useKxkb );
+ 	widget->grpOptions->setEnabled( m_kxkbConfig.m_useKxkb );
+ 
+-	// display xkb options
+-	QStringList options = m_kxkbConfig.m_options.split(',');
+-	for (QListIterator<QString> it(options); it.hasNext(); )
+-	{
+-		QString optionName = it.next();
+-		if( optionName.trimmed().isEmpty() ) {
+-			kWarning() << "skipping empty option name" ;
+-  			continue;
+-		}
+-
+-		const XkbOption& option = m_rules->options()[optionName];
+-		OptionListItem *item = m_optionGroups[ option.group->name ];
+-
+-		if (item != NULL) {
+-			OptionListItem *child = item->findChildItem( option.name );
+-
+-			if ( child )
+-				child->setState( Q3CheckListItem::On );
+-			else
+-				kDebug() << "load: Unknown option: " << optionName;
+-		}
+-		else {
+-			kDebug() << "load: Unknown option group: " << option.group->name << " of " << optionName;
+-		}
+-	}
++        updateShortcutsLabels();
+ 
+ 	updateLayoutCommand();
+ 	updateOptionsCommand();
+@@ -411,25 +488,23 @@
+ 
+ void LayoutConfig::save()
+ {
+-//	QString model = lookupLocalized(m_rules->models(), widget->comboModel->currentText());
+ 	QString model = widget->comboModel->itemData(widget->comboModel->currentIndex()).toString();
+ 	m_kxkbConfig.m_model = model;
+ 
+ 	m_kxkbConfig.m_enableXkbOptions = widget->chkEnableOptions->isChecked();
+ 	m_kxkbConfig.m_resetOldOptions = widget->checkResetOld->isChecked();
+-	m_kxkbConfig.m_options = createOptionString();
+ 
+ 	if( m_kxkbConfig.m_layouts.count() == 0 ) {
+-		m_kxkbConfig.m_layouts.append(LayoutUnit(DEFAULT_LAYOUT_UNIT));
+- 		widget->chkEnable->setChecked(false);
++	    m_kxkbConfig.m_layouts.append(LayoutUnit(DEFAULT_LAYOUT_UNIT));
++ 	    widget->grpEnableKxkb->setSelected(BTN_XKB_DISABLE);
+  	}
+ 
+-	m_kxkbConfig.m_useKxkb = widget->chkEnable->isChecked();
+-	m_kxkbConfig.m_indicatorOnly = widget->chkIndicatorOnly->isChecked();
++	m_kxkbConfig.m_useKxkb = widget->grpEnableKxkb->selected() <= BTN_XKB_INDICATOR;
++	m_kxkbConfig.m_indicatorOnly = widget->grpEnableKxkb->selected() == BTN_XKB_INDICATOR;
+ 	m_kxkbConfig.m_showSingle = widget->chkShowSingle->isChecked();
+ 	m_kxkbConfig.m_showFlag = widget->chkShowFlag->isChecked();
+ 
+-	int modeId = widget->grpSwitching->id(widget->grpSwitching->selected());
++	int modeId = widget->grpSwitching->selected();
+ 	switch( modeId ) {
+ 		default:
+ 		case 0:
+@@ -455,21 +530,94 @@
+ 	emit KCModule::changed( false );
+ }
+ 
++void LayoutConfig::xkbOptionsChanged(const QModelIndex & /*topLeft*/, const QModelIndex & /*bottomRight*/)
++{
++//    kDebug() << "chked" << topLeft << bottomRight;
++    updateOptionsCommand();
++    changed();
++//    widget->xkbOptionsTreeView->update(topLeft);
++}
++
++void LayoutConfig::xkbShortcutPressed()
++{
++    widget->tabWidget->setCurrentIndex(TAB_XKB);
++    m_xkbOptModel->gotoGroup("grp", widget->xkbOptionsTreeView);
++}
++
++void LayoutConfig::xkbShortcut3dPressed()
++{
++    widget->tabWidget->setCurrentIndex(TAB_XKB);
++    m_xkbOptModel->gotoGroup("lv3", widget->xkbOptionsTreeView);
++}
++
++void LayoutConfig::kdeShortcutPressed()
++{
++    QStringList args;
++    args << "keys";
++    int res = KToolInvocation::kdeinitExecWait( "kcmshell", args );
++    if( res )
++        updateShortcutsLabels();
++    else
++        kError() << "failed to start 'kcmshell keys'";
++}
++
++static QString getShortcutText(const QStringList& options, const QString& grp)
++{
++    if( options.indexOf(QRegExp("^" + grp + ".*")) != -1 )
++        return i18n("Defined");
++    else
++        return i18n("Not defined");
++}
++
++void LayoutConfig::updateShortcutsLabels()
++{
++    QString txt = getShortcutText( m_kxkbConfig.m_options, "grp" );
++    widget->xkbShortcut->setText(txt);
++    txt = getShortcutText( m_kxkbConfig.m_options, "lv3" );
++    widget->xkbShortcut3d->setText(txt);
++
++    KActionCollection actions(this);
++    actions.readSettings();
++    QAction* action = actions.action(I18N_NOOP("Switch to Next Keyboard Layout"));
++    if( action != NULL ) {
++        widget->kdeShortcut->setText( action->shortcut().toString(QKeySequence::NativeText) );
++    }
++    else {
++        widget->kdeShortcut->setText(i18n("Not defined"));
++    }
++}
+ 
+ void LayoutConfig::updateStickyLimit()
+ {
+     int layoutsCnt = m_kxkbConfig.m_layouts.count();
+-	int maxDepth = layoutsCnt - 1;
++    int maxDepth = layoutsCnt - 1;
+ 
+-	if( maxDepth < 2 ) {
+-		maxDepth = 2;
+-	}
++    if( maxDepth < 2 ) {
++        maxDepth = 2;
++    }
+ 
+-	widget->spinStickyDepth->setMaximum(maxDepth);
++    widget->spinStickyDepth->setMaximum(maxDepth);
+ /*	if( value > maxDepth )
+ 		setValue(maxDepth);*/
+ }
+ 
++
++void LayoutConfig::enableChanged()
++{
++    bool enabled = widget->grpEnableKxkb->selected() == 0;
++    if( enabled && m_kxkbConfig.m_layouts.count() == 0 ) {
++#ifdef HAVE_XKLAVIER
++	QList<LayoutUnit> lus = XKlavierAdaptor::getInstance(QX11Info::display())->getGroupNames();
++	if( lus.count() > 0 ) {
++	    m_kxkbConfig.setConfiguredLayouts(lus);
++            m_dstModel->reset();
++            widget->dstTableView->update();
++	}
++#endif
++    }
++    changed();
++}
++
+ void LayoutConfig::add()
+ {
+     QItemSelectionModel* selectionModel = widget->srcTableView->selectionModel();
+@@ -483,11 +631,11 @@
+     kDebug() << "selected to add" << layout;
+     m_kxkbConfig.m_layouts << LayoutUnit(layout, "");
+ 
+-	m_dstModel->reset();
+-	widget->dstTableView->update();
++    m_dstModel->reset();
++    widget->dstTableView->update();
+ 
+-	updateAddButton();
+-	updateLayoutCommand();
++    updateAddButton();
++    updateLayoutCommand();
+ 
+     updateStickyLimit();
+     changed();
+@@ -506,15 +654,16 @@
+ 	return;
+ 
+     QModelIndexList selected = selectionModel->selectedRows();
++    kDebug() << "removing" << selected;
+     m_kxkbConfig.m_layouts.removeAt(selected[0].row());
+ 
+-	m_dstModel->reset();
+-	widget->dstTableView->update();
++    m_dstModel->reset();
++    widget->dstTableView->update();
+ 
+-	layoutSelChanged();
+-	updateAddButton();
+-	updateLayoutCommand();
+-	updateStickyLimit();
++    layoutSelChanged();
++    updateAddButton();
++    updateLayoutCommand();
++    updateStickyLimit();
+ 
+     changed();
+ }
+@@ -526,6 +675,9 @@
+ 	return;
+ 
+     QModelIndexList selected = selectionModel->selectedRows();
++    if( selected.count() < 1 )
++        return;
++    
+     int row = selected[0].row();
+     int new_row = row + shift;
+     
+@@ -560,12 +712,15 @@
+ 	return;
+     }
+ 
+-	QString selectedVariant = widget->comboVariant->currentText();
+-	if( selectedVariant == DEFAULT_VARIANT_NAME )
+-		selectedVariant = "";
+-	m_kxkbConfig.m_layouts[row].variant = selectedVariant;
++    QString selectedVariant = widget->comboVariant->currentText();
++    if( selectedVariant == DEFAULT_VARIANT_NAME )
++        selectedVariant = "";
++    
++    m_kxkbConfig.m_layouts[row].variant = selectedVariant;
++    m_dstModel->reset();
++    widget->dstTableView->update();
+ 
+-	updateLayoutCommand();
++    updateLayoutCommand();
+     changed();
+ }
+ 
+@@ -596,10 +751,10 @@
+ {
+     QItemSelectionModel* selectionModel = widget->dstTableView->selectionModel();
+     if( selectionModel == NULL || !selectionModel->hasSelection() )
+-	return - 1;
++	return -1;
+ 
+     QModelIndexList selected = selectionModel->selectedRows();
+-    int row = selected[0].row();
++    int row = selected.count() > 0 ? selected[0].row() : -1;
+     return row;
+ }
+ 
+@@ -630,82 +785,22 @@
+ 
+ 		QString variant = m_kxkbConfig.m_layouts[row].variant;
+ 		if( variant != NULL && variant.isEmpty() == false ) {
+-			widget->comboVariant->setCurrentText(variant);
++                    int idx = widget->comboVariant->findText(variant);
++		    widget->comboVariant->setCurrentIndex(idx);
+ 		}
+ 		else {
+-			widget->comboVariant->setCurrentIndex(0);
++		    widget->comboVariant->setCurrentIndex(0);
+ 		}
+ 	}
+ //	updateDisplayName();
+ }
+ 
+-QWidget* LayoutConfig::makeOptionsTab()
++void LayoutConfig::makeOptionsTab()
+ {
+-  Q3ListView *listView = widget->listOptions;
+-
+-  listView->setMinimumHeight(150);
+-  listView->setSortColumn( -1 );
+-  listView->setColumnText( 0, i18n( "Options" ) );
+-  listView->clear();
+-
+-  connect(listView, SIGNAL(clicked(Q3ListViewItem *)), SLOT(changed()));
+-  connect(listView, SIGNAL(clicked(Q3ListViewItem *)), SLOT(updateOptionsCommand()));
+-
+-  connect(widget->chkEnableOptions, SIGNAL(toggled(bool)), SLOT(changed()));
+-
+-  connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(changed()));
+-  connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(updateOptionsCommand()));
+-
+-  //Create controllers for all options
+-  QHashIterator<QString, XkbOptionGroup> it( m_rules->optionGroups() );
+-  for (; it.hasNext(); )
+-  {
+-	  OptionListItem *parent;
+-	  const XkbOptionGroup& optionGroup = it.next().value();
+-
+-      if( optionGroup.exclusive ) {
+-        parent = new OptionListItem(listView, i18n( optionGroup.description ),
+-          		Q3CheckListItem::RadioButtonController, optionGroup.name);
+-        OptionListItem *item = new OptionListItem(parent, i18n( "None" ),
+-          		Q3CheckListItem::RadioButton, "none");
+-        item->setState(Q3CheckListItem::On);
+-      }
+-      else {
+-        parent = new OptionListItem(listView, i18n( optionGroup.description ),
+-            Q3CheckListItem::CheckBoxController, optionGroup.name);
+-      }
+-
+-      parent->setOpen(true);
+-      m_optionGroups.insert( optionGroup.name, parent);
+-	  kDebug() << "optionGroup insert: " << optionGroup.name;
+-  }
+-
+-
+-  QHashIterator<QString, XkbOption> it2( m_rules->options() );
+-  for (; it2.hasNext(); )
+-  {
+-	  const XkbOption& option = it2.next().value();
+-
+-	  OptionListItem *parent = m_optionGroups[option.group->name];
+-	  if( parent == NULL ) {
+-		kError() << "no option group item for group: " << option.group->name
+-			   << " for option " << option.name << endl;
+-		exit(1);
+-	  }
+-
+-     if( parent->type() == Q3CheckListItem::RadioButtonController )
+-		new OptionListItem(parent, i18n( option.description ),
+-             Q3CheckListItem::RadioButton, option.name);
+-     else
+-	 	new OptionListItem(parent, i18n( option.description ),
+-            Q3CheckListItem::CheckBox, option.name);
+-
+-//	  kDebug() << "option insert: " << option.name;
+-  }
+-
+-  //scroll->setMinimumSize(450, 330);
++    connect(widget->chkEnableOptions, SIGNAL(toggled(bool)), SLOT(changed()));
+ 
+-  return listView;
++    connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(changed()));
++    connect(widget->checkResetOld, SIGNAL(toggled(bool)), SLOT(updateOptionsCommand()));
+ }
+ 
+ void LayoutConfig::updateOptionsCommand()
+@@ -714,7 +809,7 @@
+   QString options = createOptionString();
+ 
+   if( !options.isEmpty() ) {
+-    setxkbmap = "setxkbmap -option "; //-rules " + m_rule
++    setxkbmap = "setxkbmap -option ";
+     if( widget->checkResetOld->isChecked() )
+       setxkbmap += "-option ";
+     setxkbmap += options;
+@@ -750,7 +845,7 @@
+     setxkbmap += " -layout " + kbdLayouts;
+     setxkbmap += " -variant " + kbdVariants;
+ 
+-	widget->editCmdLine->setText(setxkbmap);
++    widget->editCmdLine->setText(setxkbmap);
+ }
+ 
+ /*
+@@ -788,15 +883,14 @@
+ 
+ void LayoutConfig::changed()
+ {
+-  bool enabled = widget->chkEnable->isChecked();
++  bool enabled = widget->grpEnableKxkb->selected() == BTN_XKB_ENABLE;
+ 
+-  widget->chkIndicatorOnly->setEnabled(enabled);
+-  if( ! enabled )
+-	widget->chkIndicatorOnly->setChecked(false);
++//  widget->chkIndicatorOnly->setEnabled(enabled);
++//  if( ! enabled )
++//	widget->chkIndicatorOnly->setChecked(false);
+ 
+   widget->grpLayouts->setEnabled(enabled);
+-  widget->grpSwitching->setEnabled(enabled);
+-//  widget->grpStickySwitching->setEnabled(enabled);
++  widget->tabWidget->widget(TAB_OPTIONS)->setEnabled(enabled);
+ 
+ //  bool indicatorOnly = widget->chkIndicatorOnly->isChecked();
+ //  widget->grpIndicator->setEnabled(indicatorOnly);
+@@ -807,7 +901,7 @@
+ 
+ void LayoutConfig::loadRules()
+ {
+-    // do we need this ?
++    // TODO: do we need this ?
+     // this could obly be used if rules are changed and 'Defaults' is pressed
+     delete m_rules;
+     m_rules = new XkbRules();
+@@ -815,6 +909,8 @@
+         m_srcModel->setRules(m_rules);
+     if( m_dstModel )
+ 	m_dstModel->setRules(m_rules);
++    if( m_xkbOptModel )
++	m_xkbOptModel->setRules(m_rules);
+ }
+ 
+ void LayoutConfig::refreshRulesUI()
+@@ -838,67 +934,40 @@
+ 
+ QString LayoutConfig::createOptionString()
+ {
+-  QString options;
+-  for (QHashIterator<QString, XkbOption> it(m_rules->options()); it.hasNext(); )
+-  {
+-    const XkbOption& option = it.next().value();
+-
+-      OptionListItem *item = m_optionGroups[ option.group->name ];
+-
+-      if( !item ) {
+-        kDebug() << "WARNING: skipping empty group for " << option.name
+-          << " - could not found group: " << option.group->name << endl;
+-        continue;
+-      }
+-
+-      OptionListItem *child = item->findChildItem( option.name );
+-
+-      if ( child ) {
+-        if ( child->state() == Q3CheckListItem::On ) {
+-          QString selectedName = child->optionName();
+-          if ( !selectedName.isEmpty() && selectedName != "none" ) {
+-            if (!options.isEmpty())
+-              options.append(',');
+-            options.append(selectedName);
+-          }
+-        }
+-      }
+-      else
+-        kDebug() << "Empty option button for group " << it.key();
+-  }
+-  return options;
++    QString options = m_kxkbConfig.m_options.join(",");
++    return options;
+ }
+ 
+ 
+ void LayoutConfig::defaults()
+ {
+-	loadRules();
+-	refreshRulesUI();
+-	m_kxkbConfig.setDefaults();
++    loadRules();
++    refreshRulesUI();
++    m_kxkbConfig.setDefaults();
+ 
+-	initUI();
++    initUI();
+ 
+-	emit KCModule::changed( true );
++    emit KCModule::changed( true );
+ }
+ 
+ extern "C"
+ {
+-	KDE_EXPORT void kcminit_keyboard()
+-	{
+-		KxkbConfig m_kxkbConfig;
+-		m_kxkbConfig.load(KxkbConfig::LOAD_INIT_OPTIONS);
+-
+-		if( m_kxkbConfig.m_useKxkb == true ) {
+-			KToolInvocation::startServiceByDesktopName("kxkb");
+-		}
+-		else {
+-		// Even if the layouts have been disabled we still want to set Xkb options
+-		// user can always switch them off now in the "Options" tab
+-			if( m_kxkbConfig.m_enableXkbOptions ) {
+-				if( !XKBExtension::setXkbOptions(m_kxkbConfig.m_options, m_kxkbConfig.m_resetOldOptions) ) {
+-					kDebug() << "Setting XKB options failed!";
+-				}
+-			}
++    KDE_EXPORT void kcminit_keyboard()
++    {
++	KxkbConfig m_kxkbConfig;
++	m_kxkbConfig.load(KxkbConfig::LOAD_INIT_OPTIONS);
++
++	if( m_kxkbConfig.m_useKxkb == true ) {
++	    KToolInvocation::startServiceByDesktopName("kxkb");
++	}
++	else {
++	    // Even if the layouts have been disabled we still want to set Xkb options
++	    // user can always switch them off now in the "Options" tab
++	    if( m_kxkbConfig.m_enableXkbOptions ) {
++		if( !XKBExtension::setXkbOptions(m_kxkbConfig.m_options.join(","), m_kxkbConfig.m_resetOldOptions) ) {
++		    kDebug() << "Setting XKB options failed!";
+ 		}
++	    }
+ 	}
++    }
+ }
+--- a/kcontrol/kxkb/kxkb_applet.h
++++ b/kcontrol/kxkb/kxkb_applet.h
+@@ -24,64 +24,28 @@
+ #include <QMouseEvent>
+ #include <QPixmap>
+ 
+-#include <kpanelapplet.h>
+-#include <kconfig.h>
++#include <plasma/applet.h>
+ 
+ 
+-class KxkbWidget;
++class QSizeF;
++class KxkbCore;
+ 
+-class KxkbApplet : public KPanelApplet
++class KxkbApplet : public Plasma::Applet
+ {
+   Q_OBJECT
+ public:
+-    explicit KxkbApplet(const QString& configFile, Plasma::Type t = Plasma::Normal,
+-                        int actions = 0, QWidget *parent = 0, Qt::WFlags f = 0);
++    explicit KxkbApplet(QObject *parent, const QVariantList &args);
+     ~KxkbApplet();
+     
+-    virtual int widthForHeight(int height) const;
+-    virtual int heightForWidth(int width) const;
+-    /**
+-     * Is called when the user selects "About" from the applets RMB menu.
+-     * Reimplement this function to launch a about dialog.
+-     *
+-     * Note that this is called only when your applet supports the About action.
+-     * See @ref Action and @ref KPanelApplet().
+-     **/
+-
+-//  public slots:
+-//    virtual void about();
+-    /**
+-     * Is called when the user selects "Help" from the applets RMB menu.
+-     * Reimplement this function to launch a manual or help page.
+-     *
+-     * Note that this is called only when your applet supports the Help action.
+-     * See @ref Action and @ref KPanelApplet().
+-     **/
+-//    virtual void help();
+-    /**
+-     * Is called when the user selects "Preferences" from the applets RMB menu.
+-     * Reimplement this function to launch a preferences dialog or kcontrol module.
+-     *
+-     * Note that this is called only when your applet supports the preferences action.
+-     * See @ref Action and @ref KPanelApplet().
+-     **/
+-//    virtual void preferences();
+-    
+-//protected:
+-//    void resizeEvent(QResizeEvent *);
+-//    void mousePressEvent(QMouseEvent *e);
+-
++    void paintInterface(QPainter *painter,
++                    const QStyleOptionGraphicsItem *option,
++                                    const QRect& contentsRect);
++    QSizeF contentSizeHint() const;
+ 
+ private:
+-	KxkbWidget* kxkbWidget;
+-//private:
+-//    KConfig *ksConfig;
+-//    QWidget *mainView;
+-//    KPopupMenu *mContextMenu;
+-//    KPopupFrame *mBrightnessChooserFrame;
+-//    BrightnessChooserImpl *chooser;
+-
+-//private: // Private methods
++    KxkbCore* m_kxkbCore;
+ };
+ 
++K_EXPORT_PLASMA_APPLET(kxkb, KxkbApplet)
++
+ #endif
+--- a/kcontrol/kxkb/layoutmap.cpp
++++ b/kcontrol/kxkb/layoutmap.cpp
+@@ -42,34 +42,33 @@
+ 
+ void LayoutMap::reset()
+ {
+-	clearMaps();
+-	setCurrentWindow( X11Helper::UNKNOWN_WINDOW_ID );
++    clearMaps();
++    ownerChanged();
++    m_currentWinId = X11Helper::UNKNOWN_WINDOW_ID;
+ }
+ 
+ 
+-
+-void LayoutMap::setCurrentWindow(WId winId)
++void LayoutMap::ownerChanged()
+ {
+-	m_currentWinId = winId;
++    if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_DESKTOP ) {
++	m_currentDesktop = KWindowSystem::currentDesktop();
++    }
++    else {
++	m_currentWinId = KWindowSystem::activeWindow();
+ 	if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_WIN_CLASS )
+-		m_currentWinClass = X11Helper::getWindowClass(winId, QX11Info::display());
+-	else
+-	if( m_kxkbConfig.m_switchingPolicy == SWITCH_POLICY_DESKTOP )
+-		m_currentDesktop = KWindowSystem::currentDesktop();
++	    m_currentWinClass = X11Helper::getWindowClass(m_currentWinId, QX11Info::display());
++    }
+ }
+ 
+ // private
+-//LayoutQueue& 
+ QQueue<int>& LayoutMap::getCurrentLayoutQueueInternal()
+ {
+ 	if( m_currentWinId == X11Helper::UNKNOWN_WINDOW_ID )
+ 		return m_globalLayouts;
+ 	
+ 	switch( m_kxkbConfig.m_switchingPolicy ) {
+-		case SWITCH_POLICY_WIN_CLASS: {
+-//			QString winClass = X11Helper::getWindowClass(winId, qt_xdisplay());
++		case SWITCH_POLICY_WIN_CLASS:
+ 			return m_appLayouts[ m_currentWinClass ];
+-		}
+ 		case SWITCH_POLICY_WINDOW:
+ 			return m_winLayouts[ m_currentWinId ];
+ 		case SWITCH_POLICY_DESKTOP:
+@@ -95,7 +94,6 @@
+ }
+ 
+ // private
+-//LayoutQueue& 
+ QQueue<int>& LayoutMap::getCurrentLayoutQueue()
+ {
+ 	QQueue<int>& layoutQueue = getCurrentLayoutQueueInternal();
+@@ -116,18 +114,14 @@
+ 	int layoutState = layoutQueue.dequeue();
+ 	layoutQueue.enqueue(layoutState);
+ 	
+-	kDebug() << "map: Next layout: " << layoutQueue.head() 
+-// 			<< " group: " << layoutQueue.head()->layoutUnit.defaultGroup 
+-			<< " for " << getOwner();
++	kDebug() << "map: Next layout: " << layoutQueue.head() << " for " << getOwner();
+ 	
+ 	return layoutQueue.head();
+ }
+ 
+ void LayoutMap::setCurrentLayout(int layoutUnit) {
+-	LayoutQueue& layoutQueue = getCurrentLayoutQueue(/*m_currentWinId*/);
+-	kDebug() << "map: Storing layout: " << layoutUnit 
+-// 			<< " group: " << layoutUnit.defaultGroup 
+-			<< " for " << getOwner();
++	LayoutQueue& layoutQueue = getCurrentLayoutQueue();
++	kDebug() << "map: Storing layout: " << layoutUnit << " for " << getOwner();
+ 	
+ 	int queueSize = (int)layoutQueue.count();
+ 	for(int ii=0; ii<queueSize; ii++) {
+--- a/kcontrol/kxkb/extension.cpp
++++ b/kcontrol/kxkb/extension.cpp
+@@ -20,8 +20,6 @@
+ #include <errno.h>
+ 
+ 
+-#include <QMap>
+-#include <QFile>
+ #include <QX11Info>
+ 
+ #include <kdebug.h>
+@@ -33,35 +31,15 @@
+ #include <X11/Xlib.h>
+ #include <X11/XKBlib.h>
+ #include <X11/extensions/XKBfile.h>
+-//#include <X11/extensions/XKBgeom.h>
+-#include <X11/extensions/XKM.h>
+ 
+ #include "extension.h"
+ 
+ 
+-// QMap<QString, FILE*> XKBExtension::fileCache;	//TODO: move to class?
+-
+-
+-static QString getLayoutKey(const QString& layout, const QString& variant)
+-{
+-	return layout + '.' + variant;
+-}
+-
+-// QString XKBExtension::getPrecompiledLayoutFilename(const QString& layoutKey)
+-// {
+-// 	QString compiledLayoutFileName = m_tempDir + layoutKey + ".xkm";
+-// 	return compiledLayoutFileName;
+-// }
+-
+ XKBExtension::XKBExtension(Display *d)
+ {
+-	if ( d == NULL )
+-		d = QX11Info::display();
+-	m_dpy = d;
+-	
+-//	QStringList dirs = KGlobal::dirs()->findDirs ( "tmp", "" );
+-//	m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
+-// 	m_tempDir = KStandardDirs::locateLocal("tmp", "");
++    if ( d == NULL )
++        d = QX11Info::display();
++    m_dpy = d;
+ }
+ 
+ bool XKBExtension::init()
+@@ -94,34 +72,24 @@
+     // Do it, or face horrible memory corrupting bugs
+     ::XkbInitAtoms(NULL);
+ 
+-	int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask;
+-    if (!XkbSelectEvents(m_dpy, XkbUseCoreKbd, eventMask, eventMask)) {
+-	   kDebug() << "Couldn't select desired XKB events";
+-	   return false;
+-	}
++    int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask;
++    if( !XkbSelectEvents(m_dpy, XkbUseCoreKbd, eventMask, eventMask) ) {
++	kDebug() << "Couldn't select desired XKB events";
++	return false;
++    }
+ 
+-	kDebug() << "XKB inited";
++    kDebug() << "XKB inited";
+ 
+     return true;
+ }
+ 
+-void XKBExtension::reset()
+-{
+-// 	for(QMap<QString, FILE*>::ConstIterator it = fileCache.begin(); it != fileCache.end(); ++it) {
+-// 		fclose(*it);
+-// //		remove( QFile::encodeName(getPrecompiledLayoutFileName(*it)) );
+-// 	}
+-// 	fileCache.clear();
+-}
+-
+ XKBExtension::~XKBExtension()
+ {
+-/*	if( m_compiledLayoutFileNames.isEmpty() == false )
+-		deletePrecompiledLayouts();*/
+ }
+ 
+ bool XKBExtension::setXkbOptions(const QString& options, bool resetOld)
+ {
++    kDebug() << "Setting XKB options " << options;
+     if (options.isEmpty())
+         return true;
+ 
+@@ -138,22 +106,6 @@
+     return p.execute() == 0;
+ }
+ 
+-bool XKBExtension::setLayout(const QString& model,
+-		const QString& layout, const QString& variant,
+-		const QString& includeGroup, bool useCompiledLayouts)
+-{
+-	if( useCompiledLayouts == false ) {
+-		return setLayoutInternal( model, layout, variant, includeGroup );
+-	}
+-	
+-	const QString layoutKey = getLayoutKey(layout, variant);
+-	
+-	bool res = setLayoutInternal( model, layout, variant, includeGroup );
+-	kDebug() << "setRawLayout " << layoutKey << ": " << res;
+-	return res;
+-}
+-
+-
+ bool XKBExtension::setLayoutGroups(const QString& layouts, const QString& variants)
+ {
+ 	bool res = setLayoutInternal( "", layouts, variants, "" );
+@@ -169,41 +121,39 @@
+     if ( layout.isEmpty() )
+         return false;
+ 
+-	QString exe = KGlobal::dirs()->findExe("setxkbmap");
+-	if( exe.isEmpty() ) {
+-		kError() << "Can't find setxkbmap" << endl;
+-		return false;
+-	}
++    QString exe = KGlobal::dirs()->findExe("setxkbmap");
++    if( exe.isEmpty() ) {
++	kError() << "Can't find setxkbmap" << endl;
++	return false;
++    }
+ 
+     QString fullLayout = layout;
+     QString fullVariant = variant;
+-	if( includeGroup.isEmpty() == false ) {
++    if( includeGroup.isEmpty() == false ) {
+         fullLayout = includeGroup;
+         fullLayout += ',';
+         fullLayout += layout;
+ 		
+-//    fullVariant = baseVar;
+         fullVariant = ",";
+         fullVariant += variant;
+     }
+  
+     KProcess p;
+     p << exe;
+-//  p << "-rules" << rule;
+ 	if( model.isEmpty() == false )
+ 		p << "-model" << model;
+     p << "-layout" << fullLayout;
+     if( !fullVariant.isNull() && !fullVariant.isEmpty() )
+         p << "-variant" << fullVariant;
+ 
+-	kDebug() << "Ext: setting " << fullLayout << ", " << fullVariant;
++    kDebug() << "Ext: setting " << fullLayout << ", " << fullVariant;
+ 	
+     return p.execute() == 0;
+ }
+ 
+ bool XKBExtension::setGroup(unsigned int group)
+ {
+-	kDebug() << "Setting group " << group;
++//	kDebug() << "Setting group " << group;
+ 	return XkbLockGroup( m_dpy, XkbUseCoreKbd, group );
+ }
+ 
+--- a/kcontrol/kxkb/x11helper.h
++++ b/kcontrol/kxkb/x11helper.h
+@@ -19,36 +19,40 @@
+ #ifndef X11HELPER_H_
+ #define X11HELPER_H_
+ 
++#include <X11/Xlib.h>
+ #include <QHash>
+ 
++struct XkbOption;
++
+ struct XkbOptionGroup {
+-  QString name;
+-  QString description;
+-  bool exclusive;
++    QString name;
++    QString description;
++    bool exclusive;
++    QList<XkbOption> options;
+ };
+ 
+ struct XkbOption {
+-  QString name;
+-  QString description;
+-  XkbOptionGroup* group;
++    QString name;
++    QString description;
++    XkbOptionGroup* group;
+ };
+ 
+ struct RulesInfo {
+-	QHash<QString, QString> models;
+-	QHash<QString, QString> layouts;
+-	QHash<QString, XkbOption> options;
+-	QHash<QString, XkbOptionGroup> optionGroups;
++    QHash<QString, QString> models;
++    QHash<QString, QString> layouts;
++    QHash<QString, XkbOption> options;
++    QHash<QString, XkbOptionGroup> optionGroups;
+ };
+ 
+ 
+ class X11Helper
+ {
+ public:
+-	static const WId UNKNOWN_WINDOW_ID = (WId) 0;
++	static const Window UNKNOWN_WINDOW_ID = (Window) 0;
+ 	static const QString X11_WIN_CLASS_ROOT;
+ 	static const QString X11_WIN_CLASS_UNKNOWN;
+ 
+-	static QString getWindowClass(WId winId, Display* dpy);
++	static QString getWindowClass(Window winId, Display* dpy);
+ 
+ #ifndef HAVE_XKLAVIER
+ 	/**
+--- a/kcontrol/kxkb/TODO
++++ b/kcontrol/kxkb/TODO
+@@ -1,18 +1,11 @@
+-KDE4:
+- Catch events - layout change (late)
+- Applet - make icon work, check startup and conflict with kxkb
+  Modifier shortcuts - easier screen for Ctrl+Shift
++ Shortcut
+  Shortcut per layout
+- KPart
+- i18n
+-
+- general:
+-  - KAccels
+-  - libxklavier languages
+-
+-  - port deprecated Qt3 widget calls
++ Plasma Applet - make icon work, check startup and conflict with kxkb
++ Catch events - layout change (late)
++ i18n (kde + libxklavier)
++ Improve component
++ XkbOptions radiobuttons for exclusive group
+ 
+ Others:
+-- krunner_lock: finish kpart
+-
+ - prevent application/window list from growing endlessly
+--- a/kcontrol/kxkb/kxkb_part.cpp
++++ b/kcontrol/kxkb/kxkb_part.cpp
+@@ -28,13 +28,12 @@
+ K_PLUGIN_FACTORY(KxkbPartFactory, registerPlugin<KxkbPart>();)
+ K_EXPORT_PLUGIN(KxkbPartFactory("kxkb_part"))
+ 
+-KxkbPart::KxkbPart( QWidget* parentWidget,
+-               QObject* parent,
++KxkbPart::KxkbPart( QWidget* parent,
+                const QList<QVariant>& args )
+-  : KParts::Part(parent)
++    : QWidget(parent)
+ {
+-	int controlType = KxkbWidget::FULL;
+-	if( args.count() > 0 && args[0].type() == QVariant::Int ) {	//TODO: replace with string?
++	int controlType = KxkbWidget::MENU_LAYOUTS_ONLY;
++/*	if( args.count() > 0 && args[0].type() == QVariant::Int ) {	//TODO: replace with string?
+ 	    controlType = args[0].toInt();
+ 	    kDebug() << "controlType" << controlType << "(" << args[0] << ")";
+ 	    if( controlType <= 0 ) {
+@@ -42,11 +41,11 @@
+ 		return;
+ 	    }
+ 	}
+-
+-	KxkbLabel* kxkbWidget = new KxkbLabel(controlType);
+-	m_kxkbCore = new KxkbCore( kxkbWidget, 2 );	// 2 == NO_INIT
+-	m_kxkbCore->newInstance();
+-	setWidget(kxkbWidget->widget());
++*/
++	m_kxkbCore = new KxkbCore( this, KxkbCore::KXKB_COMPONENT, controlType, KxkbWidget::WIDGET_LABEL );
++	if( m_kxkbCore->newInstance() != 0 )
++            setVisible(false);
++//	setWidget(kxkbWidget->widget());
+ }
+ 
+ bool 
+--- a/kcontrol/kxkb/kxkb.desktop
++++ b/kcontrol/kxkb/kxkb.desktop
+@@ -67,5 +67,5 @@
+ Icon=keyboard
+ X-DBUS-StartupType=Unique
+ 
+-X-KDE-Library=kxkb_panelapplet
++X-KDE-Library=kdeinit_kxkb
+ X-KDE-UniqueApplet=true
+--- a/kcontrol/kxkb/kxkbconfig.h
++++ b/kcontrol/kxkb/kxkbconfig.h
+@@ -109,7 +109,7 @@
+ 	SwitchingPolicy m_switchingPolicy;
+ 	
+ 	QString m_model;
+-	QString m_options;
++	QStringList m_options;
+ 	QList<LayoutUnit> m_layouts;
+ 
+ 	KxkbConfig();
+--- a/kcontrol/style/style.desktop
++++ b/kcontrol/style/style.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell style
++Exec=kcmshell4 style
+ Icon=preferences-desktop-theme-style
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+@@ -167,7 +167,7 @@
+ Keywords[is]=stíll,stílar,þemur,þema,útlit,valmyndir,valslá,MacOS,letur,leturgerðir,leturgerð,gegnsætt,skjár,forrit, táknmyndir,takkar,mús,takki,hnappur
+ Keywords[it]=stile,stili,aspetto,widget,elemento grafico,icone,barre degli strumenti,testo,evidenziazione,applicazioni,applicazioni KDE
+ Keywords[ja]=スタイル,スタイル,外観,ウィジェット,アイコン,ツールバー,テキスト,ハイライト,アプリ,KDEアプリケーション
+-Keywords[km]=រចនាប័ទ្ម,រចនាប័ទ្ម,រូបរាង,ធាតុ​ក្រាហ្វិក,រូប​តំណាង,របារ​ឧបករណ៍,អត្ថបទ,ការ​បន្លិច,កម្មវិធី,កម្មវិធី​របស់ KDE
++Keywords[km]=រចនាប័ទ្ម រចនាប័ទ្ម រូបរាង ធាតុ​ក្រាហ្វិក រូប​តំណាង របារ​ឧបករណ៍ អត្ថបទ ការ​បន្លិច កម្មវិធី កម្មវិធី​របស់ KDE
+ Keywords[ko]=스타일,모양,위젯,아이콘,도구 모음,텍스트,강조,프로그램,KDE 프로그램
+ Keywords[lt]=style,styles,look,widget,icons,toolbars,text,highlight,apps,KDE applications, stilius,stiliai,išvaizda,valdiklis,ženkliukai,piktogramos,įrankių juostos,paryškinimas,KDE taikomosios programos
+ Keywords[mk]=style,styles,look,widget,icons,toolbars,text,highlight,apps,KDE applications,стил,стилови,изглед,икони,алатници,текст,KDE апликации
+--- a/kcontrol/style/CMakeLists.txt
++++ b/kcontrol/style/CMakeLists.txt
+@@ -12,7 +12,7 @@
+ 
+ kde4_add_plugin(kcm_style ${kcm_style_PART_SRCS})
+ 
+-target_link_libraries(kcm_style ${KDE4_KDE3SUPPORT_LIBS} ${BLITZ_LIBRARIES})
++target_link_libraries(kcm_style ${KDE4_KDEUI_LIBS} ${BLITZ_LIBRARIES})
+ 
+ install(TARGETS kcm_style  DESTINATION ${PLUGIN_INSTALL_DIR})
+ 
+--- /dev/null
++++ b/kcontrol/colors/schemes/Dark
+@@ -0,0 +1,69 @@
++[Colors:Button]
++BackgroundAlternate=0,2,0
++BackgroundNormal=0,28,1
++DecorationFocus=181,208,71
++DecorationHover=205,236,209
++ForegroundActive=90,143,33
++ForegroundInactive=90,143,33
++ForegroundLink=0,197,204
++ForegroundNegative=240,134,130
++ForegroundNeutral=130,211,160
++ForegroundNormal=163,255,161
++ForegroundPositive=130,238,35
++ForegroundVisited=156,129,202
++ 
++[Colors:Selection]
++BackgroundAlternate=52,109,57
++BackgroundNormal=64,133,70
++DecorationFocus=183,208,71
++DecorationHover=206,236,209
++ForegroundActive=168,209,162
++ForegroundInactive=168,209,162
++ForegroundLink=0,197,204
++ForegroundNegative=240,134,130
++ForegroundNeutral=130,211,160
++ForegroundNormal=255,255,255
++ForegroundPositive=130,238,35
++ForegroundVisited=195,172,244
++ 
++[Colors:Tooltip]
++BackgroundAlternate=9,72,1
++BackgroundNormal=0,56,0
++DecorationFocus=183,208,71
++DecorationHover=206,236,209
++ForegroundActive=90,143,33
++ForegroundInactive=90,143,33
++ForegroundLink=0,197,204
++ForegroundNegative=240,134,130
++ForegroundNeutral=130,211,160
++ForegroundNormal=195,231,154
++ForegroundPositive=130,238,35
++ForegroundVisited=156,129,202
++ 
++[Colors:View]
++BackgroundAlternate=51,72,0
++BackgroundNormal=28,36,1
++DecorationFocus=183,208,71
++DecorationHover=206,236,209
++ForegroundActive=90,143,33
++ForegroundInactive=90,143,33
++ForegroundLink=0,197,204
++ForegroundNegative=240,134,130
++ForegroundNeutral=130,211,160
++ForegroundNormal=194,220,121
++ForegroundPositive=130,238,35
++ForegroundVisited=156,129,202
++ 
++[Colors:Window]
++BackgroundAlternate=9,72,3
++BackgroundNormal=0,56,0
++DecorationFocus=183,208,71
++DecorationHover=206,236,209
++ForegroundActive=90,143,33
++ForegroundInactive=90,143,33
++ForegroundLink=0,197,204
++ForegroundNegative=240,134,130
++ForegroundNeutral=130,211,160
++ForegroundNormal=194,231,154
++ForegroundPositive=130,238,35
++ForegroundVisited=156,129,202
+--- /dev/null
++++ b/kcontrol/colors/schemes/BeOS
+@@ -0,0 +1,103 @@
++[$Version]
++update_info=kaccel.upd:kde3.3/r1
++
++[Colors:Button]
++BackgroundAlternate=218,221,215
++BackgroundNormal=218,221,215
++DecorationFocus=239,132,65
++DecorationHover=72,177,60
++ForegroundActive=152,154,149
++ForegroundInactive=152,154,149
++ForegroundLink=22,22,240
++ForegroundNegative=107,0,0
++ForegroundNeutral=0,90,95
++ForegroundNormal=0,0,0
++ForegroundPositive=0,95,0
++ForegroundVisited=94,79,109
++
++[Colors:Selection]
++BackgroundAlternate=60,131,208
++BackgroundNormal=168,168,168
++DecorationFocus=239,132,65
++DecorationHover=72,177,60
++ForegroundActive=177,202,232
++ForegroundInactive=177,202,232
++ForegroundLink=22,22,240
++ForegroundNegative=107,0,0
++ForegroundNeutral=0,90,95
++ForegroundNormal=0,0,0
++ForegroundPositive=0,95,0
++ForegroundVisited=94,79,109
++
++[Colors:Tooltip]
++BackgroundAlternate=255,248,209
++BackgroundNormal=255,248,209
++DecorationFocus=239,132,65
++DecorationHover=72,177,60
++ForegroundActive=232,185,149
++ForegroundInactive=232,185,149
++ForegroundLink=22,22,240
++ForegroundNegative=107,0,0
++ForegroundNeutral=0,90,95
++ForegroundNormal=0,0,0
++ForegroundPositive=0,95,0
++ForegroundVisited=94,79,109
++
++[Colors:View]
++BackgroundAlternate=241,241,239
++BackgroundNormal=255,255,255
++DecorationFocus=239,132,65
++DecorationHover=72,177,60
++ForegroundActive=152,152,152
++ForegroundInactive=152,152,152
++ForegroundLink=22,22,240
++ForegroundNegative=107,0,0
++ForegroundNeutral=0,90,95
++ForegroundNormal=0,0,0
++ForegroundPositive=0,95,0
++ForegroundVisited=94,79,109
++
++[Colors:Window]
++BackgroundAlternate=227,227,227
++BackgroundNormal=227,227,227
++DecorationFocus=239,132,65
++DecorationHover=72,177,60
++ForegroundActive=152,152,152
++ForegroundInactive=152,152,152
++ForegroundLink=22,22,240
++ForegroundNegative=107,0,0
++ForegroundNeutral=0,90,95
++ForegroundNormal=0,0,0
++ForegroundPositive=0,95,0
++ForegroundVisited=94,79,109
++
++[DirSelect Dialog]
++DirSelectDialog Size=400,450
++History Items=file://$HOME/share/pictures/Taiwan
++
++[General]
++shadeSortColumn=true
++widgetStyle=oxygen
++
++[KDE]
++EffectAnimateCombo=false
++EffectAnimateMenu=false
++EffectAnimateTooltip=false
++EffectNoTooltip=false
++InsertTearOffHandle=0
++ShowIconsOnPushButtons=false
++contrast=7
++
++[Toolbar style]
++Highlighting=true
++ToolButtonStyle=TextUnderIcon
++TransparentMoving=true
++
++[WM]
++activeBackground=255,213,0
++activeForeground=0,0,0
++inactiveBackground=237,237,237
++inactiveForeground=0,0,0
++
++[deprecated Global Shortcuts from kcontrol/keys]
++Defaults timestamp=Oct  7 200709:02:12
+--- a/kcontrol/colors/colorscm.cpp
++++ b/kcontrol/colors/colorscm.cpp
+@@ -23,16 +23,22 @@
+ #include <QtCore/QFileInfo>
+ #include <QtGui/QHeaderView>
+ #include <QtGui/QStackedWidget>
++#include <QtGui/QPainter>
++#include <QtGui/QBitmap>
+ #include <QtDBus/QtDBus>
+ 
++#include <KAboutData>
+ #include <KColorButton>
+ #include <KColorDialog>
++#include <KFileDialog>
+ #include <KGenericFactory>
+ #include <KGlobal>
+ #include <KGlobalSettings>
+-#include <KAboutData>
++#include <KInputDialog>
+ #include <KListWidget>
++#include <KMessageBox>
+ #include <KStandardDirs>
++#include <kio/netaccess.h>
+ 
+ K_PLUGIN_FACTORY( KolorFactory, registerPlugin<KColorCm>(); )
+ K_EXPORT_PLUGIN( KolorFactory("kcmcolors") )
+@@ -73,11 +79,18 @@
+     QStringList schemeFiles = KGlobal::dirs()->findAllResources("data", "color-schemes/*");
+     for (int i = 0; i < schemeFiles.size(); ++i)
+     {
+-        // TODO: add some processing to show some sample of the colorscheme in the icon 
+-        // like kde3 colors kcm had
++        // get the file name
+         QString filename = schemeFiles[i];
+         QFileInfo info(filename);
+-        schemeList->addItem(info.fileName());
++
++        // create the palettes for the preview icon
++        KSharedConfigPtr config = KSharedConfig::openConfig(filename);
++        QPalette pal = KGlobalSettings::createApplicationPalette(config);
++        QPalette wm = createWmPreviewPalette(config);
++
++        // add the entry
++        QIcon icon = createSchemePreviewIcon(pal, wm);
++        schemeList->addItem(new QListWidgetItem(icon, info.fileName()));
+     }
+ }
+ 
+@@ -85,8 +98,13 @@
+ {
+     if (schemeList->currentItem() != NULL)
+     {
+-        QString path = KGlobal::dirs()->findResource("data", 
++        QString path = KGlobal::dirs()->findResource("data",
+             "color-schemes/" + schemeList->currentItem()->text());
++
++        int permissions = QFile(path).permissions();
++        bool canWrite = (permissions & QFile::WriteUser);
++        schemeRemoveButton->setEnabled(canWrite);
++
+         KSharedConfigPtr temp = m_config;
+         m_config = KSharedConfig::openConfig(path);
+         updateColorSchemes();
+@@ -106,6 +124,115 @@
+     }
+ }
+ 
++void KColorCm::on_schemeRemoveButton_clicked()
++{
++    if (schemeList->currentItem() != NULL)
++    {
++        QString path = KGlobal::dirs()->findResource("data",
++            "color-schemes/" + schemeList->currentItem()->text());
++        KIO::NetAccess::del(path, this);
++        delete schemeList->takeItem(schemeList->currentRow());
++    }
++}
++
++void KColorCm::on_schemeImportButton_clicked()
++{
++    // get the path to the scheme to import
++    KUrl url = KFileDialog::getOpenUrl(KUrl(), QString(), this, i18n("Import Color Scheme"));
++
++    // TODO: possibly untar or uncompress it
++    // open it
++    KSharedConfigPtr temp = m_config;
++    m_config = KSharedConfig::openConfig(url.path());
++
++    // test to see if it has color scheme info
++    // read it
++    updateColorSchemes();
++    KConfigGroup group(m_config, "General");
++    shadeSortedColumn->setChecked(group.readEntry("shadeSortColumn", true) ? Qt::Checked : Qt::Unchecked);
++    KConfigGroup group2(m_config, "KDE");
++    contrastSlider->setValue(group2.readEntry("contrast").toInt());
++
++    // set m_config back to previous value
++    m_config = temp;
++    updateFromColorSchemes();
++    updateColorTable();
++
++    schemePreview->setPalette(m_config);
++    inactivePreview->setPalette(m_config, QPalette::Inactive);
++    disabledPreview->setPalette(m_config, QPalette::Disabled);
++
++    // save it
++    saveScheme(url.fileName());
++}
++
++void KColorCm::on_schemeSaveButton_clicked()
++{
++    QString previousName;
++    if (schemeList->currentItem() != NULL)
++    {
++        previousName = schemeList->currentItem()->text();
++    }
++    // prompt for the name to save as
++    bool ok;
++    QString name = KInputDialog::getText(i18n("Save Color Scheme"),
++        i18n("&Enter a name for the color scheme:"), previousName, &ok, this);
++    if (ok)
++    {
++        saveScheme(name);
++    }
++}
++
++void KColorCm::saveScheme(const QString &name)
++{
++    // check if that name is already in the list
++    QString path = KGlobal::dirs()->findResource("data",
++        "color-schemes/" + name);
++
++    QFile file(path);
++    int permissions = file.permissions();
++    bool canWrite = (permissions & QFile::WriteUser);
++    // or if we can overwrite it if it exists
++    if (path.isEmpty() || !file.exists() ||
++        (canWrite && KMessageBox::questionYesNo(this,
++        i18n("A color scheme with that name already exists.\nDo you want to overwrite it?"),
++        i18n("Save Color Scheme"),
++        KStandardGuiItem::overwrite(),
++        KStandardGuiItem::cancel())
++        == KMessageBox::Yes))
++    {
++        // go ahead and save it
++        QString newpath = KGlobal::dirs()->saveLocation("data", "color-schemes/");
++        newpath += name;
++        KSharedConfigPtr temp = m_config;
++        m_config = KSharedConfig::openConfig(newpath);
++        // then copy current colors into new config
++        updateFromColorSchemes();
++        KConfigGroup group(m_config, "General");
++        group.writeEntry("shadeSortColumn", (bool)shadeSortedColumn->checkState());
++        KConfigGroup group2(m_config, "KDE");
++        group2.writeEntry("contrast", contrastSlider->value());
++        // sync it
++        m_config->sync();
++        // set m_config back to the system one
++        m_config = temp;
++        // add it to the list if it's not in there already
++        if (path.isEmpty() || !file.exists())
++        {
++            schemeList->addItem(name);
++
++            // then select the new item
++            schemeList->setCurrentRow(schemeList->count() - 1);
++        }
++        emit changed(false);
++    }
++    else if (!canWrite && file.exists())
++    {
++        // give error message if !canWrite && file.exists()
++        KMessageBox::error(this, i18n("You do not have permission to overwrite that scheme"), i18n("Error"));
++    }
++}
++
+ void KColorCm::createColorEntry(QString text, QString key, QList<KColorButton *> &list, int index)
+ {
+     KColorButton *button = new KColorButton(this);
+@@ -126,13 +253,80 @@
+     int row = sender()->objectName().toInt();
+ 
+     QColor color;
+-    if(KColorDialog::getColor(color, this ) != QDialog::Rejected ) 
++    if(KColorDialog::getColor(color, this ) != QDialog::Rejected )
+     {
+         changeColor(row, color);
+         m_stackedWidgets[row - 9]->setCurrentIndex(0);
+     }
+ }
+ 
++QPalette KColorCm::createWmPreviewPalette(const KSharedConfigPtr &config)
++{
++    QPalette palette;
++    QColor color;
++
++    KConfigGroup group(config, "WM");
++
++    // use KGS accessors to get the defaults when none have been written to m_config
++    color = group.readEntry("activeBackground");
++    if (!color.isValid())
++        color = KGlobalSettings::activeTitleColor();
++    palette.setBrush(QPalette::Active, QPalette::Window, color);
++
++    color = group.readEntry("activeForeground");
++    if (!color.isValid())
++        color = KGlobalSettings::activeTextColor();
++    palette.setBrush(QPalette::Active, QPalette::WindowText, color);
++
++    color = group.readEntry("inactiveBackground");
++    if (!color.isValid())
++        color = KGlobalSettings::inactiveTitleColor();
++    palette.setBrush(QPalette::Inactive, QPalette::Window, color);
++
++    color = group.readEntry("inactiveForeground");
++    if (!color.isValid())
++        color = KGlobalSettings::activeTitleColor();
++    palette.setBrush(QPalette::Inactive, QPalette::WindowText, color);
++
++    return palette;
++}
++
++QPixmap KColorCm::createSchemePreviewIcon(const QPalette &pal, const QPalette &wm)
++{
++    const uchar bits1[] = { 0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b };
++    const uchar bits2[] = { 0x68, 0x34, 0x1a, 0xff, 0xff, 0xff };
++    const QSize bitsSize(24,2);
++    const QBitmap b1 = QBitmap::fromData(bitsSize, bits1);
++    const QBitmap b2 = QBitmap::fromData(bitsSize, bits2);
++
++    QPixmap pixmap(23, 16);
++    pixmap.fill(Qt::black); // ### use some color other than black for borders?
++
++    QPainter p(&pixmap);
++
++    p.fillRect( 1,  1, 7, 7, pal.brush(QPalette::Window));
++    p.fillRect( 2,  2, 5, 2, QBrush(pal.color(QPalette::WindowText), b1));
++
++    p.fillRect( 8,  1, 7, 7, pal.brush(QPalette::Button));
++    p.fillRect( 9,  2, 5, 2, QBrush(pal.color(QPalette::ButtonText), b1));
++
++    p.fillRect(15,  1, 7, 7, wm.brush(QPalette::Active, QPalette::Window));
++    p.fillRect(16,  2, 5, 2, QBrush(wm.color(QPalette::Active, QPalette::WindowText), b1));
++
++    p.fillRect( 1,  8, 7, 7, pal.brush(QPalette::Base));
++    p.fillRect( 2, 12, 5, 2, QBrush(pal.color(QPalette::Text), b2));
++
++    p.fillRect( 8,  8, 7, 7, pal.brush(QPalette::Highlight));
++    p.fillRect( 9, 12, 5, 2, QBrush(pal.color(QPalette::HighlightedText), b2));
++
++    p.fillRect(15,  8, 7, 7, wm.brush(QPalette::Inactive, QPalette::Window));
++    p.fillRect(16, 12, 5, 2, QBrush(wm.color(QPalette::Inactive, QPalette::WindowText), b2));
++
++    p.end();
++
++    return pixmap;
++}
++
+ void KColorCm::updateColorSchemes()
+ {
+     m_colorSchemes.clear();
+@@ -163,6 +357,12 @@
+         group.writeEntry("DecorationHover", m_colorSchemes[i].decoration(KColorScheme::HoverColor).color());
+     }
+ 
++    KConfigGroup WMGroup(m_config, "WM");
++    WMGroup.writeEntry("activeBackground", m_commonColorButtons[18]->color());
++    WMGroup.writeEntry("activeForeground", m_commonColorButtons[19]->color());
++    WMGroup.writeEntry("inactiveBackground", m_commonColorButtons[20]->color());
++    WMGroup.writeEntry("inactiveForeground", m_commonColorButtons[21]->color());
++
+     KConfigGroup KDEgroup(m_config, "KDE");
+     KDEgroup.writeEntry("contrast", contrastSlider->value());
+ 
+@@ -337,12 +537,16 @@
+             color = KGlobalSettings::activeTextColor();
+         }
+         m_commonColorButtons[19]->setColor(color);
++
++        // inactive window background
+         color = KConfigGroup(m_config, "WM").readEntry("inactiveBackground");
+         if (!color.isValid())
+         {
+             color = KGlobalSettings::inactiveTitleColor();
+         }
+         m_commonColorButtons[20]->setColor(color);
++
++        // inactive window foreground
+         color = KConfigGroup(m_config, "WM").readEntry("inactiveForeground");
+         if (!color.isValid())
+         {
+@@ -433,7 +637,7 @@
+                 KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNormal", newColor);
+                 break;
+             case 8:
+-                // Window Text Button
++                // Selection Inactive Text Button
+                 KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundInactive", newColor);
+                 break;
+ 
+@@ -471,11 +675,11 @@
+                 break;
+             case 13:
+                 // Negative Text Button (set all active text colors)
+-                KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNegavite", newColor);
+-                KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNegavite", newColor);
+-                KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNegavite", newColor);
+-                KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNegavite", newColor);
+-                KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNegavite", newColor);
++                KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNegative", newColor);
++                KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNegative", newColor);
++                KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNegative", newColor);
++                KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNegative", newColor);
++                KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNegative", newColor);
+                 break;
+             case 14:
+                 // Neutral Text Button (set all active text colors)
+--- a/kcontrol/colors/colorscm.h
++++ b/kcontrol/colors/colorscm.h
+@@ -73,8 +73,23 @@
+     /** slot called when the schemeList selection changes */
+     void loadScheme();
+ 
++    /** slot called when the remove button is clicked*/
++    void on_schemeRemoveButton_clicked();
++
++    /** slot called when the save button is clicked */
++    void on_schemeSaveButton_clicked();
++
++    /** slot called when the import button is clicked */
++    void on_schemeImportButton_clicked();
++
+ private:
+ 
++    /** create a color palette with the WM colors, for createSchemePreviewIcon */
++    static QPalette createWmPreviewPalette(const KSharedConfigPtr&);
++
++    /** create a preview of a color scheme */
++    static QPixmap createSchemePreviewIcon(const QPalette &pal, const QPalette &wm);
++
+     /** populate the schemeList with color schemes found on the system */
+     void populateSchemeList();
+ 
+@@ -83,21 +98,26 @@
+ 
+     /** setup the colortable with its buttons and labels */
+     void setupColorTable();
+-    
++
+     /** setup the effects page */
+     void setupEffectsPage();
+ 
+     /** helper to create color entries */
+     void createColorEntry(QString text, QString key, QList<KColorButton *> &list, int index);
+-    
++
+     /** copy color entries from color schemes into m_config */
+     void updateFromColorSchemes();
+-    
++
+     void changeColor(int row, const QColor &newColor);
+-    
++
+     /** get the groupKey for the given colorSet */
+     static QString colorSetGroupKey(int colorSet);
+-    
++
++    /** save the current scheme with the given name
++     @param name name to save the scheme as
++     */
++    void saveScheme(const QString &name);
++
+     QColor commonForeground(KColorScheme::ForegroundRole index);
+ 
+     QList<KColorButton *> m_backgroundButtons;
+--- a/kcontrol/colors/colors.desktop
++++ b/kcontrol/colors/colors.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell colors
++Exec=kcmshell4 colors
+ Icon=preferences-desktop-color
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/colors/colorsettings.ui
++++ b/kcontrol/colors/colorsettings.ui
+@@ -40,6 +40,12 @@
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
++            <property name="iconSize" >
++             <size>
++              <width>23</width>
++              <height>16</height>
++             </size>
++            </property>
+            </widget>
+           </item>
+           <item row="1" column="0" >
+@@ -51,6 +57,9 @@
+           </item>
+           <item row="1" column="1" >
+            <widget class="QPushButton" name="schemeRemoveButton" >
++            <property name="enabled" >
++             <bool>false</bool>
++            </property>
+             <property name="text" >
+              <string>Rem&amp;ove</string>
+             </property>
+@@ -360,7 +369,7 @@
+                 </item>
+                 <item row="21" column="0" >
+                  <property name="text" >
+-                  <string>InactiveWindowText</string>
++                  <string>Inactive Window Text</string>
+                  </property>
+                 </item>
+                </widget>
+--- a/kcontrol/colors/CMakeLists.txt
++++ b/kcontrol/colors/CMakeLists.txt
+@@ -5,9 +5,12 @@
+ kde4_add_ui_files(kcm_colors_PART_SRCS colorsettings.ui preview.ui)
+ 
+ kde4_add_plugin(kcm_colors ${kcm_colors_PART_SRCS})
+-target_link_libraries(kcm_colors ${KDE4_KDEUI_LIBS})
++target_link_libraries(kcm_colors ${KDE4_KFILE_LIBS} ${KDE4_KDEUI_LIBS})
+ 
+ install(TARGETS kcm_colors  DESTINATION ${PLUGIN_INSTALL_DIR})
+ install( FILES colors.desktop  DESTINATION  ${SERVICES_INSTALL_DIR} )
++#FILE(GLOB schemefiles schemes/*)
++set(schemefiles schemes/BeOS schemes/Dark)
++install( FILES ${schemefiles} DESTINATION ${DATA_INSTALL_DIR}/color-schemes )
+ 
+ kde4_install_icons( ${ICON_INSTALL_DIR}  )
+--- a/kcontrol/access/kaccess.desktop
++++ b/kcontrol/access/kaccess.desktop
+@@ -16,7 +16,7 @@
+ Name[el]=Εργαλείο προσιτότητας του KDE
+ Name[eo]=KDE-ilo por Alirebleco
+ Name[es]=Herramienta de accesibilidad de KDE
+-Name[et]=KDE hõlbustusvahend
++Name[et]=KDE hõlbustustööriist
+ Name[eu]=KDEren erabilerraztasun tresna
+ Name[fa]=ابزار دستیابی‌پذیری KDE
+ Name[fi]=KDE:n helppokäyttötoiminnot
+--- a/kcontrol/access/kaccess.cpp
++++ b/kcontrol/access/kaccess.cpp
+@@ -147,8 +147,7 @@
+     XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd, XkbAudibleBellMask, XkbAudibleBellMask);
+ 
+   // keyboard -------------------------------------------------------------
+-
+-  cg.changeGroup("Keyboard");
++  KConfigGroup keyboardGroup(_config,"Keyboard");
+ 
+   // get keyboard state
+   XkbDescPtr xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd);
+@@ -158,17 +157,17 @@
+     return;
+ 
+   // sticky keys
+-  if (cg.readEntry("StickyKeys", false))
++  if (keyboardGroup.readEntry("StickyKeys", false))
+     {
+-      if (cg.readEntry("StickyKeysLatch", true))
++      if (keyboardGroup.readEntry("StickyKeysLatch", true))
+         xkb->ctrls->ax_options |= XkbAX_LatchToLockMask;
+       else
+         xkb->ctrls->ax_options &= ~XkbAX_LatchToLockMask;
+-      if (cg.readEntry("StickyKeysAutoOff", false))
++      if (keyboardGroup.readEntry("StickyKeysAutoOff", false))
+          xkb->ctrls->ax_options |= XkbAX_TwoKeysMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_TwoKeysMask;
+-      if (cg.readEntry("StickyKeysBeep", false))
++      if (keyboardGroup.readEntry("StickyKeysBeep", false))
+          xkb->ctrls->ax_options |= XkbAX_StickyKeysFBMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_StickyKeysFBMask;
+@@ -178,22 +177,22 @@
+     xkb->ctrls->enabled_ctrls &= ~XkbStickyKeysMask;
+ 
+   // toggle keys
+-  if (cg.readEntry("ToggleKeysBeep", false))
++  if (keyboardGroup.readEntry("ToggleKeysBeep", false))
+      xkb->ctrls->ax_options |= XkbAX_IndicatorFBMask;
+   else
+      xkb->ctrls->ax_options &= ~XkbAX_IndicatorFBMask;
+ 
+   // slow keys
+-  if (cg.readEntry("SlowKeys", false)) {
+-      if (cg.readEntry("SlowKeysPressBeep", false))
++  if (keyboardGroup.readEntry("SlowKeys", false)) {
++      if (keyboardGroup.readEntry("SlowKeysPressBeep", false))
+          xkb->ctrls->ax_options |= XkbAX_SKPressFBMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_SKPressFBMask;
+-      if (cg.readEntry("SlowKeysAcceptBeep", false))
++      if (keyboardGroup.readEntry("SlowKeysAcceptBeep", false))
+          xkb->ctrls->ax_options |= XkbAX_SKAcceptFBMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_SKAcceptFBMask;
+-      if (cg.readEntry("SlowKeysRejectBeep", false))
++      if (keyboardGroup.readEntry("SlowKeysRejectBeep", false))
+          xkb->ctrls->ax_options |= XkbAX_SKRejectFBMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_SKRejectFBMask;
+@@ -201,11 +200,11 @@
+     }
+   else
+       xkb->ctrls->enabled_ctrls &= ~XkbSlowKeysMask;
+-  xkb->ctrls->slow_keys_delay = cg.readEntry("SlowKeysDelay", 500);
++  xkb->ctrls->slow_keys_delay = keyboardGroup.readEntry("SlowKeysDelay", 500);
+ 
+   // bounce keys
+-  if (cg.readEntry("BounceKeys", false)) {
+-      if (cg.readEntry("BounceKeysRejectBeep", false))
++  if (keyboardGroup.readEntry("BounceKeys", false)) {
++      if (keyboardGroup.readEntry("BounceKeysRejectBeep", false))
+          xkb->ctrls->ax_options |= XkbAX_BKRejectFBMask;
+       else
+          xkb->ctrls->ax_options &= ~XkbAX_BKRejectFBMask;
+@@ -213,19 +212,19 @@
+     }
+   else
+       xkb->ctrls->enabled_ctrls &= ~XkbBounceKeysMask;
+-  xkb->ctrls->debounce_delay = cg.readEntry("BounceKeysDelay", 500);
++  xkb->ctrls->debounce_delay = keyboardGroup.readEntry("BounceKeysDelay", 500);
+ 
+   // gestures for enabling the other features
+-  _gestures = cg.readEntry("Gestures", true);
++  _gestures = keyboardGroup.readEntry("Gestures", true);
+   if (_gestures)
+       xkb->ctrls->enabled_ctrls |= XkbAccessXKeysMask;
+   else
+       xkb->ctrls->enabled_ctrls &= ~XkbAccessXKeysMask;
+ 
+   // timeout
+-  if (cg.readEntry("AccessXTimeout", false))
++  if (keyboardGroup.readEntry("AccessXTimeout", false))
+     {
+-      xkb->ctrls->ax_timeout = cg.readEntry("AccessXTimeoutDelay", 30)*60;
++      xkb->ctrls->ax_timeout = keyboardGroup.readEntry("AccessXTimeoutDelay", 30)*60;
+       xkb->ctrls->axt_opts_mask = 0;
+       xkb->ctrls->axt_opts_values = 0;
+       xkb->ctrls->axt_ctrls_mask = XkbStickyKeysMask | XkbSlowKeysMask;
+@@ -236,39 +235,39 @@
+     xkb->ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask;
+ 
+   // gestures for enabling the other features
+-  if (cg.readEntry("AccessXBeep", true))
++  if (keyboardGroup.readEntry("AccessXBeep", true))
+      xkb->ctrls->ax_options |= XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask;
+   else
+      xkb->ctrls->ax_options &= ~(XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask);
+ 
+-  _gestureConfirmation = cg.readEntry("GestureConfirmation", true);
++  _gestureConfirmation = keyboardGroup.readEntry("GestureConfirmation", true);
+ 
+-  _kNotifyModifiers = cg.readEntry("kNotifyModifiers", false);
+-  _kNotifyAccessX = cg.readEntry("kNotifyAccessX", false);
++  _kNotifyModifiers = keyboardGroup.readEntry("kNotifyModifiers", false);
++  _kNotifyAccessX = keyboardGroup.readEntry("kNotifyAccessX", false);
+ 
+   // mouse-by-keyboard ----------------------------------------------
+ 
+-  cg.changeGroup("Mouse");
++  KConfigGroup mouseGroup(_config,"Mouse");
+ 
+-  if (cg.readEntry("MouseKeys", false))
++  if (mouseGroup.readEntry("MouseKeys", false))
+     {
+-      xkb->ctrls->mk_delay = cg.readEntry("MKDelay", 160);
++      xkb->ctrls->mk_delay = mouseGroup.readEntry("MKDelay", 160);
+ 
+       // Default for initial velocity: 200 pixels/sec
+-      int interval = cg.readEntry("MKInterval", 5);
++      int interval = mouseGroup.readEntry("MKInterval", 5);
+       xkb->ctrls->mk_interval = interval;
+ 
+       // Default time to reach maximum speed: 5000 msec
+-      xkb->ctrls->mk_time_to_max = cg.readEntry("MKTimeToMax",
++      xkb->ctrls->mk_time_to_max = mouseGroup.readEntry("MKTimeToMax",
+                                              (5000+interval/2)/interval);
+ 
+       // Default maximum speed: 1000 pixels/sec
+       //     (The old default maximum speed from KDE <= 3.4
+       //     (100000 pixels/sec) was way too fast)
+-      xkb->ctrls->mk_max_speed = cg.readEntry("MKMaxSpeed", interval);
++      xkb->ctrls->mk_max_speed = mouseGroup.readEntry("MKMaxSpeed", interval);
+ 
+-      xkb->ctrls->mk_curve = cg.readEntry("MKCurve", 0);
+-      xkb->ctrls->mk_dflt_btn = cg.readEntry("MKDefaultButton", 0);
++      xkb->ctrls->mk_curve = mouseGroup.readEntry("MKCurve", 0);
++      xkb->ctrls->mk_dflt_btn = mouseGroup.readEntry("MKDefaultButton", 0);
+ 
+       xkb->ctrls->enabled_ctrls |= XkbMouseKeysMask;
+     }
+@@ -828,13 +827,13 @@
+    else if (disabled & XkbStickyKeysMask)
+       config.writeEntry("StickyKeys", false);
+ 
+-   config.changeGroup("Mouse");
++   KConfigGroup mousegrp(KGlobal::config(),"Mouse");
+ 
+    if (enabled & XkbMouseKeysMask)
+-      config.writeEntry("MouseKeys", true);
++      mousegrp.writeEntry("MouseKeys", true);
+    else if (disabled & XkbMouseKeysMask)
+-      config.writeEntry("MouseKeys", false);
+-
++      mousegrp.writeEntry("MouseKeys", false);
++   mousegrp.sync();
+    config.sync();
+ }
+ 
+--- a/kcontrol/access/kcmaccess.desktop
++++ b/kcontrol/access/kcmaccess.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kcmaccess
++Exec=kcmshell4 kcmaccess
+ Icon=preferences-desktop-accessibility
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+--- a/kcontrol/access/kaccess.notifyrc
++++ b/kcontrol/access/kaccess.notifyrc
+@@ -8,7 +8,7 @@
+ Comment[da]=KDE Tilgængelighedsværktøj
+ Comment[el]=Εργαλείο προσιτότητας του KDE
+ Comment[eo]=KDE-ilo por Alirebleco
+-Comment[et]=KDE hõlbustusvahend
++Comment[et]=KDE hõlbustustööriist
+ Comment[eu]=KDEren erabilerraztasun tresna
+ Comment[fi]=KDE:n helppokäyttötoiminnot
+ Comment[fr]=Outil d'accessibilité de KDE
+@@ -79,6 +79,7 @@
+ Name[zh_TW]=組合鍵已啟動
+ Comment=A modifier key (e.g., Shift or Control) has changed its state and is now active
+ Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Control) άλλαξε την κατάστασή του και είναι τώρα ενεργό
++Comment[et]=Muuteklahv (nt. Shift või Ctrl) muutis oma olekut ning on nüüd aktiivne
+ Comment[ja]=修飾キー (Shift や Control) の状態が変更され、アクティブになりました
+ Comment[km]=គ្រាប់ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ ជំនួស (Control)) បាន​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ឥឡូវ​នេះ​សកម្ម
+ Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har endret status og er nå aktiv
+@@ -132,6 +133,7 @@
+ Name[zh_TW]=組合鍵已放開
+ Comment=A modifier key (e.g., Shift or Control) has changed its state and is now inactive
+ Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Control) άλλαξε την κατάστασή του και είναι τώρα ανενεργό
++Comment[et]=Muuteklahv (nt. Shift või Ctrl) muutis oma olekut ning on nüüd mitteaktiivne
+ Comment[ja]=修飾キー (Shift や Control) の状態が変更され、非アクティブになりました
+ Comment[km]=គ្រាប់​ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ បញ្ជា (Control)) បាន​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ហើយ​ឥឡូវ​នេះ​អសកម្ម
+ Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har endret status og er nå inaktiv
+@@ -184,8 +186,9 @@
+ Name[zh_TW]=組合鍵已鎖定
+ Comment=A modifier key (e.g., Shift or Control) has been locked and is now active for all of the following keypresses
+ Comment[el]=Ένα πλήκτρο τροποποιητή (π.χ., Shift ή Control) κλειδώθηκε και τώρα είναι ενεργό για όλα τα ακόλουθα πατήματα πλήκτρων
++Comment[et]=Muuteklahv (nt. Shift või Ctrl) on lukustatud ja on nüüd aktiivne kõikide järgnevate klahvivajutuste jaoks
+ Comment[ja]=修飾キー (Shift や Control) がロックされ、続くキー押下のすべてに対してアクティブになりました
+-Comment[km]=គ្រាប់​ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ បញ្ជា (Control)) ត្រូវ​បាន​ចាក់​សោ ហើយ​ឥឡូវ​នេះ​សកម្ម​សម្រាប់​ការ​ចុច​គ្រាប់​ចុច​ខាងក្រោម
++Comment[km]=គ្រាប់​ចុច​កែប្រែ (ឧ. ប្ដូរ (Shift) ឬ បញ្ជា (Control)) ត្រូវ​បាន​ចាក់​សោ ហើយ​ឥឡូវ​នេះ​សកម្ម​សម្រាប់​ការ​ចុច​គ្រាប់​ចុច​ខាង​ក្រោម
+ Comment[nb]=En valgtast (f.eks. Shift eller Ctrl) har blitt låst og er nå aktiv for alle etterfølgende tastetrykk
+ Comment[nds]=En Sünnertast (Ümschalt oder Stüern (Strg) a.B.) wöör fastsett un is nu för all nakamen Tasten aktiev
+ Comment[nl]=Een modificatietoets (bijv. Shift of Ctrl) is vergrendeld en nu actief voor alle volgende toetsaanslagen
+@@ -237,9 +240,10 @@
+ Name[zh_TW]=已啟動鎖定鍵
+ Comment=A lock key (e.g., Caps Lock or Num Lock) has changed its state and and is now active
+ Comment[el]=Ένα πλήκτρο κλειδώματος (π.χ., Caps Lock ή Num Lock) άλλαξε την κατάστασή του και είναι τώρα ενεργό
++Comment[et]=Lukustusklahv (nt. Caps Lock või Num Lock) muutis oma seisundit ning on nüüd mitteaktiivne
+ Comment[it]=Un tasto di blocco (ad es. Bloc Maiusc o Bloc Num) ha cambiato stato ed ora è attivo
+ Comment[ja]=ロックキー (Caps Lock や Num Lock) の状態が変更され、アクティブになりました
+-Comment[km]=គ្រាប់​ចុច​ចាក់​សោ (ឧ. ប្ដូរ​ជាប់ (Caps Lock) ឬ លេខ (Num Lock)) បាន​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ហើយ​ឥឡូវ​នេះ​វា​សកម្ម
++Comment[km]=គ្រាប់​ចុច​ចាក់​សោ (ឧ. ប្ដូរ​ជាប់ (Caps Lock) ឬ លេខ (Num Lock)) បាន​ផ្លាស់ប្ដូរ​​ស្ថានភាព​របស់​​វា ហើយ​ឥឡូវ​នេះ​វា​សកម្ម
+ Comment[nb]=En låsetast (f.eks. Caps Lock eller Num Lock) har endret status og er nå aktiv
+ Comment[nds]=En Fastsetttast (Tallenrast oder Grootschrievtast a.B.) hett sien Tostand ännert un is nu aktiev
+ Comment[nl]=Een vergrendeltoets (bijv. Caps Lock of Num Lock) is nu actief
+@@ -272,7 +276,7 @@
+ Name[it]=Un tasto di blocco è stato disattivato
+ Name[ja]=ロックキーが非アクティブになりました
+ Name[ka]=დაბლოკვის ღილაკი ამორთულია
+-Name[km]=គ្រាប់​ចុច​ចាក់​សោ​បាន​ត្រូវ​ធ្វើ​ឲ្យ​អសកម្ម
++Name[km]=គ្រាប់​ចុច​ចាក់​សោ​ត្រូវ​បាន​​​ធ្វើ​ឲ្យ​អសកម្ម
+ Name[lt]=Užrakto klavišas buvo išjungtas
+ Name[mk]=Некое копче за заклучување беше активирано
+ Name[nb]=En låsetast er blitt deaktivert
+@@ -291,9 +295,10 @@
+ Name[zh_TW]=已解除鎖定鍵
+ Comment=A lock key (e.g., Caps Lock or Num Lock) has changed its state and is now inactive
+ Comment[el]=Ένα πλήκτρο κλειδώματος (π.χ., Caps Lock ή Num Lock) άλλαξε την κατάστασή του και είναι τώρα ανενεργό
++Comment[et]=Lukustusklahv (nt. Caps Lock või Num Lock) muutis oma seisundit ning on nüüd mitteaktiivne
+ Comment[it]=Un tasto di blocco (ad es. Bloc Maiusc o Bloc Num) ha cambiato stato ed ora è inattivo
+ Comment[ja]=ロックキー (Caps Lock や Num Lock) の状態が変更され、非アクティブになりました
+-Comment[km]=គ្រាប់​ចុច​ចាក់​សោ (ឧ. ប្ដូរ​ជាប់ (Caps Lock) ឬ លេខ (Num Lock)) បាន​ត្រូវ​ផ្លាស់ប្ដូរ​សភាព​របស់​វា ហើយ​ឥឡូវ​នេះ​អសកម្ម
++Comment[km]=គ្រាប់​ចុច​ចាក់​សោ (ឧ. ប្ដូរ​ជាប់ (Caps Lock) ឬ លេខ (Num Lock)) បាន​ត្រូវ​ផ្លាស់ប្ដូរ​ស្ថានភាព​​របស់​​វា ហើយ​ឥឡូវ​នេះ​អសកម្ម
+ Comment[nb]=En låsetast (f.eks. Caps Lock eller Num Lock) har endret status og er nå inaktiv
+ Comment[nds]=En Fastsetttast (Tallenrast oder Grootschrievtast a.B.) hett sien Tostand ännert un is nu nich mehr aktiev
+ Comment[nl]=Een vergrendeltoers (bijv. Caps Lock of Num Lock ) is nu inactief
+@@ -324,7 +329,7 @@
+ Name[hu]=Ragadós billentyűk átkapcsolva
+ Name[is]=Slökkt eða kveikt hefur verið á klístruðum lyklum
+ Name[ja]=スティッキーキーが有効または無効になりました
+-Name[km]=គ្រាប់​ចុច​ស្អិត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Name[km]=គ្រាប់​ចុច​ស្អិត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Name[lt]=Lipnūs klavišai buvo įgalinti arba išjungti
+ Name[mk]=„Лепливи копчиња“ е овозможено или оневозможено
+ Name[nb]=Faste valgtaster er blitt slått på eller av
+@@ -355,7 +360,7 @@
+ Comment[hu]=A ragadós billentyűk használatát ki- vagy bekapcsolták
+ Comment[is]=Slökkt eða kveikt hefur verið á klístruðum lyklum
+ Comment[ja]=スティッキーキーが有効または無効になりました
+-Comment[km]=គ្រាប់​ចុច​ស្អិត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Comment[km]=គ្រាប់​ចុច​ស្អិត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Comment[lt]=Lipnūs klavišai buvo įjungti arba išjungti
+ Comment[mk]=„Лепливи копчиња“ е овозможено или оневозможено
+ Comment[nb]=Faste valgtaster er blitt slått på eller av
+@@ -392,7 +397,7 @@
+ Name[hu]=A lassú billentyűk használata átkapcsolva
+ Name[is]=Slökkt eða kveikt hefur verið á hægum lyklum
+ Name[ja]=スローキーが有効または無効になりました
+-Name[km]=គ្រាប់​ចុច​យឺត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Name[km]=គ្រាប់​ចុច​យឺត​​ត្រូវ​បាន​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Name[lt]=Lėti klavišai buvo įgalinti arba išjungti
+ Name[mk]=„Спори копчиња“ е овозможено или оневозможено
+ Name[nb]=Trege taster er blitt slått på eller av
+@@ -423,7 +428,7 @@
+ Comment[hu]=A lassú billentyűk használatát ki- vagy bekapcsolták
+ Comment[is]=Slökkt eða kveikt hefur verið á hægum lyklum
+ Comment[ja]=スローキーが有効または無効になりました
+-Comment[km]=គ្រាប់​ចុច​យឺត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Comment[km]=គ្រាប់​ចុច​យឺត​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Comment[lt]=Lėti klavišai buvo įgalinti arba išjungti
+ Comment[mk]=„Спори копчиња“ е овозможено или оневозможено
+ Comment[nb]=Trege taster er blitt slått på eller av
+@@ -459,7 +464,7 @@
+ Name[hu]=A visszaugró billentyűk átkapcsolva
+ Name[is]=Slökkt eða kveikt hefur verið á skoppandi lyklum
+ Name[ja]=バウンスキーが有効または無効になりました
+-Name[km]=គ្រាប់​ចុច​លោត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Name[km]=គ្រាប់​ចុច​លោត​​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Name[lt]=Tamprūs klavišai buvo įgalinti arba išjungti
+ Name[mk]=„Скокачки копчиња“ е овозможено или оневозможено
+ Name[nb]=Filtertaster er blitt slått på eller av
+@@ -490,7 +495,7 @@
+ Comment[hu]=A visszaugró billentyűk használatát ki- vagy bekapcsolták
+ Comment[is]=Slökkt eða kveikt hefur verið á skoppandi lyklum
+ Comment[ja]=バウンスキーが有効または無効になりました
+-Comment[km]=គ្រាប់​ចុច​លោត​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Comment[km]=គ្រាប់​ចុច​លោត​​ត្រូវបាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Comment[lt]=Tamprūs klavišai buvo įgalinti arba išjungti
+ Comment[mk]=„Скокачки копчиња“ е овозможено или оневозможено
+ Comment[nb]=Filtertaster er blitt slått på eller av
+@@ -527,7 +532,7 @@
+ Name[hu]=Az egérmozgató billentyűk átkapcsolva
+ Name[is]=Slökkt eða kveikt hefur verið á músarlyklum
+ Name[ja]=マウスキーが有効または無効になりました
+-Name[km]=គ្រាប់​ចុច​កណ្ដុរ​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Name[km]=គ្រាប់​ចុច​កណ្ដុរ​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Name[lt]=Pelės klavišai buvo įgalinti arba išjungti
+ Name[mk]=„Копчиња на глушецот“ е овозможено или оневозможено
+ Name[nb]=Musetaster er blitt slått på eller av
+@@ -560,7 +565,7 @@
+ Comment[is]=Slökkt eða kveikt hefur verið á músarlyklum
+ Comment[it]=Il mouse da tastiera è stato abilitato o disabilitato
+ Comment[ja]=マウスキーが有効または無効になりました
+-Comment[km]=គ្រាប់​ចុច​កណ្ដុរ​បាន​ត្រូវ​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
++Comment[km]=គ្រាប់​ចុច​កណ្ដុរ​ត្រូវ​បាន​​​អនុញ្ញាត ឬ​មិន​អនុញ្ញាត
+ Comment[lt]=Pelės mygtukai buvo įgalinti arba išjungti
+ Comment[mk]=„Копчиња на глушецот“ е овозможено или оневозможено
+ Comment[nb]=Musetaster er blitt slått på eller av
+--- a/kcontrol/access/kcmaccess.cpp
++++ b/kcontrol/access/kcmaccess.cpp
+@@ -408,7 +408,7 @@
+   stickyKeysBeep = new QCheckBox(i18n("Use system bell whenever a modifier gets latched, locked or unlocked"), grp);
+   hbox->addWidget(stickyKeysBeep);
+ 
+-  grp = new Q3GroupBox(i18n("Locking keys"), modifiers);
++  grp = new Q3GroupBox(i18n("Locking Keys"), modifiers);
+   grp->setColumnLayout( 0, Qt::Horizontal );
+   vbox->addWidget(grp);
+ 
+@@ -426,7 +426,7 @@
+   vvbox->addItem(hbox);
+   hbox->setSpacing(KDialog::spacingHint());
+   hbox->addStretch(1);
+-  kNotifyModifiersButton = new QPushButton("Configure system notification", grp);
++  kNotifyModifiersButton = new QPushButton("Configure System Notification...", grp);
+   kNotifyModifiersButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+   hbox->addWidget(kNotifyModifiersButton);
+ 
+@@ -601,7 +601,7 @@
+   vvbox->addItem(hbox);
+   hbox->setSpacing(KDialog::spacingHint());
+   hbox->addStretch(1);
+-  kNotifyAccessXButton = new QPushButton("Configure system notification", grp);
++  kNotifyAccessXButton = new QPushButton("Configure System Notification...", grp);
+   kNotifyAccessXButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+   hbox->addWidget(kNotifyAccessXButton);
+ 
+@@ -673,33 +673,32 @@
+ 
+   durationSlider->setValue(cg.readEntry("VisibleBellPause", 500));
+ 
++  KConfigGroup keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard");
+ 
+-  cg.changeGroup("Keyboard");
+-
+-  stickyKeys->setChecked(cg.readEntry("StickyKeys", false));
+-  stickyKeysLock->setChecked(cg.readEntry("StickyKeysLatch", true));
+-  stickyKeysAutoOff->setChecked(cg.readEntry("StickyKeysAutoOff", false));
+-  stickyKeysBeep->setChecked(cg.readEntry("StickyKeysBeep", true));
+-  toggleKeysBeep->setChecked(cg.readEntry("ToggleKeysBeep", false));
+-  kNotifyModifiers->setChecked(cg.readEntry("kNotifyModifiers", false));
+-
+-  slowKeys->setChecked(cg.readEntry("SlowKeys", false));
+-  slowKeysDelay->setValue(cg.readEntry("SlowKeysDelay", 500));
+-  slowKeysPressBeep->setChecked(cg.readEntry("SlowKeysPressBeep", true));
+-  slowKeysAcceptBeep->setChecked(cg.readEntry("SlowKeysAcceptBeep", true));
+-  slowKeysRejectBeep->setChecked(cg.readEntry("SlowKeysRejectBeep", true));
+-
+-  bounceKeys->setChecked(cg.readEntry("BounceKeys", false));
+-  bounceKeysDelay->setValue(cg.readEntry("BounceKeysDelay", 500));
+-  bounceKeysRejectBeep->setChecked(cg.readEntry("BounceKeysRejectBeep", true));
+-
+-  gestures->setChecked(cg.readEntry("Gestures", true));
+-  timeout->setChecked(cg.readEntry("AccessXTimeout", false));
+-  timeoutDelay->setValue(cg.readEntry("AccessXTimeoutDelay", 30));
+-
+-  accessxBeep->setChecked(cg.readEntry("AccessXBeep", true));
+-  gestureConfirmation->setChecked(cg.readEntry("GestureConfirmation", false));
+-  kNotifyAccessX->setChecked(cg.readEntry("kNotifyAccessX", false));
++  stickyKeys->setChecked(keyboardGroup.readEntry("StickyKeys", false));
++  stickyKeysLock->setChecked(keyboardGroup.readEntry("StickyKeysLatch", true));
++  stickyKeysAutoOff->setChecked(keyboardGroup.readEntry("StickyKeysAutoOff", false));
++  stickyKeysBeep->setChecked(keyboardGroup.readEntry("StickyKeysBeep", true));
++  toggleKeysBeep->setChecked(keyboardGroup.readEntry("ToggleKeysBeep", false));
++  kNotifyModifiers->setChecked(keyboardGroup.readEntry("kNotifyModifiers", false));
++
++  slowKeys->setChecked(keyboardGroup.readEntry("SlowKeys", false));
++  slowKeysDelay->setValue(keyboardGroup.readEntry("SlowKeysDelay", 500));
++  slowKeysPressBeep->setChecked(keyboardGroup.readEntry("SlowKeysPressBeep", true));
++  slowKeysAcceptBeep->setChecked(keyboardGroup.readEntry("SlowKeysAcceptBeep", true));
++  slowKeysRejectBeep->setChecked(keyboardGroup.readEntry("SlowKeysRejectBeep", true));
++
++  bounceKeys->setChecked(keyboardGroup.readEntry("BounceKeys", false));
++  bounceKeysDelay->setValue(keyboardGroup.readEntry("BounceKeysDelay", 500));
++  bounceKeysRejectBeep->setChecked(keyboardGroup.readEntry("BounceKeysRejectBeep", true));
++
++  gestures->setChecked(keyboardGroup.readEntry("Gestures", true));
++  timeout->setChecked(keyboardGroup.readEntry("AccessXTimeout", false));
++  timeoutDelay->setValue(keyboardGroup.readEntry("AccessXTimeoutDelay", 30));
++
++  accessxBeep->setChecked(keyboardGroup.readEntry("AccessXBeep", true));
++  gestureConfirmation->setChecked(keyboardGroup.readEntry("GestureConfirmation", false));
++  kNotifyAccessX->setChecked(keyboardGroup.readEntry("kNotifyAccessX", false));
+ 
+   checkAccess();
+ 
+@@ -721,37 +720,37 @@
+ 
+   cg.writeEntry("VisibleBellPause", durationSlider->value());
+ 
++  KConfigGroup keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard");
+ 
+-  cg.changeGroup("Keyboard");
+-
+-  cg.writeEntry("StickyKeys", stickyKeys->isChecked());
+-  cg.writeEntry("StickyKeysLatch", stickyKeysLock->isChecked());
+-  cg.writeEntry("StickyKeysAutoOff", stickyKeysAutoOff->isChecked());
+-  cg.writeEntry("StickyKeysBeep", stickyKeysBeep->isChecked());
+-  cg.writeEntry("ToggleKeysBeep", toggleKeysBeep->isChecked());
+-  cg.writeEntry("kNotifyModifiers", kNotifyModifiers->isChecked());
+-
+-  cg.writeEntry("SlowKeys", slowKeys->isChecked());
+-  cg.writeEntry("SlowKeysDelay", slowKeysDelay->value());
+-  cg.writeEntry("SlowKeysPressBeep", slowKeysPressBeep->isChecked());
+-  cg.writeEntry("SlowKeysAcceptBeep", slowKeysAcceptBeep->isChecked());
+-  cg.writeEntry("SlowKeysRejectBeep", slowKeysRejectBeep->isChecked());
+-
+-
+-  cg.writeEntry("BounceKeys", bounceKeys->isChecked());
+-  cg.writeEntry("BounceKeysDelay", bounceKeysDelay->value());
+-  cg.writeEntry("BounceKeysRejectBeep", bounceKeysRejectBeep->isChecked());
+-
+-  cg.writeEntry("Gestures", gestures->isChecked());
+-  cg.writeEntry("AccessXTimeout", timeout->isChecked());
+-  cg.writeEntry("AccessXTimeoutDelay", timeoutDelay->value());
+-
+-  cg.writeEntry("AccessXBeep", accessxBeep->isChecked());
+-  cg.writeEntry("GestureConfirmation", gestureConfirmation->isChecked());
+-  cg.writeEntry("kNotifyAccessX", kNotifyAccessX->isChecked());
++  keyboardGroup.writeEntry("StickyKeys", stickyKeys->isChecked());
++  keyboardGroup.writeEntry("StickyKeysLatch", stickyKeysLock->isChecked());
++  keyboardGroup.writeEntry("StickyKeysAutoOff", stickyKeysAutoOff->isChecked());
++  keyboardGroup.writeEntry("StickyKeysBeep", stickyKeysBeep->isChecked());
++  keyboardGroup.writeEntry("ToggleKeysBeep", toggleKeysBeep->isChecked());
++  keyboardGroup.writeEntry("kNotifyModifiers", kNotifyModifiers->isChecked());
++
++  keyboardGroup.writeEntry("SlowKeys", slowKeys->isChecked());
++  keyboardGroup.writeEntry("SlowKeysDelay", slowKeysDelay->value());
++  keyboardGroup.writeEntry("SlowKeysPressBeep", slowKeysPressBeep->isChecked());
++  keyboardGroup.writeEntry("SlowKeysAcceptBeep", slowKeysAcceptBeep->isChecked());
++  keyboardGroup.writeEntry("SlowKeysRejectBeep", slowKeysRejectBeep->isChecked());
++
++
++  keyboardGroup.writeEntry("BounceKeys", bounceKeys->isChecked());
++  keyboardGroup.writeEntry("BounceKeysDelay", bounceKeysDelay->value());
++  keyboardGroup.writeEntry("BounceKeysRejectBeep", bounceKeysRejectBeep->isChecked());
++
++  keyboardGroup.writeEntry("Gestures", gestures->isChecked());
++  keyboardGroup.writeEntry("AccessXTimeout", timeout->isChecked());
++  keyboardGroup.writeEntry("AccessXTimeoutDelay", timeoutDelay->value());
++
++  keyboardGroup.writeEntry("AccessXBeep", accessxBeep->isChecked());
++  keyboardGroup.writeEntry("GestureConfirmation", gestureConfirmation->isChecked());
++  keyboardGroup.writeEntry("kNotifyAccessX", kNotifyAccessX->isChecked());
+ 
+ 
+   cg.sync();
++  keyboardGroup.sync();
+ 
+   if (systemBell->isChecked() ||
+       customBell->isChecked() ||
+--- a/kcontrol/xinerama/xinerama.desktop
++++ b/kcontrol/xinerama/xinerama.desktop
+@@ -2,7 +2,7 @@
+ Icon=preferences-desktop-display-multiple
+ Type=Service
+ ServiceTypes=KCModule
+-Exec=kcmshell xinerama
++Exec=kcmshell4 xinerama
+ DocPath=kcontrol/multiplemonitors.html
+ Hidden[$e]=$(if test_kcm_xinerama; then echo "false"; else echo "true"; fi)
+ 
+@@ -160,7 +160,7 @@
+ Keywords[hu]=Xinerama,két fejes,két fej,monitor
+ Keywords[it]=Xinerama,dual head,multihead,monitor,monitor multipli
+ Keywords[ja]=Xinerama,デュアルヘッド,マルチヘッド,モニタ
+-Keywords[km]=Xinerama,​ក្បាល​ពីរ,​ក្បាល​ច្រើន,​ម៉ូនីទ័រ
++Keywords[km]=Xinerama ​ក្បាល​ពីរ ​ក្បាល​ច្រើន ​ម៉ូនីទ័រ
+ Keywords[ko]=Xinerama,듀얼 헤드,모니터,다중 모니터
+ Keywords[lt]=Xinerama,dual head,multihead,monitor,dviejų monitorių,monitorius
+ Keywords[lv]=Xinerama,dual head,multihead,monitori
+--- a/kcontrol/xinerama/CMakeLists.txt
++++ b/kcontrol/xinerama/CMakeLists.txt
+@@ -19,7 +19,7 @@
+ kde4_add_plugin(kcm_xinerama ${kcm_xinerama_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_xinerama  ${KDE4_KDE3SUPPORT_LIBS} ${X11_Xinerama_LIB})
++target_link_libraries(kcm_xinerama  ${KDE4_KDEUI_LIBS} ${QT_QT3SUPPORT_LIBRARY} ${X11_Xinerama_LIB})
+ 
+ install(TARGETS kcm_xinerama  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kcontrol/randr/CMakeLists.txt
++++ b/kcontrol/randr/CMakeLists.txt
+@@ -31,7 +31,7 @@
+ kde4_add_plugin(kcm_randr ${kcm_randr_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_randr  ${KDE4_KDEUI_LIBS} ${X11_Xrandr_LIB} ${QT_QTGUI_LIBRARY} ${QT_QT3SUPPORT_LIBRARY})
++target_link_libraries(kcm_randr  ${KDE4_KDEUI_LIBS} ${X11_Xrandr_LIB} )
+ 
+ install(TARGETS kcm_randr  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+@@ -50,7 +50,7 @@
+ 
+ kde4_add_executable(krandrtray ${krandrtray_SRCS})
+ 
+-target_link_libraries(krandrtray  ${KDE4_KUTILS_LIBS} ${X11_Xrandr_LIB} ${QT_QTGUI_LIBRARY} ${QT_QT3SUPPORT_LIBRARY})
++target_link_libraries(krandrtray  ${KDE4_KUTILS_LIBS} ${X11_Xrandr_LIB} )
+ 
+ install(TARGETS krandrtray DESTINATION ${BIN_INSTALL_DIR})
+ 
+--- a/kcontrol/randr/krandrtray.desktop
++++ b/kcontrol/randr/krandrtray.desktop
+@@ -76,6 +76,7 @@
+ Comment[de]=Ein Werkzeug zum Ändern der Bildschirmgröße und -ausrichtung
+ Comment[el]=Ένα εφαρμογίδιο αλλαγής μεγέθους και προσανατολισμού οθονών Χ.
+ Comment[es]=Una miniaplicación del panel para redimensionar y reorientar pantallas X.
++Comment[et]=Paneeliaplett X'i ekraanide suuruse muutmiseks ja pööramiseks
+ Comment[fa]=برنامک تابلویی برای تغییر اندازه و تغییر جهت پرده‌های X.
+ Comment[he]=יישומון לוח לשינוי גודל וכיוון המסך
+ Comment[it]=Un'applet del pannello per ridimensionare e ruotare gli schermi X.
+--- a/kcontrol/randr/layoutmanager.h
++++ b/kcontrol/randr/layoutmanager.h
+@@ -29,7 +29,6 @@
+ 
+ class LayoutManager : public QObject
+ {
+-	Q_OBJECT
+ public:
+ 	LayoutManager(RandRScreen *screen, QGraphicsScene *scene);
+ 	~LayoutManager();
+@@ -43,6 +42,11 @@
+ private:
+ 	RandRScreen *m_screen;
+ 	QGraphicsScene *m_scene;
++
++public:
++
++	Q_OBJECT
++
+ };
+ 
+ #endif // HAS_RANDR_1_2
+--- a/kcontrol/randr/randr.desktop
++++ b/kcontrol/randr/randr.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell randr
++Exec=kcmshell4 randr
+ Icon=preferences-desktop-display-randr
+ Type=Service
+ ServiceTypes=KCModule
+@@ -88,7 +88,7 @@
+ Comment[el]=Αλλαγή μεγέθους και Περιστροφή της οθόνης σας
+ Comment[eo]=Grandigu kaj turnu viajn ekranblokon
+ Comment[es]=Ajustar el tamaño y rotar la pantalla
+-Comment[et]=Oma vaate suuruse muutmine ja pööramine
++Comment[et]=Oma kuva suuruse muutmine ja pööramine
+ Comment[eu]=Aldatu tamaina eta biratu zure pantaila
+ Comment[fa]=تغییر اندازه و چرخش صفحه نمایش شما
+ Comment[fi]=Resoluution muuttaminen ja ruudun kääntäminen
+@@ -103,7 +103,7 @@
+ Comment[ja]=ディスプレイのリサイズと回転
+ Comment[ka]=ეკრანის ზომის და ორიენტაციის შეცვლა
+ Comment[kk]=Дисплейдің өлшемін және бағытын өзгерту
+-Comment[km]=ប្ដូរ​ទំហំ និង​​បង្វិល​ការ​បង្ហាញ​របស់​អ្នក
++Comment[km]=ផ្លាស់ប្ដូរ​​ទំហំ និង​​បង្វិល​ការ​បង្ហាញ​របស់​អ្នក
+ Comment[ko]=디스플레이의 크기와 방향 조정
+ Comment[lt]=Keisti ekrano dydį ir orientaciją
+ Comment[lv]=Maina izmēru un rotē Jūsu ekrānu
+@@ -164,7 +164,7 @@
+ Keywords[is]=resize,rotate,display,color,depth,size,horizontal,vertical,stækka,minnka,snúa
+ Keywords[it]=ridimensiona,ruota,schermo,colori,profondità di colore,dimensione,orizzontale,verticale
+ Keywords[ja]=リサイズ,回転,ディスプレイ,色,深度,サイズ,水平,垂直
+-Keywords[km]=ផ្លាស់ប្ដូរ​ទំហំ,បង្វិល,ការ​បង្ហាញ,ពណ៌,ជម្រៅ,ទំហំ,ផ្ដេក,បញ្ឈរ
++Keywords[km]=ផ្លាស់ប្ដូរ​ទំហំ បង្វិល ការ​បង្ហាញ ពណ៌ ជម្រៅ ទំហំ ផ្ដេក បញ្ឈរ
+ Keywords[ko]=크기 조정,회전,색,깊이,크기,수평,수직
+ Keywords[lt]=resize,rotate,display,color,depth,size,horizontal,vertical,keisti dydį,pasukti,sukti,ekranas,spalva,gylis,dydis,horizontalus,vertikalus
+ Keywords[lv]=mainīt izmēru,rotēt,ekrāns,krāsa,dziļums,izmērs,horizontāls,vertikāls
+--- a/kcontrol/smserver/kcmsmserver.desktop
++++ b/kcontrol/smserver/kcmsmserver.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kcmsmserver
++Exec=kcmshell4 kcmsmserver
+ Icon=preferences-system-session
+ Type=Service
+ ServiceTypes=KCModule
+@@ -168,7 +168,7 @@
+ Keywords[is]=ksmserver,seta,stimpla út,innskráning,staðfesting,vista,endurheimta
+ Keywords[it]=ksmserver,sessione,uscita,conferma,salva,ripristina
+ Keywords[ja]=ksmserver,セッション,ログアウト,確認,保存,復旧
+-Keywords[km]=ksmserver,សម័យ,ចេញ,ការ​អះអាង,រក្សា​ទុក,ស្ដារ
++Keywords[km]=ksmserver សម័យ ចេញ ការ​អះអាង រក្សា​ទុក ស្ដារ
+ Keywords[ko]=ksmserver,세션,로그아웃,확인,저장,복원
+ Keywords[lt]=ksmserver,sesija,išsiregistravimas,patvirtinimas,išsaugoti,atstatyti
+ Keywords[lv]=ksmserveris,sesija,atteikšanās,apstiprinājums,saglabāt,atjaunot
+--- a/kcontrol/smserver/CMakeLists.txt
++++ b/kcontrol/smserver/CMakeLists.txt
+@@ -9,7 +9,7 @@
+ kde4_add_plugin(kcm_smserver ${kcm_smserver_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_smserver  ${KDE4_KDE3SUPPORT_LIBS} )
++target_link_libraries(kcm_smserver  ${QT_QT3SUPPORT_LIBRARY} ${KDE4_KDEUI_LIBS} )
+ 
+ install(TARGETS kcm_smserver  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kcontrol/kthememanager/kthememanager.desktop
++++ b/kcontrol/kthememanager/kthememanager.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kthememanager
++Exec=kcmshell4 kthememanager
+ Icon=preferences-desktop-theme-manager
+ Type=Service
+ ServiceTypes=KCModule
+@@ -163,7 +163,7 @@
+ Keywords[hu]=témák,megjelenés
+ Keywords[it]=temi,aspetto
+ Keywords[ja]=テーマ,look and feel,外観,ルックアンドフィール
+-Keywords[km]=ស្បែក,រូបរាង និង​មុខងារ
++Keywords[km]=ស្បែក រូូបរាង និង​មុខងារ
+ Keywords[ko]=테마,모습과 느낌
+ Keywords[lt]=themes,look and feel,temos,išvaizda ir jausena
+ Keywords[lv]=tēmas,izskats un sajūtas
+--- a/kcontrol/kthememanager/newthemewidget.ui
++++ b/kcontrol/kthememanager/newthemewidget.ui
+@@ -94,7 +94,7 @@
+         </widget>
+       </item>
+       <item row="5" column="1" >
+-        <widget class="Q3TextEdit" name="teComment" />
++        <widget class="QTextEdit" name="teComment" />
+       </item>
+       <item row="4" column="1" >
+         <widget class="QLineEdit" name="leVersion" />
+--- a/kcontrol/kthememanager/ktheme.cpp
++++ b/kcontrol/kthememanager/ktheme.cpp
+@@ -144,34 +144,34 @@
+         QDomElement desktopElem = m_dom.createElement( "desktop" );
+         desktopElem.setAttribute( "number", i );
+         desktopElem.setAttribute( "common", common );
+-
+-        desktopConf.changeGroup( "Desktop" + QString::number( i ) );
++        
++        KConfigGroup group(&_desktopConf,"Desktop" + QString::number( i ));
+ 
+         QDomElement modeElem = m_dom.createElement( "mode" );
+-        modeElem.setAttribute( "id", desktopConf.readEntry( "BackgroundMode", "Flat" ) );
++        modeElem.setAttribute( "id", group.readEntry( "BackgroundMode", "Flat" ) );
+         desktopElem.appendChild( modeElem );
+ 
+         QDomElement c1Elem = m_dom.createElement( "color1" );
+-        c1Elem.setAttribute( "rgb", desktopConf.readEntry( "Color1",QColor() ).name() );
++        c1Elem.setAttribute( "rgb", group.readEntry( "Color1",QColor() ).name() );
+         desktopElem.appendChild( c1Elem );
+ 
+         QDomElement c2Elem = m_dom.createElement( "color2" );
+-        c2Elem.setAttribute( "rgb", desktopConf.readEntry( "Color2",QColor() ).name() );
++        c2Elem.setAttribute( "rgb", group.readEntry( "Color2",QColor() ).name() );
+         desktopElem.appendChild( c2Elem );
+ 
+         QDomElement blendElem = m_dom.createElement( "blending" );
+-        blendElem.setAttribute( "mode", desktopConf.readEntry( "BlendMode", QString( "NoBlending" ) ) );
+-        blendElem.setAttribute( "balance", desktopConf.readEntry( "BlendBalance", QString::number( 100 ) ) );
+-        blendElem.setAttribute( "reverse", desktopConf.readEntry( "ReverseBlending", false ) );
++        blendElem.setAttribute( "mode", group.readEntry( "BlendMode", QString( "NoBlending" ) ) );
++        blendElem.setAttribute( "balance", group.readEntry( "BlendBalance", QString::number( 100 ) ) );
++        blendElem.setAttribute( "reverse", group.readEntry( "ReverseBlending", false ) );
+         desktopElem.appendChild( blendElem );
+ 
+         QDomElement patElem = m_dom.createElement( "pattern" );
+-        patElem.setAttribute( "name", desktopConf.readEntry( "Pattern" ) );
++        patElem.setAttribute( "name", group.readEntry( "Pattern" ) );
+         desktopElem.appendChild( patElem );
+ 
+         QDomElement wallElem = m_dom.createElement( "wallpaper" );
+-        wallElem.setAttribute( "url", processFilePath( "desktop", desktopConf.readPathEntry( "Wallpaper" ) ) );
+-        wallElem.setAttribute( "mode", desktopConf.readEntry( "WallpaperMode" ) );
++        wallElem.setAttribute( "url", processFilePath( "desktop", group.readPathEntry( "Wallpaper" ) ) );
++        wallElem.setAttribute( "mode", group.readEntry( "WallpaperMode" ) );
+         desktopElem.appendChild( wallElem );
+ 
+         // TODO handle multi wallpapers (aka slideshow)
+@@ -183,9 +183,9 @@
+     }
+ 
+     // 11. Screensaver
+-    desktopConf.changeGroup( "ScreenSaver" );
++    KConfigGroup saver(&_desktopConf,"ScreenSaver" );
+     QDomElement saverElem = m_dom.createElement( "screensaver" );
+-    saverElem.setAttribute( "name", desktopConf.readEntry( "Saver" ) );
++    saverElem.setAttribute( "name", saver.readEntry( "Saver" ) );
+     m_root.appendChild( saverElem );
+ 
+     // 3. Icons
+@@ -347,8 +347,8 @@
+         QString value;
+ 
+         if ( group == "FMSettings" ) {
+-            desktopConf.changeGroup( group );
+-            value = desktopConf.readEntry( key, QString() );
++            KConfigGroup grp(&_desktopConf,group );
++            value = grp.readEntry( key, QString() );
+         }
+         else {
+             value = globalConf->group(group).readEntry( key, QString() );
+@@ -411,19 +411,19 @@
+             desktopConf.writeEntry( "CommonDesktop", common );
+             desktopConf.writeEntry( "DeskNum", desktopElem.attribute( "number", "0" ).toUInt() );
+ 
+-            desktopConf.changeGroup( QString( "Desktop%1" ).arg( i ) );
+-            desktopConf.writeEntry( "BackgroundMode", getProperty( desktopElem, "mode", "id" ) );
+-            desktopConf.writeEntry( "Color1", QColor( getProperty( desktopElem, "color1", "rgb" ) ) );
+-            desktopConf.writeEntry( "Color2", QColor( getProperty( desktopElem, "color2", "rgb" ) ) );
+-            desktopConf.writeEntry( "BlendMode", getProperty( desktopElem, "blending", "mode" ) );
+-            desktopConf.writeEntry( "BlendBalance", getProperty( desktopElem, "blending", "balance" ) );
+-            desktopConf.writeEntry( "ReverseBlending",
++            KConfigGroup grp(&_desktopConf, QString( "Desktop%1" ).arg( i ) );
++            grp.writeEntry( "BackgroundMode", getProperty( desktopElem, "mode", "id" ) );
++            grp.writeEntry( "Color1", QColor( getProperty( desktopElem, "color1", "rgb" ) ) );
++            grp.writeEntry( "Color2", QColor( getProperty( desktopElem, "color2", "rgb" ) ) );
++            grp.writeEntry( "BlendMode", getProperty( desktopElem, "blending", "mode" ) );
++            grp.writeEntry( "BlendBalance", getProperty( desktopElem, "blending", "balance" ) );
++            grp.writeEntry( "ReverseBlending",
+                                     static_cast<bool>( getProperty( desktopElem, "blending", "reverse" ).toUInt() ) );
+-            desktopConf.writeEntry( "Pattern", getProperty( desktopElem, "pattern", "name" ) );
+-            desktopConf.writeEntry( "Wallpaper",
++            grp.writeEntry( "Pattern", getProperty( desktopElem, "pattern", "name" ) );
++            grp.writeEntry( "Wallpaper",
+                                     unprocessFilePath( QLatin1String("desktop"),
+                                                        getProperty( desktopElem, "wallpaper", "url" ) ) );
+-            desktopConf.writeEntry( "WallpaperMode", getProperty( desktopElem, "wallpaper", "mode" ) );
++            grp.writeEntry( "WallpaperMode", getProperty( desktopElem, "wallpaper", "mode" ) );
+ 
+             if ( common )
+                 break;          // stop here
+@@ -435,8 +435,8 @@
+ 
+     if ( !saverElem.isNull() )
+     {
+-        desktopConf.changeGroup( "ScreenSaver" );
+-        desktopConf.writeEntry( "Saver", saverElem.attribute( "name" ) );
++        KConfigGroup grp(&_desktopConf,"ScreenSaver" );
++        grp.writeEntry( "Saver", saverElem.attribute( "name" ) );
+     }
+ 
+     desktopConf.sync();         // TODO sync and signal only if <desktop> elem present
+@@ -459,15 +459,15 @@
+             QDomElement iconSubElem = iconList.item( i ).toElement();
+             QString object = iconSubElem.attribute( "object" );
+             if ( object == "desktop" )
+-                iconConf.changeGroup( "DesktopIcons" );
++                iconConf=KConfigGroup(KGlobal::config(), "DesktopIcons" );
+             else if ( object == "mainToolbar" )
+-                iconConf.changeGroup( "MainToolbarIcons" );
++                iconConf=KConfigGroup(KGlobal::config(),"MainToolbarIcons" );
+             else if ( object == "panel" )
+-                iconConf.changeGroup( "PanelIcons" );
++                iconConf=KConfigGroup(KGlobal::config(),"PanelIcons" );
+             else if ( object == "small" )
+-                iconConf.changeGroup( "SmallIcons" );
++                iconConf=KConfigGroup(KGlobal::config(),"SmallIcons" );
+             else if ( object == "toolbar" )
+-                iconConf.changeGroup( "ToolbarIcons" );
++                iconConf=KConfigGroup(KGlobal::config(),"ToolbarIcons" );
+ 
+             QString iconName = iconSubElem.tagName();
+             if ( iconName.contains( "Color" ) )
+@@ -503,13 +503,13 @@
+ 
+             if ( object == "global" )
+             {
+-                soundGroup.changeGroup(eventElem.attribute("name"));
+-                soundGroup.writeEntry( "soundfile", unprocessFilePath( QLatin1String("sounds"), eventElem.attribute( "url" ) ) );
+-                soundGroup.writeEntry( "presentation", soundGroup.readEntry( "presentation" ,0) | 1 );
++                KConfigGroup grp(KSharedConfig::openConfig("knotify.eventsrc"),eventElem.attribute("name"));
++                grp.writeEntry( "soundfile", unprocessFilePath( QLatin1String("sounds"), eventElem.attribute( "url" ) ) );
++                grp.writeEntry( "presentation", soundGroup.readEntry( "presentation" ,0) | 1 );
+             }
+             else if ( object == "kwin" )
+             {
+-                kwinSoundGroup.changeGroup(eventElem.attribute("name"));
++                kwinSoundGroup=KConfigGroup(KSharedConfig::openConfig("kwin.eventsrc"),eventElem.attribute("name"));
+                 kwinSoundGroup.writeEntry( "soundfile", unprocessFilePath( QLatin1String("sounds"), eventElem.attribute( "url" ) ) );
+                 kwinSoundGroup.writeEntry( "presentation", soundGroup.readEntry( "presentation",0 ) | 1 );
+             }
+@@ -541,9 +541,9 @@
+             QDomElement colorElem = colorList.item( i ).toElement();
+             QString object = colorElem.attribute( "object" );
+             if ( object == "global" )
+-                colorGroup.changeGroup("General");
++                colorGroup=KConfigGroup(KGlobal::config(),"General");
+             else if ( object == "kwin" )
+-                colorGroup.changeGroup("WM");
++                colorGroup=KConfigGroup(KGlobal::config(),"WM");
+ 
+             QString colName = colorElem.tagName();
+             QColor curColor = QColor( colorElem.attribute( "rgb" ) );
+@@ -551,7 +551,7 @@
+             colorScheme.writeEntry( colName, curColor ); // thememgr.kcsrc
+         }
+ 
+-        colorGroup.changeGroup("KDE");
++        colorGroup=KConfigGroup(KGlobal::config(),"KDE");
+         colorGroup.writeEntry( "colorScheme", "thememgr.kcsrc", KConfig::Persistent|KConfig::Global);
+         colorGroup.writeEntry( "contrast", colorsElem.attribute( "contrast", "7" ), KConfig::Persistent|KConfig::Global);
+         colorScheme.writeEntry( "contrast", colorsElem.attribute( "contrast", "7" ) );
+--- a/kcontrol/kthememanager/kthemedlg.ui.h
++++ b/kcontrol/kthememanager/kthemedlg.ui.h
+@@ -19,32 +19,32 @@
+ 
+ void KThemeDlg::startBackground()
+ {
+-    KRun::runCommand("kcmshell background", this);
++    KRun::runCommand("kcmshell4 background", this);
+ }
+ 
+ void KThemeDlg::startColors()
+ {
+-    KRun::runCommand("kcmshell colors", this);
++    KRun::runCommand("kcmshell4 colors", this);
+ }
+ 
+ void KThemeDlg::startStyle()
+ {
+-    KRun::runCommand("kcmshell style", this);
++    KRun::runCommand("kcmshell4 style", this);
+ }
+ 
+ void KThemeDlg::startIcons()
+ {
+-    KRun::runCommand("kcmshell icons", this);
++    KRun::runCommand("kcmshell4 icons", this);
+ }
+ 
+ void KThemeDlg::startFonts()
+ {
+-   KRun::runCommand("kcmshell fonts", this);
++   KRun::runCommand("kcmshell4 fonts", this);
+ }
+ 
+ void KThemeDlg::startSaver()
+ {
+-    KRun::runCommand("kcmshell screensaver", this);
++    KRun::runCommand("kcmshell4 screensaver", this);
+ }
+ 
+ #endif // KTHEMEDLG_UI_H
+--- a/kcontrol/launch/kcmlaunch.cpp
++++ b/kcontrol/launch/kcmlaunch.cpp
+@@ -91,7 +91,7 @@
+     lbl_cursorTimeout->setText( i18n( "&Startup indication timeout:" ) );
+     GroupBox1Layout->addWidget( lbl_cursorTimeout, 2, 0 );
+     sb_cursorTimeout = new KIntNumInput( GroupBox1);
+-    sb_cursorTimeout->setRange( 0, 99, 1, true );
++    sb_cursorTimeout->setRange( 0, 99 );
+     sb_cursorTimeout->setSuffix( i18n(" sec") );
+     GroupBox1Layout->addWidget( sb_cursorTimeout, 2, 1 );
+     lbl_cursorTimeout->setBuddy( sb_cursorTimeout );
+@@ -131,7 +131,7 @@
+     lbl_taskbarTimeout->setText( i18n( "Start&up indication timeout:" ) );
+     GroupBox2Layout->addWidget( lbl_taskbarTimeout, 1, 0 );
+     sb_taskbarTimeout = new KIntNumInput( GroupBox2);
+-    sb_taskbarTimeout->setRange( 0, 99, 1, true );
++    sb_taskbarTimeout->setRange( 0, 99 );
+     sb_taskbarTimeout->setSuffix( i18n(" sec") );
+     GroupBox2Layout->addWidget( sb_taskbarTimeout, 1, 1 );
+     lbl_taskbarTimeout->setBuddy( sb_taskbarTimeout );
+--- a/kcontrol/launch/kcmlaunch.desktop
++++ b/kcontrol/launch/kcmlaunch.desktop
+@@ -4,7 +4,7 @@
+ Type=Service
+ ServiceTypes=KCModule
+ DocPath=kcontrol/kcmlaunch/index.html
+-Exec=kcmshell kcmlaunch
++Exec=kcmshell4 kcmlaunch
+ 
+ X-KDE-Library=kcm_launch
+ X-KDE-ParentApp=kcontrol
+@@ -160,7 +160,7 @@
+ Keywords[is]=forrit,start,keyrsla,upptekin,bendill,upplýsingar,mús,pointer,rotating,spinning,disk,startup,program,report
+ Keywords[it]=applicazione,avvio,lancio,occupato,cursore,feedback,segnalazione,mouse,puntatore,rotazione,disco,programma,segnale
+ Keywords[ja]=アプリケーション,開始,起動,ビジー,カーソル,フィードバック,マウス,ポインタ,回転,スピン,開始,プログラム,レポート
+-Keywords[km]=កម្មវិធី,ចាប់ផ្ដើម,ដំណើរ​ការ,រវល់,ទស្សន៍​ទ្រនិច,មតិ​អ្នកប្រើ,កណ្ដុរ,ព្រួញ​កណ្តុរ,​បង្វិល,បង្កើន​បន្ថយ, ថាស,ចាប់ផ្ដើម,កម្មវិធី,របាយការណ៍
++Keywords[km]=កម្មវិធី ចាប់ផ្ដើម ដំណើរ​ការ រវល់ ទស្សន៍​ទ្រនិច មតិ​អ្នកប្រើ កណ្ដុរ ព្រួញ​កណ្តុរ ​បង្វិល បង្កើន​បន្ថយ  ថាស ចាប់ផ្ដើម កម្មវិធី របាយការណ៍
+ Keywords[ko]=프로그램,시작,실행,바쁨,커서,피드백,마우스,포인터,회전,디스크,시작
+ Keywords[lt]=application,start,launch,busy,cursor,feedback,mouse,pointer,rotating,spinning,disk,startup,program,report, programa,startas,paleisti,užimtas,kursorius,atgalinis ryšys, pelė, sukimasis, diskas, paleidimas, raportas
+ Keywords[lv]=aplikācija,startēt,palaist,aizņemts,kursors,atbilde,pele,bultiņa,rotēšana,sagriešanās,disks,startēšana,programma,reports
+--- a/kcontrol/keys/shortcuts.cpp
++++ b/kcontrol/keys/shortcuts.cpp
+@@ -120,10 +120,6 @@
+ #define NOSLOTS
+ //#define KICKER_ALL_BINDINGS
+ #include "../../kwin/kwinbindings.cpp"
+-//#include "../../kicker/kicker/core/kickerbindings.cpp"
+-//#include "../../kicker/taskbar/taskbarbindings.cpp"
+-//#include "../../kdesktop/kdesktopbindings.cpp"
+-#include "../../klipper/klipperbindings.cpp"
+ #include "../kxkb/kxkbbindings.cpp"
+ 
+ 	kDebug(125) << "B-----------";
+--- a/kcontrol/keys/keys.desktop
++++ b/kcontrol/keys/keys.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell keys
++Exec=kcmshell4 keys
+ Icon=preferences-desktop-keyboard-shortcut
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+@@ -168,7 +168,7 @@
+ Keywords[is]=Lyklar,Hnappar,Flýtihnappar,Flýtilyklar,Lyklabindingar
+ Keywords[it]=tasti,associazioni globali di tasti,schema di tasti,associazioni di tasti,scorciatoie,scorciatoie delle applicazioni
+ Keywords[ja]=キー,グローバルキー,キーバインド,Key sheme,キーバインド,ショートカット,アプリケーションショートカット
+-Keywords[km]=គ្រាប់ចុច,ការ​ចង​គ្រាប់ចុច​សកល,គ្រោងការណ៍​គ្រាប់ចុច,ការ​ចង​គ្រាប់ចុច,ផ្លូវកាត់,ផ្លូវកាត់​កម្មវិធី
++Keywords[km]=គ្រាប់ចុច ការ​ចង​គ្រាប់ចុច​សកល គ្រោងការណ៍​គ្រាប់ចុច ការ​ចង​គ្រាប់ចុច ផ្លូវកាត់ ផ្លូវកាត់​កម្មវិធី
+ Keywords[ko]=키,전역 키 바인딩,키 배열,키 바인딩,단축키,프로그램 단축키
+ Keywords[lt]=Keys,klavišai,Global key bindings,klavišų sietis,Key scheme,klavišų schema,klavišų išdėstymas,Key bindings,shortcuts,spartieji klavišai,application shortcuts,programų spartieji klavišai
+ Keywords[lv]=Taustiņi,Globālās taustiņu sasaistes,Taustiņu shēma,Taustiņu sasaistes,īsinājumikonas,aplikāciju īsinājumikonas
+--- a/kcontrol/keys/keyconfig.cpp
++++ b/kcontrol/keys/keyconfig.cpp
+@@ -62,9 +62,6 @@
+ #define NOSLOTS
+ #define KShortcuts KAccelShortcuts
+ #include "../../kwin/kwinbindings.cpp"
+-#include "../../kicker/kicker/core/kickerbindings.cpp"
+-#include "../../kicker/taskbar/taskbarbindings.cpp"
+-#include "../../klipper/klipperbindings.cpp"
+ #include "../kxkb/kxkbbindings.cpp"
+ #undef KShortcuts
+     KeyScheme = "Global Key Scheme";
+@@ -475,10 +472,7 @@
+ // this should match the included files above
+ #define NOSLOTS
+ #define KShortcuts KAccelShortcuts
+-#include "../../../workspace/klipper/klipperbindings.cpp"
+ #include "../../kwin/kwinbindings.cpp"
+-#include "../../kicker/kicker/core/kickerbindings.cpp"
+-#include "../../kicker/taskbar/taskbarbindings.cpp"
+ #include "../kxkb/kxkbbindings.cpp"
+ #undef KShortcuts
+ 
+--- a/kcontrol/keys/mac4.kksrc
++++ b/kcontrol/keys/mac4.kksrc
+@@ -30,7 +30,7 @@
+ Name[ja]=Macintosh スキーマ
+ Name[ka]=Mac სქემა
+ Name[kk]=Mac сұлбасы
+-Name[km]=គ្រោងការណ៍ Mac
++Name[km]=គ្រោងការណ៍​មេក
+ Name[ko]=Mac 배열
+ Name[lt]=Mac schema
+ Name[mk]=Mac-шема
+--- a/kcontrol/keys/kde4.kksrc
++++ b/kcontrol/keys/kde4.kksrc
+@@ -26,7 +26,7 @@
+ Name[it]=Predefinito di KDE per 4 tasti modificatori
+ Name[ja]=KDE 標準 (4 モディファイアキー)
+ Name[kk]=4 түрлендіру перне үшін KDE-нің әдетті баптауы
+-Name[km]=លំនាំ​ដើម​របស់ KDE ​សម្រាប់​​គ្រាប់​ចុច​កែប្រែ​ ៤
++Name[km]=លំនាំដើម​របស់ KDE ​សម្រាប់​​គ្រាប់​ចុច​កែប្រែ​ ៤
+ Name[ko]=네 개의 수정자 키를 사용하는 KDE 기본값
+ Name[lt]=KDE numatytoji 4 klavišams - modifikatoriams
+ Name[mk]=KDE-стандардно за 4 копчиња-модификатори
+--- a/kcontrol/keys/main.cpp
++++ b/kcontrol/keys/main.cpp
+@@ -121,6 +121,12 @@
+ {
+   KDE_EXPORT void kcminit_keys()
+   {
++#ifdef __GNUC__
++#warning TODO Check if this is still needed and redo it
++#endif
++// This is currently disabled - it makes the kdedglobalaccel module think the shortcuts
++// are for kcminit, and it takes the shortcuts away from e.g. Klipper.
++#if 0
+ 	kDebug(125) << "KeyModule::init()\n";
+ 
+ 	kDebug(125) << "KeyModule::init() - Load Included Bindings\n";
+@@ -129,7 +135,7 @@
+ 	QAction* a = 0L;
+ // this should match the included files above
+ #define NOSLOTS
+-#include "../..//klipper/klipperbindings.cpp"
++//#include "../..//klipper/klipperbindings.cpp"
+ #include "../../kwin/kwinbindings.cpp"
+ //#define KICKER_ALL_BINDINGS
+ //#include "../../kicker/kicker/core/kickerbindings.cpp"
+@@ -146,22 +152,17 @@
+ 	    kDebug(125) << "KeyModule::init() - Read Config Bindings\n";
+ 	    // Check for old group,
+ 	    if( KGlobal::config()->hasGroup( "Global Keys" ) ) {
+-#ifdef __GNUC__
+-#warning TODO PORT ME (KGlobalAccel related)
+-#endif
+ //		KGlobalAccel::self()->readSettings();
+ 		KGlobal::config()->deleteGroup( "Global Keys", KConfig::Global);
+ 	    }
+             KGlobal::config()->deleteGroup( "deprecated Global Shortcuts from kcontrol/keys", KConfig::Global);
+ 
+ 	    kDebug(125) << "KeyModule::init() - Write Config Bindings\n";
+-#ifdef __GNUC__
+-#warning TODO PORT ME (KGlobalAccel related)
+-#endif
+         //KGlobalAccel::self()->writeSettings();
+             group.writeEntry( "Defaults timestamp", __DATE__ __TIME__, KConfig::Normal|KConfig::Global);
+         }
+ 	delete actionCollection;
++#endif
+   }
+ }
+ 
+--- a/kcontrol/kdm/kdm.desktop
++++ b/kcontrol/kdm/kdm.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kdm
++Exec=kcmshell4 kdm
+ Icon=preferences-desktop-login
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kcontrol/bell/bell.cpp
++++ b/kcontrol/bell/bell.cpp
+@@ -20,15 +20,16 @@
+ */
+ 
+ #include <QCheckBox>
+-#include <Qt3Support/Q3GroupBox>
+ #include <QLayout>
+ #include <QPushButton>
+ 
++
+ //Added by qt3to4:
+ #include <QVBoxLayout>
+ #include <QHBoxLayout>
+ #include <QGridLayout>
+ #include <QBoxLayout>
++#include <QGroupBox>
+ 
+ #include <kcmodule.h>
+ #include <kaboutdata.h>
+@@ -83,8 +84,8 @@
+   layout->setSpacing(KDialog::spacingHint());
+ 
+   int row = 0;
+-  Q3GroupBox *box = new Q3GroupBox( i18n("Bell Settings"), this );
+-  box->setColumnLayout( 0, Qt::Horizontal );
++  QGroupBox *box = new QGroupBox(i18n("Bell Settings"), this );
++  new QVBoxLayout( box );
+   layout->addWidget(box);
+   layout->addStretch();
+   QGridLayout *grid = new QGridLayout();
+@@ -117,7 +118,7 @@
+   m_volume->setWhatsThis( i18n("Here you can customize the volume of the system bell. For further"
+     " customization of the bell, see the \"Accessibility\" control module.") );
+ 
+-  m_pitch = new KIntNumInput(m_volume, 800, box);
++  m_pitch = new KIntNumInput(800, box);
+   m_pitch->setLabel(i18n("&Pitch:"));
+   m_pitch->setRange(20, 2000, 20);
+   m_pitch->setSuffix(i18n(" Hz"));
+@@ -126,7 +127,7 @@
+   m_pitch->setWhatsThis( i18n("Here you can customize the pitch of the system bell. For further"
+     " customization of the bell, see the \"Accessibility\" control module.") );
+ 
+-  m_duration = new KIntNumInput(m_pitch, 100, box);
++  m_duration = new KIntNumInput(100, box);
+   m_duration->setLabel(i18n("&Duration:"));
+   m_duration->setRange(1, 1000, 50);
+   m_duration->setSuffix(i18n(" msec"));
+--- a/kcontrol/bell/bell.desktop
++++ b/kcontrol/bell/bell.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell bell
++Exec=kcmshell4 bell
+ Icon=preferences-desktop-notification-bell
+ Type=Service
+ ServiceTypes=KCModule,KCModuleInit
+--- a/kcontrol/bell/CMakeLists.txt
++++ b/kcontrol/bell/CMakeLists.txt
+@@ -9,7 +9,7 @@
+ kde4_add_plugin(kcm_bell ${kcm_bell_PART_SRCS})
+ 
+ 
+-target_link_libraries(kcm_bell  ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QT3SUPPORT_LIBRARY} ${X11_X11_LIB})
++target_link_libraries(kcm_bell  ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY} ${X11_X11_LIB})
+ 
+ install(TARGETS kcm_bell  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/startkde.cmake
++++ b/startkde.cmake
+@@ -74,9 +74,9 @@
+ kcmrandrrc [Screen3]
+ kcmfonts General forceFontDPI 0
+ EOF
+-kstartupconfig
++kstartupconfig4
+ if test $? -ne 0; then
+-    xmessage -geometry 500x100 "Could not start kstartupconfig. Check your installation."
++    xmessage -geometry 500x100 "Could not start kstartupconfig4. Check your installation."
+ fi
+ . $kdehome/share/config/startupconfig
+ 
+--- a/menu/desktop/kde-education.directory
++++ b/menu/desktop/kde-education.directory
+@@ -8,6 +8,7 @@
+ Name[de]=Lernprogramme
+ Name[el]=Εκπαίδευση
+ Name[es]=Educación
++Name[et]=Õpptimine
+ Name[fa]=آموزش
+ Name[ga]=Oideachas
+ Name[he]=חינוך
+--- a/menu/desktop/kde-utilities.directory
++++ b/menu/desktop/kde-utilities.directory
+@@ -15,7 +15,7 @@
+ Name[el]=Εργαλεία
+ Name[eo]=Utilaĵoj
+ Name[es]=Utilidades
+-Name[et]=Utiliidid
++Name[et]=Tööriistad
+ Name[eu]=Tresnak
+ Name[fa]=برنامه‌های سودمند
+ Name[fi]=Apuohjelmat
+@@ -31,7 +31,7 @@
+ Name[ja]=ユーティリティ
+ Name[ka]=ხელსაწყოები
+ Name[kk]=Утилиталары
+-Name[km]=ឧបករណ៍
++Name[km]=ឧបករណ៍​ប្រើ​ប្រាស់
+ Name[ko]=유틸리티
+ Name[lt]=Pagalbininkai
+ Name[lv]=Utilītas
+@@ -80,7 +80,7 @@
+ Comment[el]=Εργαλεία
+ Comment[eo]=Utilaĵoj
+ Comment[es]=Utilidades
+-Comment[et]=Utiliidid
++Comment[et]=Tööriistad
+ Comment[eu]=Tresnak
+ Comment[fa]=برنامه‌های سودمند
+ Comment[fi]=Apuohjelmat
+@@ -96,7 +96,7 @@
+ Comment[ja]=ユーティリティ
+ Comment[ka]=ხელსაწყოები
+ Comment[kk]=Утилиталары
+-Comment[km]=ឧបករណ៍
++Comment[km]=ឧបករណ៍​ប្រើប្រាស់
+ Comment[ko]=유틸리티
+ Comment[lt]=Pagalbininkai
+ Comment[lv]=Utilītas
+--- a/menu/desktop/kde-edu-languages.directory
++++ b/menu/desktop/kde-edu-languages.directory
+@@ -10,6 +10,7 @@
+ Name[de]=Sprachen
+ Name[el]=Γλώσσες
+ Name[es]=Idiomas
++Name[et]=Keeled
+ Name[fa]=زبانها
+ Name[ga]=Teangacha
+ Name[he]=שפות
+--- a/menu/desktop/kde-edu-science.directory
++++ b/menu/desktop/kde-edu-science.directory
+@@ -6,10 +6,12 @@
+ Name[ar]=العلوم
+ Name[be]=Навука
+ Name[bg]=Наука
++Name[br]=Skiantoù
+ Name[csb]=Ùczba
+ Name[de]=Wissenschaft
+ Name[el]=Επιστήμη
+ Name[es]=Ciencia
++Name[et]=Teadus
+ Name[fa]=علم
+ Name[ga]=Eolaíocht
+ Name[he]=מדע
+--- a/menu/desktop/kde-internet.directory
++++ b/menu/desktop/kde-internet.directory
+@@ -17,7 +17,7 @@
+ Name[ja]=インターネット
+ Name[ka]=ინტერნეტი
+ Name[kk]=Интернет
+-Name[km]=អ៊ិនធឺណិត
++Name[km]=អ៊ីនធឺណិត
+ Name[ko]=인터넷
+ Name[lt]=Internetas
+ Name[lv]=Internets
+--- a/menu/desktop/kde-development-webdevelopment.directory
++++ b/menu/desktop/kde-development-webdevelopment.directory
+@@ -31,7 +31,7 @@
+ Name[ja]=ウェブ開発
+ Name[ka]=ვებ პროგრამირება
+ Name[kk]=Веб жобалау
+-Name[km]=​អភិវឌ្ឍន៍​បណ្តាញ
++Name[km]=ការ​​អភិវឌ្ឍន៍​បណ្តាញ
+ Name[ko]=웹 개발
+ Name[lt]=Žiniatinklio programavimas
+ Name[mk]=Веб-развој
+@@ -96,7 +96,7 @@
+ Name[ja]=ウェブ開発
+ Name[ka]=ვებ პროგრამირება
+ Name[kk]=Веб жобалау
+-Name[km]=​អភិវឌ្ឍន៍​បណ្តាញ
++Name[km]=ការ​​អភិវឌ្ឍន៍​បណ្តាញ
+ Name[ko]=웹 개발
+ Name[lt]=Žiniatinklio programavimas
+ Name[mk]=Веб-развој
+--- a/menu/desktop/kde-internet-terminal.directory
++++ b/menu/desktop/kde-internet-terminal.directory
+@@ -16,7 +16,7 @@
+ Name[el]=Εφαρμογές τερματικού
+ Name[eo]=Terminal-Aplikaĵoj
+ Name[es]=Aplicaciones de terminal
+-Name[et]=Terminali rakendused
++Name[et]=Terminalirakendused
+ Name[eu]=Terminaleko aplikazioak
+ Name[fa]=کاربردهای پایانه
+ Name[fi]=Päätesovellukset
+--- a/menu/desktop/kde-games-arcade.directory
++++ b/menu/desktop/kde-games-arcade.directory
+@@ -24,7 +24,7 @@
+ Name[is]=Spilasalur
+ Name[ja]=アーケード
+ Name[kk]=Аркад ойындары
+-Name[km]=ធ្វើ​ដំណើរ
++Name[km]=អារខាដ
+ Name[ko]=아케이드
+ Name[lt]=Arkada
+ Name[lv]=Arkāde
+--- a/menu/desktop/kde-edu-tools.directory
++++ b/menu/desktop/kde-edu-tools.directory
+@@ -10,6 +10,7 @@
+ Name[de]=Unterrichts-Anwendungen
+ Name[el]=Εργαλείο διδασκαλίας
+ Name[es]=Herramienta de enseñanza
++Name[et]=Õpperakendused
+ Name[fa]=ابزارهای آموزشی
+ Name[ga]=Uirlisí Múinteoireachta
+ Name[he]=כלי לימוד
+--- a/menu/desktop/kde-edu-miscellaneous.directory
++++ b/menu/desktop/kde-edu-miscellaneous.directory
+@@ -10,6 +10,7 @@
+ Name[de]=Verschiedenes
+ Name[el]=Διάφορα
+ Name[es]=Diversos
++Name[et]=Muud
+ Name[fa]=متفرقه
+ Name[ga]=Éagsúil
+ Name[he]=שונות
+--- a/menu/desktop/kde-development.directory
++++ b/menu/desktop/kde-development.directory
+@@ -32,7 +32,7 @@
+ Name[ja]=開発
+ Name[ka]=განვითარება
+ Name[kk]=Жетілдіру
+-Name[km]=​អភិវឌ្ឍន៍
++Name[km]=ការ​​អភិវឌ្ឍន៍
+ Name[ko]=개발
+ Name[lt]=Programavimas
+ Name[lv]=Izstrāde
+--- a/menu/desktop/kde-system-terminal.directory
++++ b/menu/desktop/kde-system-terminal.directory
+@@ -16,7 +16,7 @@
+ Name[el]=Εφαρμογές τερματικού
+ Name[eo]=Terminal-Aplikaĵoj
+ Name[es]=Aplicaciones de terminal
+-Name[et]=Terminali rakendused
++Name[et]=Terminalirakendused
+ Name[eu]=Terminaleko aplikazioak
+ Name[fa]=کاربردهای پایانه
+ Name[fi]=Päätesovellukset
+--- a/menu/desktop/kde-unknown.directory
++++ b/menu/desktop/kde-unknown.directory
+@@ -30,7 +30,7 @@
+ Name[is]=Tapað & fundið
+ Name[it]=Oggetti smarriti
+ Name[kk]=Жоғалып табылғандар
+-Name[km]=បាត់ និង​រកឃើញ
++Name[km]=បាត់ ហើយ​រកឃើញ
+ Name[lt]=Pamesta ir rasta
+ Name[lv]=Pazudis & Atrasts
+ Name[mk]=Изгубено-најдено
+--- a/menu/desktop/kde-utilities-xutils.directory
++++ b/menu/desktop/kde-utilities-xutils.directory
+@@ -15,7 +15,7 @@
+ Name[el]=Εργαλεία-X
+ Name[eo]=X-Utilaĵoj
+ Name[es]=Utilidades-X
+-Name[et]=X'i utiliidid
++Name[et]=X'i tööriistad
+ Name[eu]=X-tresnak
+ Name[fa]=برنامه‌های سودمند X
+ Name[fi]=X-Apuohjelmat
+@@ -31,7 +31,7 @@
+ Name[ja]=X-ユーティリティ
+ Name[ka]= X-ხელსაწყოები
+ Name[kk]=X-утилиталар
+-Name[km]=ឧបករណ៍-X
++Name[km]=ឧបករណ៍​ប្រើប្រាស់-X
+ Name[ko]=X 유틸리티
+ Name[lt]=X pagalbininkai
+ Name[lv]=X Utilītas
+@@ -79,7 +79,7 @@
+ Comment[el]=Εργαλεία των X Windows
+ Comment[eo]=Utilaĵoj por la X-Fenestrosistemo
+ Comment[es]=Utilidades X Window
+-Comment[et]=X Window utiliidid
++Comment[et]=X Window tööriistad
+ Comment[eu]=X Window tresnak
+ Comment[fa]=برنامه‌های سودمند پنجرۀ X
+ Comment[fi]=X Window -apuohjelmat
+@@ -95,7 +95,7 @@
+ Comment[ja]=X ウィンドウユーティリティ
+ Comment[ka]=X Window–ს ხელსაწყოები
+ Comment[kk]=X Window утилиталары
+-Comment[km]=ឧបករណ៍ X Window
++Comment[km]=ឧបករណ៍​ប្រើប្រាស់ X Window
+ Comment[ko]=X 윈도 유틸리티
+ Comment[lt]=X Window pagalbininkai
+ Comment[lv]=X logu utilītas
+--- a/menu/desktop/kde-more.directory
++++ b/menu/desktop/kde-more.directory
+@@ -33,7 +33,7 @@
+ Name[ja]=その他のアプリケーション
+ Name[ka]=დამატებითი პროგრამები
+ Name[kk]=Басқа қолданбалар
+-Name[km]=កម្មវិធីបន្ថែម​ទៀត
++Name[km]=កម្មវិធី​ផ្សេង​ទៀត
+ Name[ko]=더 많은 프로그램
+ Name[lt]=Daugiau programų
+ Name[lv]=Vairāk aplikāciju
+--- a/menu/desktop/kde-edu-mathematics.directory
++++ b/menu/desktop/kde-edu-mathematics.directory
+@@ -11,6 +11,7 @@
+ Name[de]=Mathematik
+ Name[el]=Μαθηματικά
+ Name[es]=Matemáticas
++Name[et]=Matemaatika
+ Name[fa]=ریاضیات
+ Name[ga]=Matamaitic
+ Name[he]=מתמטיקה
+--- a/doc/CMakeLists.txt
++++ b/doc/CMakeLists.txt
+@@ -1,8 +1,6 @@
+ add_subdirectory(kdm)
+-add_subdirectory(kicker)
+ add_subdirectory(kinfocenter)
+ add_subdirectory(klipper)
+ add_subdirectory(kmenuedit)
+-add_subdirectory(kompmgr)
+ add_subdirectory(ksysguard)
+ add_subdirectory(kxkb)
+--- a/systemsettings/categories/settings-notifications.desktop
++++ b/systemsettings/categories/settings-notifications.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Benachrichtigungen
+ Name[el]=Ειδοποιήσεις
+ Name[es]=Notificaciones
++Name[et]=Märguanded
+ Name[fa]=اخطارها
+ Name[ga]=Fógairt
+ Name[he]=הודעות מערכת
+--- a/systemsettings/categories/settings-about-me.desktop
++++ b/systemsettings/categories/settings-about-me.desktop
+@@ -12,6 +12,7 @@
+ Name[de]=Persönliche Informationen
+ Name[el]=Σχετικά με μένα
+ Name[es]=Acerca de mí
++Name[et]=Isiklik info
+ Name[fa]=درباره من
+ Name[ga]=Maidir Liomsa
+ Name[he]=אודותיי
+--- a/systemsettings/categories/settings-look-and-feel.desktop
++++ b/systemsettings/categories/settings-look-and-feel.desktop
+@@ -14,6 +14,7 @@
+ Name[de]=Erscheinungsbild & Verhalten
+ Name[el]=Όψη & αίσθηση
+ Name[es]=Aspecto y comportamiento
++Name[et]=Välimus
+ Name[fa]=ظاهر و احساس
+ Name[ga]=Cuma
+ Name[he]=מראה ותחושה
+--- a/systemsettings/categories/settings-general.desktop
++++ b/systemsettings/categories/settings-general.desktop
+@@ -12,6 +12,7 @@
+ Name[csb]=Spòdlowé
+ Name[de]=Allgemein
+ Name[el]=Γενικά
++Name[et]=Üldine
+ Name[fa]=عمومی
+ Name[ga]=Ginearálta
+ Name[he]=כללי
+--- a/systemsettings/categories/settings-advanced-user-settings.desktop
++++ b/systemsettings/categories/settings-advanced-user-settings.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Erweiterte Benutzereinstellungen
+ Name[el]=Προχωρημένες ρυθμίσεις χρήστη
+ Name[es]=Preferencias para usuarios avanzados
++Name[et]=Muud kasutaja seadistused
+ Name[fa]=تنظیمات کاربر پیشرفته
+ Name[ga]=Ardsocruithe Úsáideora
+ Name[he]=הגדרות משתמש מתקדמות
+--- a/systemsettings/categories/settings-computer-administration.desktop
++++ b/systemsettings/categories/settings-computer-administration.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Systemverwaltung
+ Name[el]=Διαχείριση συστήματος
+ Name[es]=Administración del equipo
++Name[et]=Arvuti haldamine
+ Name[fa]=سرپرستی رایانه
+ Name[he]=ניהול המחשב
+ Name[it]=Amministrazione del computer
+--- a/systemsettings/categories/settings-regional-and-language.desktop
++++ b/systemsettings/categories/settings-regional-and-language.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Land/Region & Sprache
+ Name[el]=Τοπικές ρυθμίσεις & γλώσσα
+ Name[es]=Región e idioma
++Name[et]=Riik/regioon ja keel
+ Name[fa]=منطقه‌ای و زبان
+ Name[ga]=Réigiún agus Teanga
+ Name[he]=איזור ושפה
+--- a/systemsettings/categories/settings-personal.desktop
++++ b/systemsettings/categories/settings-personal.desktop
+@@ -12,6 +12,7 @@
+ Name[bg]=Лични бележки
+ Name[de]=Persönliches
+ Name[el]=Προσωπικά
++Name[et]=Isiklik
+ Name[fa]=شخصی
+ Name[ga]=Pearsanta
+ Name[he]=הגדרות אישיות
+--- a/systemsettings/categories/settings-keyboard-and-mouse.desktop
++++ b/systemsettings/categories/settings-keyboard-and-mouse.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Tastatur & Maus
+ Name[el]=Πληκτρολόγιο & ποντίκι
+ Name[es]=Teclado y ratón
++Name[et]=Klaviatuur ja hiir
+ Name[fa]=صفحه کلید و موشی
+ Name[ga]=Méarchlár & Luch
+ Name[he]=מקלדת ועכבר
+--- a/systemsettings/categories/settings-network-settings.desktop
++++ b/systemsettings/categories/settings-network-settings.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Netzwerk-Einstellungen
+ Name[el]=Ρυθμίσεις δικτύου
+ Name[es]=Preferencias de red
++Name[et]=Võrguseadistused
+ Name[fa]=تنظیمات شبکه
+ Name[ga]=Socruithe Líonra
+ Name[he]=הגדרות רשת
+--- a/systemsettings/categories/settings-sharing.desktop
++++ b/systemsettings/categories/settings-sharing.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Freigabe
+ Name[el]=Διαμοιρασμός
+ Name[es]=Compartición
++Name[et]=Jagamine
+ Name[fa]=اشتراک
+ Name[ga]=Comhroinnt
+ Name[he]=שיתוף
+--- a/systemsettings/categories/settings-network-and-connectivity.desktop
++++ b/systemsettings/categories/settings-network-and-connectivity.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Netzwerk & Verbindungen
+ Name[el]=Δίκτυο & συνδεσιμότητα
+ Name[es]=Red y conectividad
++Name[et]=Võrk
+ Name[fa]=شبکه و اتصال
+ Name[ga]=Líonra & Nascacht
+ Name[he]=רשת וקישוריות
+--- a/systemsettings/categories/systemsettingscategory.desktop
++++ b/systemsettings/categories/systemsettingscategory.desktop
+@@ -9,6 +9,7 @@
+ Name[de]=Systemeinstellungen-Kategorie
+ Name[el]=Κατηγορία ρυθμίσεων συστήματος
+ Name[es]=Categoría de preferencias del sistema
++Name[et]=Süsteemi seadistuste kategooria
+ Name[fa]=دسته تنظیمات سیستم
+ Name[he]=קטגוריית הגדרות מערכת
+ Name[ja]=システム設定のカテゴリ
+--- a/systemsettings/modulesview.h
++++ b/systemsettings/modulesview.h
+@@ -26,6 +26,7 @@
+ #include <QListWidget>
+ #include <QList>
+ 
++#include <KService>
+ /**
+  * Overloaded to give a larger default size that fits with text of two lines.
+  */
+@@ -102,6 +103,7 @@
+ 	QList<RowIconView*> groups;
+ 	KCModuleMenu *rootMenu;
+ 	QString menuPath;
++	KService::List categories;
+ 
+ 	void createRow( const QString &parentPath, QBoxLayout *layout );
+ };
+--- a/systemsettings/kcmodulemenu.cpp
++++ b/systemsettings/kcmodulemenu.cpp
+@@ -28,22 +28,28 @@
+ class KCModuleMenuPrivate {
+ public:
+ 	KCModuleMenuPrivate(){
++		categories = KServiceTypeTrader::self()->query("SystemSettingsCategory");
++		modules = KServiceTypeTrader::self()->query("KCModule");
+ 	}
+-				
++
+ 	QMap<QString, QList<MenuItem> > menus;
+ 	QString basePath;
++	KService::List categories;
++	KService::List modules;
++
+ };
+ 
+ KCModuleMenu::KCModuleMenu( const QString &menuName ) :
+ 	d( new KCModuleMenuPrivate )
+ {
++	Q_UNUSED(menuName);
+ 	// Make sure we can find the menu
+ 	QString menuRoot = "System Settings"; //just a handy key to use, not part of UI
+ 	d->basePath = menuRoot + '/';
+ 	readMenu( "", menuRoot );
+ 
+-	QMapIterator<QString, QList<MenuItem> > i(d->menus);
+ 	/*debugging
++	QMapIterator<QString, QList<MenuItem> > i(d->menus);
+ 	while (i.hasNext()) {
+ 		i.next();
+ 		kDebug() << "menu: " << i.key();
+@@ -54,7 +60,6 @@
+ 		}
+ 	}
+ 	*/
+-	KService::List offers = KServiceTypeTrader::self()->query("KCModule");
+ }
+ 
+ KCModuleMenu::~KCModuleMenu()
+@@ -67,9 +72,8 @@
+ 	typedef KSharedPtr<KService> MySharedPtr_KService;
+ 
+ 	QList<MenuItem> currentMenu;
+-	KService::List categories = KServiceTypeTrader::self()->query("SystemSettingsCategory");
+-	for (int i = 0; i < categories.size(); ++i) {
+-		const KService* entry = categories.at(i).data();
++	for (int i = 0; i < d->categories.size(); ++i) {
++		const KService* entry = d->categories.at(i).data();
+ 		QString parentCategory = entry->property("X-KDE-System-Settings-Parent-Category").toString();
+ 		QString category = entry->property("X-KDE-System-Settings-Category").toString();
+ 
+@@ -83,9 +87,8 @@
+ 		}
+ 	}
+ 
+-	KService::List modules = KServiceTypeTrader::self()->query("KCModule");
+-	for (int i = 0; i < modules.size(); ++i) {
+-		const KService* entry = modules.at(i).data();
++	for (int i = 0; i < d->modules.size(); ++i) {
++		const KService* entry = d->modules.at(i).data();
+ 		QString category = entry->property("X-KDE-System-Settings-Parent-Category").toString();
+ 		if( category == parentName && !parentName.isEmpty() ) {
+ 			// Add the module info to the menu
+@@ -98,6 +101,7 @@
+ 		}
+ 	}
+ 
++	qSort(currentMenu);
+ 	d->menus.insert( caption + '/', currentMenu );
+ }
+ 
+@@ -157,3 +161,18 @@
+ 	}
+ 	return d->menus[menuPath];
+ }
++
++bool MenuItem::operator<(const MenuItem& rhs) const
++{
++    //kDebug() << "comparing" << caption << "to" << rhs.caption;
++    if (caption == i18n("General")) {
++        //kDebug() << "General tab ... we're always the smallest even if we have to lie about it";
++        return true;
++    } else if (rhs.caption == i18n("General")) {
++        //kDebug() << "Other guy is 'General', let's always say we're bigger";
++        return false;
++    }
++
++    return caption < rhs.caption;
++}
++
+--- a/systemsettings/systemsettings.desktop
++++ b/systemsettings/systemsettings.desktop
+@@ -13,6 +13,7 @@
+ Name[de]=Systemeinstellungen
+ Name[el]=Ρυθμίσεις συστήματος
+ Name[es]=Preferencias del sistema
++Name[et]=Süsteemi seadistused
+ Name[fa]=تنظیمات سیستم
+ Name[ga]=Socruithe an Chórais
+ Name[he]=הגדרות מערכת
+--- a/systemsettings/kcmsearch.cpp
++++ b/systemsettings/kcmsearch.cpp
+@@ -50,6 +50,7 @@
+ 	int page = 0;
+ 	int *hitArray = new int[moduleViewList->count()];
+ 
++	QRegExp reSearch('*'+search+'*', Qt::CaseInsensitive, QRegExp::Wildcard);
+ 	while ( moduleViewListIt.hasNext() ) {
+ 		mainView = moduleViewListIt.next();
+ 
+@@ -58,7 +59,8 @@
+ 			int itemCounter = 0;
+ 			QListWidgetItem *item = (*it)->item(itemCounter);
+ 			while( item ) {
+-				bool hit = itemMatches(item, search);
++				bool hit = reSearch.indexIn( item->text() ) >= 0 ||
++						itemMatches(item, search);
+ 				((ModuleIconItem*)item)->loadIcon(hit);
+ 				count += hit ? 1 : 0;
+ 				//item = item->nextItem();
+--- a/systemsettings/modulesview.cpp
++++ b/systemsettings/modulesview.cpp
+@@ -36,6 +36,7 @@
+ {
+ 	this->rootMenu = rootMenu;	
+ 	this->menuPath = menuPath;
++	this->categories = KServiceTypeTrader::self()->query("SystemSettingsCategory");
+ 
+ 	QVBoxLayout *layout = new QVBoxLayout( this );
+ 	layout->setMargin( 11 );
+@@ -97,7 +98,6 @@
+ {
+ 	//find the category name and search for it
+ 	QString categoryName = parentPath.section('/', -2, -2);
+-	KService::List categories = KServiceTypeTrader::self()->query("SystemSettingsCategory");
+ 	QString iconName;
+ 	for (int i = 0; i < categories.size(); ++i) {
+ 		const KService* entry = categories.at(i).data();
+--- a/systemsettings/mainwindow.cpp
++++ b/systemsettings/mainwindow.cpp
+@@ -85,11 +85,11 @@
+ 	QScrollArea *modulesScroller;
+ 	moduleTabs->show();
+ 
+-    foreach( const MenuItem &item , subMenus ) {
++	foreach( const MenuItem &item , subMenus ) {
+ 		if( item.menu ) {
+ 			modulesScroller = new QScrollArea(moduleTabs);
+ 
+-            modulesScroller->setFrameStyle( QFrame::NoFrame );
++			modulesScroller->setFrameStyle( QFrame::NoFrame );
+ 
+ 			modulesScroller->setWidgetResizable(true);
+ 			ModulesView *modulesView = new ModulesView( menu, item.subMenu, modulesScroller );
+@@ -187,7 +187,7 @@
+ 
+ 	// Now it's time to draw our display
+ 	foreach( const MenuItem &item , menu->menuList() ) {
+-        	if( item.menu ) {
++		if( item.menu ) {
+ 			KServiceGroup::Ptr group = KServiceGroup::group( item.subMenu );
+ 			if ( !group ){
+ 				kDebug() << "Invalid Group \"" << item.subMenu << "\".  Check your installation.";
+@@ -364,11 +364,11 @@
+ 	} else {
+ 		
+ 		if(length>=1) {
+-			generalHitLabel->setText(i18np("%1 hit in General","%1 hits in General",hitList[1]));
++			generalHitLabel->setText(i18np("%1 hit in General","%1 hits in General",hitList[0]));
+ 		}
+ 	
+ 		if(length>=2) {
+-			advancedHitLabel->setText(i18np("%1 hit in Advanced","%1 hits in Advanced",hitList[0]));
++			advancedHitLabel->setText(i18np("%1 hit in Advanced","%1 hits in Advanced",hitList[1]));
+ 		}
+ 
+ 	}
+--- a/systemsettings/kcmodulemenu.h
++++ b/systemsettings/kcmodulemenu.h
+@@ -77,7 +77,8 @@
+  */
+ class MenuItem {
+ public:
+-	MenuItem( bool isMenu=false ){ menu = isMenu; }	
++	MenuItem( bool isMenu=false ){ menu = isMenu; }
++	bool operator<(const MenuItem& rhs) const;
+ 	bool menu;
+ 	QString subMenu;
+ 	QString caption;
+--- a/klipper/klipper-kde31.sh
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#!/bin/sh
+-filename=`kde4-config --localprefix`share/autostart/klipper.desktop
+-if grep 'Hidden=true' "$filename" > /dev/null 2> /dev/null; then
+-  echo AutoStart=false
+-else
+-  echo AutoStart=true
+-fi
+-rm -f "$filename"
+--- a/klipper/klipperbindings.cpp
++++ /dev/null
+@@ -1,42 +0,0 @@
+-// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
+-/* This file is part of the KDE project
+-   Copyright (C) by Andrew Stanley-Jones
+-
+-   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 NOSLOTS
+-# define DEF( name, key, fnSlot ) \
+-   a = actionCollection->addAction( name );                        \
+-   a->setText( i18n(name) );                                       \
+-   qobject_cast<KAction*>( a )->setGlobalShortcut(KShortcut(key)); \
+-   connect(a, SIGNAL(triggered(bool)), SLOT(fnSlot))
+-#else
+-# define DEF( name, key, fnSlot ) \
+-   a = actionCollection->addAction( name );             \
+-   a->setText( i18n(name) );                            \
+-   qobject_cast<KAction*>( a )->setGlobalShortcut(KShortcut(key));
+-#endif
+-
+-        a = actionCollection->addAction( "Program:klipper" );
+-        a->setText( i18n("Clipboard") );
+-
+-	DEF( I18N_NOOP("Show Klipper Popup-Menu"), Qt::ALT+Qt::CTRL+Qt::Key_V, slotPopupMenu() );
+-
+-        DEF( I18N_NOOP("Manually Invoke Action on Current Clipboard"), Qt::ALT+Qt::CTRL+Qt::Key_R, slotRepeatAction() );
+-	DEF( I18N_NOOP("Enable/Disable Clipboard Actions"), Qt::ALT+Qt::CTRL+Qt::Key_X, toggleURLGrabber() );
+-
+-#undef DEF
+--- a/klipper/klipper-1-2.pl
++++ /dev/null
+@@ -1,63 +0,0 @@
+-#!/usr/bin/perl
+-
+-my ($section, %data);
+-
+-#read in all the data, split it up into hashes. Thanks again to malte for much input
+-while (<>) {
+-	if (/\[(.*)\]/) {
+-		$sections{$section} = {%data} if $section;
+-		$section = $1;
+-		undef %data;
+-		next;
+- 	}
+-	$data{$1} = $2 if /^([^=]*)=(.*)$/;
+-}
+-
+-$sections{$section} = {%data} if $section;
+-
+-# not used up to now
+-# $version = $sections{'General'}->{'Version'};
+-
+-# if "Action description" is not available, we have a new, fresh configuration
+-# without any need for conversion.
+-if ( ! $sections{'Action_0'}->{'Action description'} ) {
+-    exit;
+-}
+-
+-$numActions = $sections{'General'}->{'Number of Actions'};
+-for my $i (0..($numActions - 1)) {
+-    my $actionGroup = "Action_$i";
+-    my $numCommands = $sections{$actionGroup}->{'Number of commands'};
+-
+-    print "[$actionGroup]\n";
+-    # rename some keys
+-    print "Description=$sections{$actionGroup}->{'Action description'}\n";
+-    print "Regexp=$sections{$actionGroup}->{'Action regexp'}\n";
+-    print "Number of commands=$numCommands\n";
+-
+-    # move the command entries from "Action_x" to "Action_x/Command_y"
+-    for my $k (0..($numCommands - 1)) {
+-	my $command = "Command_$k";
+-	my $commandGroup = "$actionGroup/$command";
+-	print "\n[$commandGroup]\n";
+-	my $value = $sections{$actionGroup}->{"$command: commandline"};
+-	print "Commandline=$value\n";
+-	$value = $sections{$actionGroup}->{"$command: description"};
+-	print "Description=$value\n";
+-	$value = $sections{$actionGroup}->{"$command: enabled"};
+-	print "Enabled=$value\n";
+-    }
+-    print "\n";
+-}
+-
+-&copySection( "General" );
+-&copySection( "Global Keys" );
+-
+-sub copySection()
+-{
+-    my ($group) = @_;
+-    print "\n[$group]\n";
+-    while (($key,$value) = each(%{$sections{$group}})) {
+-	print "$key=$value\n";
+-    }
+-}
+--- a/klipper/klipperrc.upd
++++ /dev/null
+@@ -1,7 +0,0 @@
+-Id=25082001
+-File=klipperrc
+-Script=klipper-1-2.pl,perl
+-Id=kde3.1
+-File=klipperrc
+-Group=General
+-Script=klipper-kde31.sh,sh
+--- a/klipper/klippershortcuts.upd
++++ /dev/null
+@@ -1,5 +0,0 @@
+-Id=04112002
+-File=klipperrc,kdeglobals
+-Group=Global Shortcuts
+-AllKeys
+-RemoveGroup=Global Shortcuts
+--- a/klipper/klipperpopup.h
++++ b/klipper/klipperpopup.h
+@@ -17,14 +17,13 @@
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+ */
+-#ifndef _KLIPPERPOPUP_H_
+-#define _KLIPPERPOPUP_H_
++#ifndef KLIPPERPOPUP_H
++#define KLIPPERPOPUP_H
+ 
+-#include <kmenu.h>
+-#include <Qt3Support/Q3PtrList>
++#include <QList>
++#include <QWidgetAction>
+ 
+-//Added by qt3to4:
+-#include <QKeyEvent>
++#include <kmenu.h>
+ 
+ class History;
+ class KHelpMenu;
+@@ -96,7 +95,7 @@
+     /**
+      * (unowned) actions to plug into the primary popup menu
+      */
+-    Q3PtrList<QAction> m_actions;
++    QList<QAction*> m_actions;
+ 
+     /**
+      * Proxy helper object used to track history items
+@@ -109,9 +108,9 @@
+     KLineEdit* m_filterWidget;
+ 
+     /**
+-     * id of search widget, for convenience
++     * Action of search widget
+      */
+-    int m_filterWidgetId;
++    QWidgetAction *m_filterWidgetAction;
+ 
+     /**
+      * The current number of history items in the clipboard
+--- a/klipper/history.cpp
++++ b/klipper/history.cpp
+@@ -31,12 +31,12 @@
+       m_topIsUserSelected( false )
+ {
+     connect( this, SIGNAL( changed() ), m_popup, SLOT( slotHistoryChanged() ) );
+-    itemList.setAutoDelete( true );
+ 
+ }
+ 
+ 
+ History::~History() {
++    qDeleteAll(itemList);
+ }
+ 
+ History::iterator History::youngest() {
+@@ -85,14 +85,10 @@
+     if ( !newItem )
+         return;
+ 
+-    for ( const HistoryItem* item = itemList.first(); item; item=next() ) {
+-        if ( *item == *newItem ) {
+-            itemList.remove();
+-            emit changed();
+-            return;
+-        }
++    if (itemList.contains(newItem)) {
++        itemList.removeAll(newItem);
++        emit changed();
+     }
+-
+ }
+ 
+ 
+@@ -101,20 +97,20 @@
+     emit changed();
+ }
+ 
+-void History::slotMoveToTop(int pos ) {
+-    if ( pos < 0 || static_cast<unsigned>( pos ) >= itemList.count() ) {
++void History::slotMoveToTop(QAction *action) {
++    bool ok = false;
++    int pos = action->data().toInt(&ok);
++    if (!ok) // not an action from popupproxy
++        return;
++
++    if ( pos < 0 || pos >= itemList.count() ) {
+         kDebug() << "Argument pos out of range: " << pos;
+         return;
+     }
+ 
+     m_topIsUserSelected = true;
+ 
+-    itemList.first();
+-    for ( ; pos; pos-- ) {
+-        itemList.next();
+-    }
+-    HistoryItem* item = itemList.take();
+-    itemList.prepend( item );
++    itemList.move(pos, 0);
+     emit changed();
+     emit topChanged();
+ }
+--- a/klipper/historyurlitem.cpp
++++ b/klipper/historyurlitem.cpp
+@@ -19,9 +19,7 @@
+ */
+ #include "historyurlitem.h"
+ 
+-#include <k3multipledrag.h>
+-#include <k3urldrag.h>
+-#include <Qt3Support/Q3CString>
++#include <QMimeData>
+ 
+ HistoryURLItem::HistoryURLItem( const KUrl::List &_urls, KUrl::MetaDataMap _metaData, bool _cut )
+     : urls( _urls ), metaData( _metaData ), cut( _cut )
+--- a/klipper/popupproxy.cpp
++++ b/klipper/popupproxy.cpp
+@@ -42,6 +42,7 @@
+       nextItemNumber( 0 )
+ {
+     connect( parent->history(), SIGNAL( changed() ), SLOT( slotHistoryChanged() ) );
++    connect(proxy_for_menu, SIGNAL(triggered(QAction*)), parent->history(), SLOT(slotMoveToTop(QAction*)));
+ }
+ 
+ void PopupProxy::slotHistoryChanged() {
+@@ -87,33 +88,35 @@
+                                 int& remainingHeight,
+                                 const int index )
+ {
+-
+-    // Insert item
+-    int id = -1;
++    QAction *action = new QAction(this);
+     QPixmap image( item->image() );
+     if ( image.isNull() ) {
+         // Squeeze text strings so that do not take up the entire screen (or more)
+         QString text = proxy_for_menu->fontMetrics().elidedText( item->text().simplified(), Qt::ElideMiddle, m_menu_width );
+         text.replace( "&", "&&" );
+-        id = proxy_for_menu->insertItem( text, -1, index );
++        action->setText(text);
+     } else {
+         const QSize max_size( m_menu_width,m_menu_height/4 );
+         if ( image.height() > max_size.height() || image.width() > max_size.width() ) {
+             image = image.scaled( max_size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+         }
+-        id = proxy_for_menu->insertItem( image, -1, index );
++        action->setIcon(QIcon(image));
+     }
+ 
++    action->setData(nextItemNumber);
++
++    proxy_for_menu->insertAction(proxy_for_menu->actions().at(index), action);
+ 
+     // Determine height of a menu item.
++
++    int itemheight = QFontMetrics(proxy_for_menu->fontMetrics()).height();
++
++//TODO Use old-style QStyle and QStyleOption API
++#if 0
+     Q_ASSERT( id != -1 ); // Be sure that the item was inserted.
+     QMenuItem* mi = proxy_for_menu->findItem( id );
+-    int fontheight = QFontMetrics( proxy_for_menu->fontMetrics()  ).height();
+-#ifdef __GNUC__
+-#warning Use old-style QStyle and QStyleOption API
+-#endif    
+-    int itemheight = fontheight;
+-#if 0
++
++
+     int itemheight = proxy_for_menu->style().sizeFromContents(QStyle::CT_PopupMenuItem,
+                                                               proxy_for_menu,
+                                                               QSize( 0, fontheight ),
+@@ -121,12 +124,6 @@
+ #endif
+     // Test if there was enough space
+     remainingHeight -= itemheight;
+-    History* history = parent()->history();
+-    proxy_for_menu->connectItem(  id,
+-                                  history,
+-                                  SLOT( slotMoveToTop( int ) ) );
+-    proxy_for_menu->setItemParameter(  id, nextItemNumber );
+-
+ }
+ 
+ int PopupProxy::insertFromSpill( int index ) {
+@@ -142,23 +139,25 @@
+     int remainingHeight = m_menu_height - proxy_for_menu->sizeHint().height();
+     // Force at least one item to be inserted.
+     remainingHeight = qMax( remainingHeight, 0 );
+-    for ( const HistoryItem* item = spillPointer.current();
+-          item && remainingHeight >= 0;
+-          nextItemNumber++, item = ++spillPointer )
+-    {
++
++    while (spillPointer.hasNext() && remainingHeight >= 0) {
++        const HistoryItem *item = spillPointer.next();
+         if ( m_filter.indexIn( item->text() ) == -1) {
+             continue;
+         }
+         tryInsertItem( item, remainingHeight, index++ );
+         count++;
++        nextItemNumber++;
+     }
+ 
+     // If there is more items in the history, insert a new "More..." menu and
+     // make *this a proxy for that menu ('s content).
+-    if ( spillPointer.current() ) {
++    if (spillPointer.hasNext()) {
+         KMenu* moreMenu = new KMenu( proxy_for_menu );
+-        proxy_for_menu->insertItem( i18n( "&More" ), moreMenu, -1, index );
+-        connect( moreMenu, SIGNAL( aboutToShow() ), SLOT( slotAboutToShow() ) );
++        QAction *menuAction = new QAction(i18n("&More"), this);
++        menuAction->setMenu(moreMenu);
++        connect(moreMenu, SIGNAL(aboutToShow()), SLOT(slotAboutToShow()));
++        proxy_for_menu->insertAction(proxy_for_menu->actions().at(index), menuAction);
+         proxy_for_menu = moreMenu;
+     }
+ 
+--- a/klipper/history.h
++++ b/klipper/history.h
+@@ -18,11 +18,12 @@
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+ */
+-#ifndef _HISTORY_H_
+-#define _HISTORY_H_
++#ifndef HISTORY_H
++#define HISTORY_H
++
++#include <QAction>
++#include <QList>
+ 
+-#include <QObject>
+-#include <Qt3Support/Q3PtrList>
+ #include "historyitem.h"
+ 
+ class KlipperPopup;
+@@ -36,7 +37,7 @@
+     /**
+      * Iterator for history
+      */
+-    typedef Q3PtrListIterator<HistoryItem> iterator;
++    typedef QListIterator<const HistoryItem*> iterator;
+ 
+     /**
+      * Return (toplevel) popup menu (or default view, of you like)
+@@ -70,11 +71,6 @@
+     const HistoryItem* first();
+ 
+     /**
+-     * Traversal: Get current item
+-     */
+-    const HistoryItem* next();
+-
+-    /**
+      * Get an iterator pointing to the first (most recent) item
+      * This iterator should probably be a constant iterator, but
+      * the QTL doesn't support this easily.
+@@ -112,7 +108,7 @@
+     /**
+      * move the history in position pos to top
+      */
+-    void slotMoveToTop(int pos );
++    void slotMoveToTop(QAction *action);
+ 
+     /**
+      * Clear history
+@@ -132,7 +128,7 @@
+     /**
+      * The history
+      */
+-    Q3PtrList<HistoryItem> itemList;
++    QList<const HistoryItem*> itemList;
+ 
+     /**
+      * ensure that the number of items does not exceed max_size()
+@@ -161,6 +157,4 @@
+ 
+ inline const HistoryItem* History::first() { return itemList.first(); }
+ 
+-inline const HistoryItem* History::next() { return itemList.next();  }
+-
+ #endif
+--- a/klipper/klipper.cpp
++++ b/klipper/klipper.cpp
+@@ -22,41 +22,20 @@
+ */
+ 
+ #include <QClipboard>
+-#include <QCursor>
+-#include <QDateTime>
+-#include <QFile>
+-#include <QPainter>
+-
+-#include <QtGui/QMacMime>
+-#include <Qt3Support/Q3ColorDrag>
+-#include <QPaintEvent>
+-#include <QMouseEvent>
+-#include <QX11Info>
++#include <QtDBus/QDBusConnection>
+ 
+ #include <kaboutdata.h>
+-#include <kaction.h>
+-#include <kapplication.h>
+-#include <kconfig.h>
+-#include <kglobal.h>
+-#include <kicon.h>
+ #include <klocale.h>
+ #include <kmessagebox.h>
+ #include <ksavefile.h>
+ #include <ksessionmanager.h>
+ #include <kstandarddirs.h>
+-#include <kstringhandler.h>
+ #include <ksystemtrayicon.h>
+-#include <k3urldrag.h>
+-#include <kwindowsystem.h>
+ #include <kdebug.h>
+ #include <kglobalsettings.h>
+-#include <QtDBus/QDBusConnection>
+-#include <kiconloader.h>
+-#include <khelpmenu.h>
+-#include <kstandardguiitem.h>
+ #include <kactioncollection.h>
+ #include <ktoggleaction.h>
+-#include <kconfiggroup.h>
++#include <KConfigSkeleton>
+ 
+ #include "configdialog.h"
+ #include "klipper.h"
+@@ -73,6 +52,8 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xatom.h>
+ 
++//#define NOISY_KLIPPER
++
+ namespace {
+     /**
+      * Use this when manipulating the clipboard
+@@ -151,7 +132,7 @@
+ 
+     // we need that collection, otherwise KToggleAction is not happy :}
+     //QString defaultGroup( "default" );
+-    KActionCollection *collection = new KActionCollection( this );
++    collection = new KActionCollection( this );
+     toggleURLGrabAction = new KToggleAction( this );
+     collection->addAction( "toggleUrlGrabAction", toggleURLGrabAction );
+     toggleURLGrabAction->setEnabled( true );
+@@ -159,8 +140,8 @@
+     clearHistoryAction = collection->addAction( "clearHistoryAction" );
+     clearHistoryAction->setIcon( KIcon("history-clear") );
+     clearHistoryAction->setText( i18n("C&lear Clipboard History") );
+-    connect(clearHistoryAction, SIGNAL(triggered(bool) ), history(), SLOT( slotClear() ));
+-    connect( clearHistoryAction, SIGNAL( activated() ), SLOT( slotClearClipboard() ) );
++    connect(clearHistoryAction, SIGNAL(triggered() ), history(), SLOT( slotClear() ));
++    connect( clearHistoryAction, SIGNAL( triggered() ), SLOT( slotClearClipboard() ) );
+     //clearHistoryAction->setGroup( defaultGroup );
+     configureAction = collection->addAction( "configureAction" );
+     configureAction->setIcon( KIcon("configure") );
+@@ -187,19 +168,22 @@
+     connect( poll, SIGNAL( clipboardChanged( bool ) ),
+              this, SLOT( newClipData( bool ) ) );
+ 
+-    m_pixmap = KSystemTrayIcon::loadIcon( "klipper" ).pixmap();
++    QAction *a = collection->addAction("show_klipper_popup");
++    a->setText(i18n("Show Klipper Popup-Menu"));
++    qobject_cast<KAction*>(a)->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_V));
++    connect(a, SIGNAL(triggered()), SLOT(slotPopupMenu()));
++
++    a = collection->addAction("repeat_action");
++    a->setText(i18n("Manually Invoke Action on Current Clipboard"));
++    qobject_cast<KAction*>(a)->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_R));
++    connect(a, SIGNAL(triggered()), SLOT(slotRepeatAction()));
++
++    a = collection->addAction("clipboard_action");
++    a->setText(i18n("Enable/Disable Clipboard Actions"));
++    qobject_cast<KAction*>(a)->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_X));
++    connect(a, SIGNAL(triggered()), SLOT(toggleURLGrabber()));
+ 
+-    globalKeys = KGlobalAccel::self();
+-    KActionCollection* actionCollection = collection;
+-    QAction* a = 0L;
+-#ifdef __GNUC__
+-#warning TODO PORT ME (KGlobalAccel related)
+-#endif
+-#include "klipperbindings.cpp"
+-    // the keys need to be read from kdeglobals, not kickerrc --ellis, 22/9/02
+-    //globalKeys->readSettings();
+-    //globalKeys->updateConnections();
+-    //toggleURLGrabAction->setShortcut(globalKeys->shortcut("Enable/Disable Clipboard Actions"));
++    toggleURLGrabAction->setShortcut(qobject_cast<KAction*>(collection->action("clipboard_action"))->globalShortcut());
+ 
+     connect( toggleURLGrabAction, SIGNAL( toggled( bool )),
+              this, SLOT( setURLGrabberEnabled( bool )));
+@@ -388,9 +372,13 @@
+     QByteArray data;
+     QDataStream history_stream( &data, QIODevice::WriteOnly );
+     history_stream << klipper_version; // const char*
+-    for (  const HistoryItem* item = history()->first(); item; item = history()->next() ) {
++
++    History::iterator it = history()->youngest();
++    while (it.hasNext()) {
++        const HistoryItem *item = it.next();
+         history_stream << item;
+     }
++
+     quint32 crc = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() );
+     QDataStream ds ( &history_file );
+     ds << crc << data;
+@@ -476,12 +464,7 @@
+ void Klipper::slotSettingsChanged( int category )
+ {
+     if ( category == (int) KGlobalSettings::SETTINGS_SHORTCUTS ) {
+-#ifdef __GNUC__
+-#warning TODO PORT ME (KGlobalAccel related)
+-#endif
+-        //globalKeys->readSettings();
+-        //globalKeys->updateConnections();
+-        //toggleURLGrabAction->setShortcut(globalKeys->shortcut("Enable/Disable Clipboard Actions"));
++        toggleURLGrabAction->setShortcut(qobject_cast<KAction*>(collection->action("clipboard_action"))->globalShortcut());
+     }
+ }
+ 
+@@ -502,8 +485,7 @@
+         readConfiguration( m_config.data() );
+     }
+ 
+-    ConfigDialog *dlg = new ConfigDialog( myURLGrabber->actionList(),
+-                                          globalKeys, isApplet() );
++    ConfigDialog *dlg = new ConfigDialog( 0, new KConfigSkeleton(), myURLGrabber->actionList(), collection, isApplet() );
+     dlg->setKeepContents( bKeepContents );
+     dlg->setPopupAtMousePos( bPopupAtMouse );
+     dlg->setStripWhiteSpace( myURLGrabber->trimmed() );
+@@ -525,12 +507,8 @@
+         bSynchronize = dlg->synchronize();
+         bUseGUIRegExpEditor = dlg->useGUIRegExpEditor();
+         dlg->commitShortcuts();
+-#ifdef __GNUC__
+-#warning TODO PORT ME (KGlobalAccel related)
+-#endif
+-        //globalKeys->writeSettings();
+-        //globalKeys->updateConnections();
+-        //toggleURLGrabAction->setShortcut(globalKeys->shortcut("Enable/Disable Clipboard Actions"));
++
++        toggleURLGrabAction->setShortcut(qobject_cast<KAction*>(collection->action("clipboard_action"))->globalShortcut());
+ 
+         myURLGrabber->setActionList( dlg->actionList() );
+         myURLGrabber->setPopupTimeout( dlg->popupTimeout() );
+@@ -557,7 +535,9 @@
+     }
+ 
+     saveSession();
+-    int autoStart = KMessageBox::questionYesNoCancel( 0L, i18n("Should Klipper start automatically\nwhen you login?"), i18n("Automatically Start Klipper?"),KGuiItem(i18n("Start")), KGuiItem(i18n("Do Not Start")) );
++    int autoStart = KMessageBox::questionYesNoCancel(0, i18n("Should Klipper start automatically when you login?"),
++                                                     i18n("Automatically Start Klipper?"), KGuiItem(i18n("Start")),
++                                                     KGuiItem(i18n("Do Not Start")), KStandardGuiItem::cancel(), "StartAutomatically");
+ 
+     KConfigGroup config( KGlobal::config(), "General");
+     if ( autoStart == KMessageBox::Yes ) {
+@@ -736,9 +716,15 @@
+ //   while the user is doing a selection using the mouse, OOo stops updating the clipboard
+ //   contents, so in practice it's like the user has selected only the part which was
+ //   selected when Klipper asked first.
+-	Qt::ButtonState buttonstate = QApplication::mouseButtons();
+-    if( ( buttonstate & ( Qt::ShiftModifier | Qt::LeftButton )) == Qt::ShiftModifier // #85198
+-        || ( buttonstate & Qt::LeftButton ) == Qt::LeftButton ) { // #80302
++// Use XQueryPointer rather than QApplication::mouseButtons()/keyboardModifiers(), because
++//   Klipper needs the very current state.
++    Window root, child;
++    int root_x, root_y, win_x, win_y;
++    uint state;
++    XQueryPointer( QX11Info::display(), QX11Info::appRootWindow(), &root, &child,
++                   &root_x, &root_y, &win_x, &win_y, &state );
++    if( ( state & ( ShiftMask | Button1Mask )) == ShiftMask // #85198
++        || ( state & Button1Mask ) == Button1Mask ) { // #80302
+         m_pendingContentsCheck = true;
+         m_pendingCheckTimer.start( 100 );
+         return true;
+@@ -834,7 +820,7 @@
+     if ( selectionMode && bIgnoreSelection )
+         return;
+ 
+-    if( selectionMode && bSelectionTextOnly && data->hasText())
++    if( selectionMode && bSelectionTextOnly && !data->hasText())
+         return;
+ 
+ #ifdef __GNUC__
+@@ -944,18 +930,25 @@
+ QStringList Klipper::getClipboardHistoryMenu()
+ {
+     QStringList menu;
+-    for ( const HistoryItem* item = history()->first(); item; item = history()->next() ) {
++
++    History::iterator it = history()->youngest();
++    while (it.hasNext()) {
++        const HistoryItem *item = it.next();
+         menu << item->text();
+     }
++
+     return menu;
+ }
+ 
+ QString Klipper::getClipboardHistoryItem(int i)
+ {
+-    for ( const HistoryItem* item = history()->first(); item; item = history()->next() , i-- ) {
++    History::iterator it = history()->youngest();
++    while (it.hasNext()) {
++        const HistoryItem *item = it.next();
+         if ( i == 0 ) {
+             return item->text();
+         }
++        i--;
+     }
+     return QString();
+ 
+--- a/klipper/klipper.h
++++ b/klipper/klipper.h
+@@ -18,24 +18,20 @@
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+ */
+-#ifndef _KLIPPER_H_
+-#define _KLIPPER_H_
++#ifndef KLIPPER_H
++#define KLIPPER_H
+ 
+-#include <kapplication.h>
+-#include <kglobalaccel.h>
+-#include <kmenu.h>
+-#include <QMap>
+-#include <QPixmap>
+-//Added by qt3to4:
+-#include <QMouseEvent>
+-#include <QPaintEvent>
++#include <QKeyEvent>
++#include <QMenu>
+ #include <QTimer>
+-#include <kglobal.h>
+-#include <kconfig.h>
++
++#include <KApplication>
++#include <KIcon>
+ 
+ class QClipboard;
+ class KToggleAction;
+ class KAboutData;
++class KActionCollection;
+ class URLGrabber;
+ class ClipboardPoll;
+ class QTime;
+@@ -62,8 +58,6 @@
+     Klipper(QObject *parent, const KSharedConfigPtr &config);
+     ~Klipper();
+ 
+-    KGlobalAccel *globalKeys;
+-
+     /**
+      * Get clipboard history (the "document")
+      */
+@@ -207,6 +201,7 @@
+ 
+     bool blockFetchingNewData();
+     KlipperSessionManager* session_managed;
++    KActionCollection *collection;
+ };
+ 
+ #endif
+--- a/klipper/historyitem.cpp
++++ b/klipper/historyitem.cpp
+@@ -17,14 +17,11 @@
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+ */
+-#include <QtGui/QMacMime>
+-#include <Qt3Support/Q3ColorDrag>
+ #include <QMap>
+ 
+ #include <QPixmap>
+ 
+ #include <kdebug.h>
+-#include <k3urldrag.h>
+ 
+ #include "historyitem.h"
+ #include "historystringitem.h"
+--- a/klipper/klipperrc.desktop
++++ b/klipper/klipperrc.desktop
+@@ -676,7 +676,7 @@
+ Description[en_GB]=Launch &Mutt
+ Description[eo]=Lanĉi poŝtilon "&Mutt"
+ Description[es]=Iniciar &mutt
+-Description[et]=&Mutt'i käivitamine
++Description[et]=&Mutti käivitamine
+ Description[eu]=Abiarazi &mutt 
+ Description[fa]=راه‌اندازی &mutt‌
+ Description[fi]=Käynistä &Mutt
+@@ -895,7 +895,7 @@
+ Description[ja]=KWrite を起動(&W)
+ Description[ka]=K&Write-ის გაშვება
+ Description[kk]=K&Write-ты жегу
+-Description[km]=ចាប់ផ្ដើម  KWrite
++Description[km]=ចាប់ផ្ដើម KWrite
+ Description[lt]=Paleisti K&Write
+ Description[lv]=Palaist K&Write
+ Description[mk]=Стартувај K&Write
+@@ -1145,7 +1145,7 @@
+ Description[de]=Gopher-Adresse (URL)
+ Description[eo]=Gofer-URL
+ Description[es]=URL de Gopher
+-Description[et]=Gopher'i URL
++Description[et]=Gopheri URL
+ Description[eu]=Gopher URLa
+ Description[fa]=نشانی وب گوفر
+ Description[fr]=URL Gopher
+--- a/klipper/historyimageitem.cpp
++++ b/klipper/historyimageitem.cpp
+@@ -18,9 +18,7 @@
+    Boston, MA 02110-1301, USA.
+ */
+ 
+-
+-//Added by qt3to4:
+-#include <QPixmap>
++#include <QMimeData>
+ 
+ #include <kdebug.h>
+ 
+--- a/klipper/configdialog.cpp
++++ b/klipper/configdialog.cpp
+@@ -42,30 +42,26 @@
+ 
+ #include "configdialog.h"
+ 
+-ConfigDialog::ConfigDialog( const ActionList *list, KGlobalAccel *accel,
+-                            bool isApplet )
+-    : KPageDialog()
+-{
+-    setFaceType( Tabbed );
+-    setCaption( i18n("Configure") );
+-    setButtons( Ok | Cancel | Help );
+-
++ConfigDialog::ConfigDialog(QWidget *parent, KConfigSkeleton *skeleton, const ActionList *list, KActionCollection *collection,
++                           bool isApplet)
++    : KConfigDialog(parent, "preferences", skeleton)
++{
+     if ( isApplet )
+         setHelp( QString(), "klipper" );
+ 
+-    KVBox *w = 0L; // the parent for the widgets
++    QWidget *w = 0; // the parent for the widgets
+ 
+-    w = new KVBox( this );
+-    generalWidget = new GeneralWidget( w, "general widget" );
+-    addPage( w, i18n("&General") );
+-
+-    w = new KVBox( this );
+-    actionWidget = new ActionWidget( list, this, w, "actions widget" );
+-    addPage( w, i18n("Ac&tions") );
+-
+-    w = new KVBox( this );
+-    shortcutsWidget = new KShortcutsEditor( w, KShortcutsEditor::GlobalAction );
+-    addPage( w, i18n("&Shortcuts") );
++    w = new QWidget(this);
++    generalWidget = new GeneralWidget(w);
++    addPage(generalWidget, i18nc("General Config", "General"), "klipper", i18n("General Config"));
++
++    w = new QWidget(this);
++    actionWidget = new ActionWidget( list, this, w);
++    addPage(actionWidget, i18nc("Actions Config", "Actions"), "configure", i18n("Actions Config"));
++
++    w = new QWidget(this);
++    shortcutsWidget = new KShortcutsEditor( collection, w, KShortcutsEditor::GlobalAction );
++    addPage(shortcutsWidget, i18nc("Shortcuts Config", "Shortcuts"), "configure-shortcuts", i18n("Shortcuts Config"));
+ }
+ 
+ 
+@@ -100,10 +96,9 @@
+ ////
+ 
+ 
+-GeneralWidget::GeneralWidget( QWidget *parent, const char *name )
++GeneralWidget::GeneralWidget( QWidget *parent )
+     : KVBox( parent )
+ {
+-    setObjectName(name);
+     setSpacing(KDialog::spacingHint());
+ 
+     cbMousePos = new QCheckBox( i18n("&Popup menu at mouse-cursor position"),
+@@ -227,13 +222,10 @@
+ }
+ 
+ 
+-ActionWidget::ActionWidget( const ActionList *list, ConfigDialog* configWidget, QWidget *parent,
+-                            const char *name )
++ActionWidget::ActionWidget( const ActionList *list, ConfigDialog* configWidget, QWidget *parent )
+     : KVBox( parent ),
+       advancedWidget( 0L )
+ {
+-    setObjectName(name);
+-
+     Q_ASSERT( list != 0L );
+ 
+     QLabel *lblAction = new QLabel(
+@@ -274,13 +266,15 @@
+     const QPixmap& doc = SmallIcon( "misc" );
+     const QPixmap& exec = SmallIcon( "exec" );
+ 
+-    for ( action = it.current(); action; action = ++it ) {
++    while (it.hasNext()) {
++        action = it.next();
+         item = new Q3ListViewItem( listView, after,
+                                   action->regExp(), action->description() );
+         item->setPixmap( 0, doc );
+ 
+-        Q3PtrListIterator<ClipCommand> it2( action->commands() );
+-        for ( command = it2.current(); command; command = ++it2 ) {
++        QListIterator<ClipCommand*> it2( action->commands() );
++        while (it2.hasNext()) {
++            command = it2.next();
+             child = new Q3ListViewItem( item, after,
+                                        command->command, command->description);
+         if ( command->pixmap.isEmpty() )
+@@ -310,8 +304,9 @@
+     connect( delActionButton, SIGNAL( clicked() ), SLOT( slotDeleteAction() ));
+ 
+     QLabel *label = new QLabel(i18n("Click on a highlighted item's column to change it. \"%s\" in a command will be replaced with the clipboard contents."), box);
+-    label->setAlignment( Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignVCenter );
+-
++    label->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
++    label->setWordWrap( true );
++    
+     box->setStretchFactor( label, 5 );
+ 
+     box = new KHBox( this );
+@@ -393,7 +388,6 @@
+     Q3ListViewItem *child = 0L;
+     ClipAction *action = 0L;
+     ActionList *list = new ActionList;
+-    list->setAutoDelete( true );
+     while ( item ) {
+         action = new ClipAction( item->text( 0 ), item->text( 1 ) );
+         child = item->firstChild();
+@@ -432,11 +426,9 @@
+     }
+ }
+ 
+-AdvancedWidget::AdvancedWidget( QWidget *parent, const char *name )
++AdvancedWidget::AdvancedWidget( QWidget *parent )
+     : KVBox( parent )
+ {
+-    setObjectName(name);
+-
+     editListBox = new KEditListBox( i18n("D&isable Actions for Windows of Type WM_CLASS"), this, "editlistbox", true, KEditListBox::Add | KEditListBox::Remove );
+ 
+     editListBox->setWhatsThis(
+--- a/klipper/urlgrabber.cpp
++++ b/klipper/urlgrabber.cpp
+@@ -18,13 +18,12 @@
+    Boston, MA 02110-1301, USA.
+ */
+ 
+-#include <cstdlib>
++#include <netwm.h>
+ 
+-#include <QCursor>
+-#include <QHash>
+ #include <QTimer>
++#include <QX11Info>
++#include <QUuid>
+ 
+-#include <kapplication.h>
+ #include <kconfig.h>
+ #include <kdialog.h>
+ #include <ktextedit.h>
+@@ -32,23 +31,15 @@
+ #include <kmenu.h>
+ #include <kprocess.h>
+ #include <kservice.h>
+-#include <kiconloader.h>
+ #include <kdebug.h>
+-#include <netwm.h>
+ #include <kstringhandler.h>
+ #include <kmacroexpander.h>
++#include <kglobal.h>
+ 
+ #include "urlgrabber.h"
+-#include <QX11Info>
+-#include <kglobal.h>
+ 
+ // TODO:
+ // - script-interface?
+-// - Bug in KMenu::clear() (insertTitle() doesn't go away sometimes)
+-
+-#define URL_EDIT_ITEM 10
+-#define DO_NOTHING_ITEM 11
+-#define DISABLE_POPUP 12
+ 
+ URLGrabber::URLGrabber(const KSharedConfigPtr &config)
+  : m_config( config )
+@@ -62,8 +53,6 @@
+     m_trimmed = true;
+ 
+     myActions = new ActionList();
+-    myActions->setAutoDelete( true );
+-    myMatches.setAutoDelete( false );
+ 
+     readConfiguration( m_config.data() );
+ 
+@@ -94,7 +83,10 @@
+ 
+ URLGrabber::~URLGrabber()
+ {
++    if (myMenu)
++        delete myMenu;
+     delete myActions;
++    qDeleteAll(myMatches);
+ }
+ 
+ //
+@@ -104,7 +96,7 @@
+ void URLGrabber::invokeAction( const QString& clip )
+ {
+     if ( !clip.isEmpty() )
+-	myClipData = clip;
++        myClipData = clip;
+     if ( m_trimmed )
+         myClipData = myClipData.trimmed();
+ 
+@@ -123,8 +115,10 @@
+ {
+     myMatches.clear();
+     ClipAction *action = 0L;
++
+     ActionListIterator it( *myActions );
+-    for ( action = it.current(); action; action = ++it ) {
++    while (it.hasNext()) {
++        action = it.next();
+         if ( action->matches( clipData ) )
+             myMatches.append( action );
+     }
+@@ -159,8 +153,8 @@
+     ClipAction *action = 0L;
+     ClipCommand *command = 0L;
+ 
+-    if ( it.count() > 0 ) {
+-	// don't react on konqi's/netscape's urls...
++    if (it.hasNext()) {
++        // don't react on konqi's/netscape's urls...
+         if ( wm_class_check && isAvoidedWindow() )
+             return;
+ 
+@@ -168,28 +162,34 @@
+         myCommandMapper.clear();
+ 
+         myPopupKillTimer->stop();
+-        delete myMenu;
++
+         myMenu = new KMenu;
+-        connect( myMenu, SIGNAL( activated( int )),
+-                 SLOT( slotItemSelected( int )));
+ 
+-        for ( action = it.current(); action; action = ++it ) {
+-            Q3PtrListIterator<ClipCommand> it2( action->commands() );
+-            if ( it2.count() > 0 )
+-                myMenu->addTitle( SmallIcon( "klipper" ), action->description() +
+-				     i18n(" - Actions For: ") +
+-				     KStringHandler::csqueeze(myClipData, 45));
+-            for ( command = it2.current(); command; command = ++it2 ) {
++        connect(myMenu, SIGNAL(triggered(QAction*)), SLOT(slotItemSelected(QAction*)));
++
++        while (it.hasNext()) {
++            action = it.next();
++            QListIterator<ClipCommand*> it2( action->commands() );
++            if ( it2.hasNext() )
++                myMenu->addTitle(KIcon( "klipper" ), action->description() +
++                                 i18n(" - Actions For: ") +
++                                 KStringHandler::csqueeze(myClipData, 45));
++            while (it2.hasNext()) {
++                command = it2.next();
+                 item = command->description;
+                 if ( item.isEmpty() )
+                     item = command->command;
+ 
+-                int id;
+-                if ( command->pixmap.isEmpty() )
+-                    id = myMenu->insertItem( item );
+-                else
+-                    id = myMenu->insertItem( SmallIcon(command->pixmap), item);
+-                myCommandMapper.insert( id, command );
++                QString id = QUuid::createUuid().toString();
++                QAction * action = new QAction(this);
++                action->setData(id);
++                action->setText(item);
++
++                if (!command->pixmap.isEmpty())
++                    action->setIcon(KIcon(command->pixmap));
++
++                myCommandMapper.insert(id, command);
++                myMenu->addAction(action);
+             }
+         }
+ 
+@@ -198,13 +198,19 @@
+         if ( wm_class_check )
+         {
+             myMenu->addSeparator();
+-            myMenu->insertItem( i18n( "Disable This Popup" ), DISABLE_POPUP );
++            QAction *disableAction = new QAction(i18n("Disable This Popup"), this);
++            connect(disableAction, SIGNAL(triggered()), SLOT(editData()));
++            myMenu->addAction(disableAction);
+         }
+         myMenu->addSeparator();
+         // add an edit-possibility
+-        myMenu->insertItem( SmallIcon("edit"), i18n("&Edit Contents..."),
+-                            URL_EDIT_ITEM );
+-        myMenu->insertItem( KIcon("cancel"), i18n("&Cancel"), DO_NOTHING_ITEM );
++        QAction *editAction = new QAction(KIcon("edit"), i18n("&Edit Contents..."), this);
++        connect(editAction, SIGNAL(triggered()), SLOT(editData()));
++        myMenu->addAction(editAction);
++
++        QAction *cancelAction = new QAction(KIcon("dialog-cancel"), i18n("&Cancel"), this);
++        connect(cancelAction, SIGNAL(triggered()), myMenu, SLOT(hide()));
++        myMenu->addAction(cancelAction);
+ 
+         if ( myPopupKillTimeout > 0 )
+             myPopupKillTimer->start( 1000 * myPopupKillTimeout );
+@@ -214,27 +220,24 @@
+ }
+ 
+ 
+-void URLGrabber::slotItemSelected( int id )
++void URLGrabber::slotItemSelected(QAction *action)
+ {
+     myMenu->hide(); // deleted by the timer or the next action
+ 
+-    switch ( id ) {
+-    case -1:
+-    case DO_NOTHING_ITEM:
+-        break;
+-    case URL_EDIT_ITEM:
+-        editData();
+-        break;
+-    case DISABLE_POPUP:
+-	emit sigDisablePopup();
+-	break;
+-    default:
+-        ClipCommand *command = myCommandMapper.find( id );
+-        if ( !command )
+-            qWarning("Klipper: cannot find associated action");
+-        else
+-            execute( command );
++    QString id = action->data().toString();
++
++    if (id.isEmpty()) {
++        kDebug() << "Klipper: no command associated";
++        return;
+     }
++
++    QHash<QString, ClipCommand*>::iterator i = myCommandMapper.find(id);
++    ClipCommand *command = i.value();
++
++    if (command)
++        execute(command);
++    else
++        kDebug() << "Klipper: cannot find associated action";
+ }
+ 
+ 
+@@ -251,7 +254,7 @@
+         KProcess proc;
+         proc.setShellCommand(cmdLine.trimmed());
+         if (!proc.startDetached())
+-            qWarning("Klipper: Could not start process!");
++            kDebug() << "Klipper: Could not start process!";
+     }
+ }
+ 
+@@ -272,16 +275,14 @@
+     dlg->adjustSize();
+ 
+     if ( dlg->exec() == KDialog::Accepted ) {
+-        myClipData = edit->text();
+-        delete dlg;
++        myClipData = edit->toPlainText();
+         QTimer::singleShot( 0, this, SLOT( slotActionMenu() ) );
+     }
+     else
+     {
+-        delete dlg;
+-        myMenu->deleteLater();
+-        myMenu = 0L;
++        delete myMenu;
+     }
++    delete dlg;
+ }
+ 
+ 
+@@ -314,11 +315,11 @@
+ 
+     int i = 0;
+     QString group;
+-    while ( (action = it.current()) ) {
++    while (it.hasNext()) {
++        action = it.next();
+         group = QString("Action_%1").arg( i );
+         action->save( kc, group );
+         ++i;
+-        ++it;
+     }
+ }
+ 
+@@ -357,7 +358,7 @@
+                             &unused, &data_ret ) == Success) {
+         if ( type_ret == XA_STRING && format_ret == 8 && nitems_ret > 0 ) {
+             wmClass = QString::fromUtf8( (const char *) data_ret );
+-            ret = (myAvoidWindows.find( wmClass ) != myAvoidWindows.end());
++            ret = (myAvoidWindows.indexOf( wmClass ) != -1);
+         }
+ 
+         XFree( data_ret );
+@@ -380,7 +381,6 @@
+     }
+ 
+     delete myMenu;
+-    myMenu = 0L;
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////
+@@ -412,20 +412,18 @@
+ ClipAction::ClipAction( const QString& regExp, const QString& description )
+     : myRegExp( regExp ), myDescription( description )
+ {
+-    myCommands.setAutoDelete( true );
+ }
+ 
+ 
+ ClipAction::ClipAction( const ClipAction& action )
+ {
+-    myCommands.setAutoDelete( true );
+     myRegExp      = action.myRegExp;
+     myDescription = action.myDescription;
+ 
+     ClipCommand *command = 0L;
+-    Q3PtrListIterator<ClipCommand> it( myCommands );
+-    for ( ; it.current(); ++it ) {
+-        command = it.current();
++    QListIterator<ClipCommand*> it( myCommands );
++    while (it.hasNext()) {
++        command = it.next();
+         addCommand(command->command, command->description, command->isEnabled);
+     }
+ }
+@@ -437,7 +435,6 @@
+ {
+     KConfigGroup cg(kc, group);
+ 
+-    myCommands.setAutoDelete( true );
+     int num = cg.readEntry( "Number of commands", 0 );
+ 
+     // read the commands
+@@ -455,6 +452,7 @@
+ 
+ ClipAction::~ClipAction()
+ {
++    qDeleteAll(myCommands);
+ }
+ 
+ 
+@@ -479,11 +477,12 @@
+     cg.writeEntry( "Number of commands", myCommands.count() );
+ 
+     struct ClipCommand *cmd;
+-    Q3PtrListIterator<struct ClipCommand> it( myCommands );
++    QListIterator<struct ClipCommand*> it( myCommands );
+ 
+     // now iterate over all commands of this action
+     int i = 0;
+-    while ( (cmd = it.current()) ) {
++    while (it.hasNext()) {
++        cmd = it.next();
+         QString _group = group + "/Command_%1";
+         KConfigGroup cg(kc, _group.arg(i));
+ 
+@@ -492,7 +491,6 @@
+         cg.writeEntry( "Enabled", cmd->isEnabled );
+ 
+         ++i;
+-        ++it;
+     }
+ }
+ 
+--- a/klipper/historyimageitem.h
++++ b/klipper/historyimageitem.h
+@@ -18,12 +18,10 @@
+    Boston, MA 02110-1301, USA.
+ */
+ 
+-#ifndef _HISTORYIMAGEITEM_H_
+-#define _HISTORYIMAGEITEM_H_
++#ifndef HISTORYIMAGEITEM_H
++#define HISTORYIMAGEITEM_H
+ 
+ #include "historyitem.h"
+-#include <QPixmap>
+-#include <Qt3Support/Q3ColorDrag>
+ 
+ /**
+  * A image entry in the clipboard history.
+--- a/klipper/configdialog.h
++++ b/klipper/configdialog.h
+@@ -30,10 +30,11 @@
+ #include <k3listview.h>
+ #include <knuminput.h>
+ #include <kvbox.h>
++#include <KConfigDialog>
+ 
+ #include "urlgrabber.h"
+ 
+-class KGlobalAccel;
++class KConfigSkeleton;
+ class KShortcutsEditor;
+ class K3ListView;
+ class QPushButton;
+@@ -47,7 +48,7 @@
+     friend class ConfigDialog;
+ 
+ public:
+-    GeneralWidget( QWidget *parent, const char *name );
++    GeneralWidget( QWidget *parent );
+     ~GeneralWidget();
+ 
+ private Q_SLOTS:
+@@ -69,7 +70,7 @@
+     Q_OBJECT
+ 
+ public:
+-    explicit AdvancedWidget( QWidget *parent = 0L, const char *name = 0L );
++    explicit AdvancedWidget( QWidget *parent = 0L );
+     ~AdvancedWidget();
+ 
+     void setWMClasses( const QStringList& items );
+@@ -86,7 +87,7 @@
+     friend class ConfigDialog;
+ 
+ public:
+-    ActionWidget( const ActionList *list, ConfigDialog* configWidget, QWidget *parent, const char *name );
++    ActionWidget( const ActionList *list, ConfigDialog* configWidget, QWidget *parent );
+     ~ActionWidget();
+ 
+     /**
+@@ -130,12 +131,12 @@
+ };*/
+ 
+ 
+-class ConfigDialog : public KPageDialog
++class ConfigDialog : public KConfigDialog
+ {
+     Q_OBJECT
+ 
+ public:
+-    ConfigDialog( const ActionList *list, KGlobalAccel *accel, bool isApplet );
++    ConfigDialog( QWidget *parent, KConfigSkeleton *config, const ActionList *list, KActionCollection *collection, bool isApplet );
+     ~ConfigDialog();
+ 
+     ActionList * actionList() const { return actionWidget->actionList(); }
+--- a/klipper/klipperpopup.cpp
++++ b/klipper/klipperpopup.cpp
+@@ -19,16 +19,11 @@
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+ */
+-#include <kmessagebox.h>
++
+ #include <khelpmenu.h>
+-#include <kiconloader.h>
+ #include <klineedit.h>
+-
+ #include <klocale.h>
+-#include <kaction.h>
+-#include <kglobalsettings.h>
+ #include <kwindowsystem.h>
+-#include <kapplication.h>
+ #include <kdebug.h>
+ 
+ #include "klipperpopup.h"
+@@ -45,16 +40,16 @@
+ #ifdef DEBUG_EVENTS__
+ kdbgstream& operator<<( kdbgstream& stream, const QKeyEvent& e ) {
+     stream << "(QKeyEvent(text=" << e.text() << ",key=" << e.key() << ( e.isAccepted()?",accepted":",ignored)" ) << ",count=" << e.count();
+-    if ( e.state() & Qt::AltModifier ) {
++    if ( e.modifiers() & Qt::AltModifier ) {
+         stream << ",ALT";
+     }
+-    if ( e.state() & Qt::ControlModifier ) {
++    if ( e.modifiers() & Qt::ControlModifier ) {
+         stream << ",CTRL";
+     }
+-    if ( e.state() & Qt::MetaModifier ) {
++    if ( e.modifiers() & Qt::MetaModifier ) {
+         stream << ",META";
+     }
+-    if ( e.state() & Qt::ShiftModifier ) {
++    if ( e.modifiers() & Qt::ShiftModifier ) {
+         stream << ",SHIFT";
+     }
+     if ( e.isAutoRepeat() ) {
+@@ -73,10 +68,6 @@
+  */
+ class KLineEditBlackKey : public KLineEdit {
+ public:
+-    KLineEditBlackKey(const QString& string, QWidget* parent )
+-        : KLineEdit( string, parent )
+-        {}
+-
+     KLineEditBlackKey( QWidget* parent )
+         : KLineEdit( parent )
+         {}
+@@ -100,7 +91,7 @@
+       helpmenu( new KHelpMenu( this, Klipper::aboutData(), false ) ),
+       m_popupProxy( 0 ),
+       m_filterWidget( 0 ),
+-      m_filterWidgetId( 10 ),
++      m_filterWidgetAction( 0 ),
+       n_history_items( 0 )
+ {
+     KWindowInfo i = KWindowSystem::windowInfo( winId(), NET::WMGeometry );
+@@ -123,8 +114,7 @@
+         if ( !m_filterWidget->text().isEmpty() ) {
+             m_dirty = true;
+             m_filterWidget->clear();
+-            setItemVisible( m_filterWidgetId, false );
+-            m_filterWidget->hide();
++            m_filterWidgetAction->setVisible(false);
+         }
+     }
+     ensureClean();
+@@ -141,99 +131,82 @@
+ }
+ 
+ void KlipperPopup::buildFromScratch() {
+-    m_filterWidget = new KLineEditBlackKey( this );
+-    addTitle( SmallIcon( "klipper" ), i18n("Klipper - Clipboard Tool"));
+-#ifdef __GNUC__
+-#warning "KlipperPopup::buildFromScratch, insertItem does not take a QWidget as first parameter"
+-#endif
+-#if 0
+-    m_filterWidgetId = insertItem( m_filterWidget, m_filterWidgetId, 1 );
+-#endif
++    addTitle(KIcon("klipper"), i18n("Klipper - Clipboard Tool"));
++
++    m_filterWidget = new KLineEditBlackKey(this);
++    m_filterWidgetAction = new QWidgetAction(this);
++    m_filterWidgetAction->setDefaultWidget(m_filterWidget);
++
++    addAction(m_filterWidgetAction);
+     m_filterWidget->setFocusPolicy( Qt::NoFocus );
+-    setItemVisible( m_filterWidgetId, false );
+-    m_filterWidget->hide();
+-    QString lastGroup;
+-
+-    // Bit of a hack here. It would be better of KHelpMenu could be an action.
+-    //    Insert Help-menu at the butttom of the "default" group.
+-    QString group;
+-    QString defaultGroup( "default" );
+-    for ( QAction* action = m_actions.first(); action; action = m_actions.next() ) {
+-#ifdef __GNUC__
+-#warning no more group() in action, this hack needs to be revised
+-#endif
+-        //group = action->group();
+-        if ( group != lastGroup ) {
+-            if ( lastGroup == defaultGroup ) {
+-                insertItem( KIcon("help-contents"), KStandardGuiItem::help().text(), helpmenu->menu() );
+-            }
++    m_filterWidgetAction->setVisible(false);
++
++    QListIterator<QAction *> i(m_actions);
++    for (int i = 0; i < m_actions.count(); i++) {
++        if (i == 0)
++            addSeparator();
++
++        if (i + 1 == m_actions.count()) {
++            addMenu(helpmenu->menu())->setIcon(KIcon("help-contents"));
+             addSeparator();
+         }
+-        lastGroup = group;
+-        addAction(action);
++
++        addAction(m_actions.at(i));
+     }
+ 
+     if ( KGlobalSettings::insertTearOffHandle() ) {
+-        insertTearOffHandle();
++        setTearOffEnabled(true);
+     }
+ 
+ }
+ 
+ void KlipperPopup::rebuild( const QString& filter ) {
+-
+-    bool from_scratch = ( count() == 0 );
+-    if ( from_scratch ) {
++    if (actions().isEmpty()) {
+         buildFromScratch();
+     } else {
+         for ( int i=0; i<n_history_items; i++ ) {
+-            removeItemAt( TOP_HISTORY_ITEM_INDEX );
++            if (i < actions().count())
++                removeAction(actions().at(TOP_HISTORY_ITEM_INDEX));
+         }
+     }
+ 
+     QRegExp filterexp( filter );
+-    QPalette palette;
++    QPalette palette = m_filterWidget->palette();
+     if ( filterexp.isValid() ) {
+         palette.setColor( m_filterWidget->foregroundRole(), palette.color(foregroundRole()) );
+     } else {
+         palette.setColor( m_filterWidget->foregroundRole(), Qt::red );
+     }
+-    m_filterWidget->setPalette( palette );
+     n_history_items = m_popupProxy->buildParent( TOP_HISTORY_ITEM_INDEX, filterexp );
+-
+     if ( n_history_items == 0 ) {
+         if ( m_history->empty() ) {
+-            insertItem( QSempty, -1, TOP_HISTORY_ITEM_INDEX  );
++            insertAction(actions().at(TOP_HISTORY_ITEM_INDEX), new QAction(QSempty, this));
+         } else {
+-            insertItem( QSnomatch, -1, TOP_HISTORY_ITEM_INDEX );
++            palette.setColor( m_filterWidget->foregroundRole(), Qt::red );
++            insertAction(actions().at(TOP_HISTORY_ITEM_INDEX), new QAction(QSnomatch, this));
+         }
+         n_history_items++;
+     } else {
+         if ( history()->topIsUserSelected() ) {
+-            int id = idAt( TOP_HISTORY_ITEM_INDEX );
+-            if ( id != -1 ) {
+-                setItemChecked( id,true );
+-            }
++            actions().at(TOP_HISTORY_ITEM_INDEX)->setCheckable(true);
++            actions().at(TOP_HISTORY_ITEM_INDEX)->setChecked(true);
+         }
+     }
+-
+-
++    m_filterWidget->setPalette( palette );
+     m_dirty = false;
+-
+ }
+ 
+ void KlipperPopup::plugAction( QAction* action ) {
+-    m_actions.append( action );
++    m_actions.append(action);
+ }
+ 
+ 
+-
+-
+ /* virtual */
+ void KlipperPopup::keyPressEvent( QKeyEvent* e ) {
+     // If alt-something is pressed, select a shortcut
+     // from the menu. Do this by sending a keyPress
+     // without the alt-modifier to the superobject.
+-    if ( e->state() & Qt::AltModifier ) {
++    if ( e->modifiers() & Qt::AltModifier ) {
+         QKeyEvent ke( QEvent::KeyPress,
+                       e->key(),
+                       e->modifiers() ^ Qt::AltModifier,
+@@ -242,9 +215,9 @@
+                       e->count() );
+         KMenu::keyPressEvent( &ke );
+ #ifdef DEBUG_EVENTS__
+-        kDebug() << "Passing this event to ancestor (KMenu): " << e "->" << ke;
++        kDebug() << "Passing this event to ancestor (KMenu): " << e << "->" << ke;
+ #endif
+-        if ( ke.isAccepted() ) {
++        if (ke.isAccepted()) {
+             e->accept();
+             return;
+         } else {
+@@ -269,15 +242,10 @@
+ #ifdef DEBUG_EVENTS__
+         kDebug() << "Passing this event to ancestor (KMenu): " << e;
+ #endif
+-        KMenu::keyPressEvent( e );
+-        if ( isItemActive( m_filterWidgetId ) ) {
+-#ifdef __GNUC__
+-#warning setActiveItem do not exist in Q3PopupMenu class
+-#endif
+-#if 0
+-            setActiveItem( TOP_HISTORY_ITEM_INDEX );
+-#endif
+-        }
++        KMenu::keyPressEvent(e);
++        if (activeAction() ==  m_filterWidgetAction)
++            setActiveAction(actions().at(TOP_HISTORY_ITEM_INDEX));
++
+         break;
+     }
+     default:
+@@ -285,32 +253,25 @@
+ #ifdef DEBUG_EVENTS__
+         kDebug() << "Passing this event down to child (KLineEdit): " << e;
+ #endif
+-	QString lastString = m_filterWidget->text();
+-        QApplication::sendEvent( m_filterWidget, e );
+-        if ( m_filterWidget->text().isEmpty() ) {
+-            if ( isItemVisible( m_filterWidgetId ) )
+-            {
+-                setItemVisible( m_filterWidgetId, false );
+-                m_filterWidget->hide();
+-            }
++        setActiveAction(actions().at(actions().indexOf(m_filterWidgetAction)));
++        QString lastString = m_filterWidget->text();
++        QApplication::sendEvent(m_filterWidget, e);
++
++        if (m_filterWidget->text().isEmpty()) {
++            if (m_filterWidgetAction->isVisible())
++                m_filterWidgetAction->setVisible(false);
+         }
+-        else if ( !isItemVisible( m_filterWidgetId ) )
+-        {
+-            setItemVisible( m_filterWidgetId, true );
+-            m_filterWidget->show();
++        else if (!m_filterWidgetAction->isVisible() )
++            m_filterWidgetAction->setVisible(true);
+ 
+-        }
+-	if ( m_filterWidget->text() != lastString) {
++        if (m_filterWidget->text() != lastString) {
+             slotHistoryChanged();
+-            rebuild( m_filterWidget->text() );
+-	}
+-        break;
++            rebuild(m_filterWidget->text());
++        }
+ 
++        break;
+     } //default:
+     } //case
+-
+ }
+ 
+-
+-
+ #include "klipperpopup.moc"
+--- a/klipper/CMakeLists.txt
++++ b/klipper/CMakeLists.txt
+@@ -1,39 +1,34 @@
+-
+ KDE4_NO_ENABLE_FINAL(klipper)
+-include_directories(
+-   ${KDEBASE_WORKSPACE_SOURCE_DIR}/kicker/libkicker/ )
+-
+-########### next target ###############
+-
+-add_definitions (-DQT3_SUPPORT)
+ 
+-########### next target ###############
+-
+-set(libklipper_common_SRCS klipper.cpp urlgrabber.cpp configdialog.cpp clipboardpoll.cpp history.cpp historyitem.cpp historystringitem.cpp klipperpopup.cpp popupproxy.cpp  historyimageitem.cpp historyurlitem.cpp )
++add_definitions(-DQT3_SUPPORT -DQT3_SUPPORT_WARNINGS)
+ 
++set(libklipper_common_SRCS
++    klipper.cpp
++    urlgrabber.cpp
++    configdialog.cpp
++    clipboardpoll.cpp
++    history.cpp
++    historyitem.cpp
++    historystringitem.cpp
++    klipperpopup.cpp
++    popupproxy.cpp
++    historyimageitem.cpp
++    historyurlitem.cpp
++)
+ 
+ set(klipper_KDEINIT_SRCS ${libklipper_common_SRCS} main.cpp tray.cpp)
+ 
++kde4_add_kdeinit_executable(klipper ${klipper_KDEINIT_SRCS})
+ 
+-kde4_add_kdeinit_executable( klipper ${klipper_KDEINIT_SRCS})
+-
+-target_link_libraries(kdeinit_klipper  ${KDE4_KDE3SUPPORT_LIBS}  )
++target_link_libraries(kdeinit_klipper ${KDE4_KDE3SUPPORT_LIBS})
+ if (X11_Xfixes_FOUND)
+   target_link_libraries(kdeinit_klipper ${X11_Xfixes_LIB})
+ endif (X11_Xfixes_FOUND)
+ 
+-install(TARGETS kdeinit_klipper  DESTINATION ${LIB_INSTALL_DIR} )
++install(TARGETS kdeinit_klipper DESTINATION ${LIB_INSTALL_DIR})
+ 
+-target_link_libraries( klipper kdeinit_klipper )
+-install(TARGETS klipper DESTINATION ${BIN_INSTALL_DIR})
++target_link_libraries(klipper kdeinit_klipper)
+ 
+-########### install files ###############
+-
+-install(FILES klipper.desktop  DESTINATION  ${XDG_APPS_INSTALL_DIR})
++install(TARGETS klipper DESTINATION ${BIN_INSTALL_DIR})
++install(FILES klipper.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
+ install(FILES klipper.desktop DESTINATION ${AUTOSTART_INSTALL_DIR})
+-install(FILES klipperrc.upd klippershortcuts.upd  DESTINATION  ${KCONF_UPDATE_INSTALL_DIR})
+-install(PROGRAMS klipper-1-2.pl klipper-kde31.sh DESTINATION  ${KCONF_UPDATE_INSTALL_DIR})
+-
+-
+-kde4_install_icons( ${ICON_INSTALL_DIR}  )
+-
+--- a/klipper/urlgrabber.h
++++ b/klipper/urlgrabber.h
+@@ -20,14 +20,11 @@
+ #ifndef URLGRABBER_H
+ #define URLGRABBER_H
+ 
+-#include <Qt3Support/Q3PtrList>
+-#include <Qt3Support/Q3IntDict>
++#include <QHash>
+ #include <QRegExp>
+ 
+-
+ #include <kconfig.h>
+ 
+-
+ class QTimer;
+ 
+ class KConfig;
+@@ -35,8 +32,8 @@
+ 
+ class ClipAction;
+ struct ClipCommand;
+-typedef Q3PtrList<ClipAction> ActionList;
+-typedef Q3PtrListIterator<ClipAction> ActionListIterator;
++typedef QList<ClipAction*> ActionList;
++typedef QListIterator<ClipAction*> ActionListIterator;
+ 
+ class URLGrabber : public QObject
+ {
+@@ -68,11 +65,10 @@
+ 
+   bool trimmed() const { return m_trimmed; }
+   void setStripWhiteSpace( bool enable ) { m_trimmed = enable; }
+-    
++
+ private:
+   const ActionList& matchingActions( const QString& );
+   void execute( const struct ClipCommand *command ) const;
+-  void editData();
+   bool isAvoidedWindow() const;
+   void actionMenu( bool wm_class_check );
+ 
+@@ -81,7 +77,7 @@
+   QStringList myAvoidWindows;
+   QString myClipData;
+   ClipAction *myCurrentAction;
+-  Q3IntDict<ClipCommand> myCommandMapper;
++  QHash<QString, ClipCommand*> myCommandMapper;
+   KMenu *myMenu;
+   QTimer *myPopupKillTimer;
+   int myPopupKillTimeout;
+@@ -90,8 +86,9 @@
+ 
+ private Q_SLOTS:
+   void slotActionMenu() { actionMenu( true ); }
+-  void slotItemSelected( int );
++  void slotItemSelected(QAction *action);
+   void slotKillPopupMenu();
++  void editData();
+ 
+ 
+ Q_SIGNALS:
+@@ -108,7 +105,6 @@
+     QString description;
+     bool isEnabled;
+     QString pixmap;
+-    //  int id; // the index reflecting the position in the list of commands
+ };
+ 
+ /**
+@@ -139,7 +135,7 @@
+   void clearCommands() { myCommands.clear(); }
+ 
+   void  addCommand( const QString& command, const QString& description, bool, const QString& icon = "" );
+-  const Q3PtrList<ClipCommand>& commands() 	const { return myCommands; }
++  const QList<ClipCommand*>& commands() 	const { return myCommands; }
+ 
+   /**
+    * Saves this action to a a given KConfig object
+@@ -150,7 +146,7 @@
+ private:
+   QRegExp 		myRegExp;
+   QString 		myDescription;
+-  Q3PtrList<ClipCommand> 	myCommands;
++  QList<ClipCommand*> 	myCommands;
+ 
+ };
+ 
+--- a/solid/control/backends/fakebluetooth/solid_fakebluetooth.desktop
++++ b/solid/control/backends/fakebluetooth/solid_fakebluetooth.desktop
+@@ -11,6 +11,7 @@
+ Name[csb]=Falszëwi Bluetooth
+ Name[de]=Bluetooth (Dummy)
+ Name[el]=Πλαστό Bluetooth
++Name[et]=Liba-Bluetooth
+ Name[fa]=بلوتوث جعلی
+ Name[he]=‏Bluetooth מזוייף
+ Name[ja]=疑似 Bluetooth
+@@ -35,6 +36,7 @@
+ Comment[csb]=Sprôwianié falszëwim Bluetoothã
+ Comment[de]=Bluetooth-Verwaltung (Dummy)
+ Comment[el]=Διαχείριση πλαστού Bluetooth
++Comment[et]=Liba-Bluetoothi haldur
+ Comment[fa]=مدیریت بلوتوث جعلی
+ Comment[he]=ניהול Bluetooth מזוייף
+ Comment[it]=Gestione di un falso Bluetooth
+--- a/solid/control/backends/fakenet/solid_fakenet.desktop
++++ b/solid/control/backends/fakenet/solid_fakenet.desktop
+@@ -10,6 +10,7 @@
+ Name[csb]=Falszëwô séc
+ Name[de]=Netzwerk (Dummy)
+ Name[el]=Πλαστό δίκτυο
++Name[et]=Liba-võrk
+ Name[fa]=شبکۀ جعلی
+ Name[he]=רשת מזוייפת
+ Name[ja]=疑似ネット
+@@ -34,6 +35,7 @@
+ Comment[csb]=Sprôwianié falszëwą sécą
+ Comment[de]=Netzwerkverwaltung (Dummy)
+ Comment[el]=Διαχειριστής πλαστού δικτύου
++Comment[et]=Liba-võrgu haldur
+ Comment[fa]=مدیریت شبکۀ جعلی
+ Comment[he]=ניהול רשת מזוייף
+ Comment[it]=Gestione di una falsa rete
+--- a/solid/control/solid/control/solidnetworkmanager.desktop
++++ b/solid/control/solid/control/solidnetworkmanager.desktop
+@@ -8,6 +8,7 @@
+ Comment[bg]=Заден слой за управление на мрежа
+ Comment[de]=Backend zur Netzwerkverwaltung
+ Comment[el]=Σύστημα διαχείρισης δικτύου
++Comment[et]=Võrgu haldamise taustaprogramm
+ Comment[fa]=پایانۀ پشتیبانی مدیریت شبکه
+ Comment[he]=ממשק ניהול רשת
+ Comment[ja]=ネットワーク管理のバックエンド
+--- a/solid/control/solid/control/solidpowermanager.desktop
++++ b/solid/control/solid/control/solidpowermanager.desktop
+@@ -9,11 +9,12 @@
+ Comment[de]=Backend zur Energieverwaltung
+ Comment[el]=Σύστημα διαχείρισης ενέργειας
+ Comment[es]=Motor de la gestión de energía
++Comment[et]=Voolutarbe haldamise taustaprogramm
+ Comment[fa]=پایانۀ پشتیبانی مدیریت توان
+ Comment[he]=ממשק ניהול צריכת חשמל
+ Comment[ja]=電源管理のバックエンド
+ Comment[kk]=Қуаттандыруды басқару тетігі
+-Comment[km]=ការ​គ្រប់គ្រង​ថាមពល​កម្មវិធី​ខាងក្រោយ
++Comment[km]=ការ​គ្រប់គ្រង​ថាមពល​កម្មវិធី​ខាង​ក្រោយ
+ Comment[ko]=전력 관리 백엔드
+ Comment[nb]=Bakgrunnsmotor for strømstyring
+ Comment[nds]=Hülpprogramm för de Stroomkuntrull
+--- a/solid/control/solid/control/solidbluetoothmanager.desktop
++++ b/solid/control/solid/control/solidbluetoothmanager.desktop
+@@ -8,6 +8,7 @@
+ Comment[bg]=Заден слой за управление на Bluetooth
+ Comment[de]=Backend zur Bluetooth-Verwaltung
+ Comment[el]=Σύστημα διαχείρισης Bluetooth
++Comment[et]=Bluetoothi haldamise taustaprogramm
+ Comment[fa]=پایانۀ پشتیبانی مدیریت بلوتوث
+ Comment[he]=ממשק ניהול Bluetooth
+ Comment[ja]=Bluetooth 管理のバックエンド
+--- a/solid/bluez/solid_bluez.desktop
++++ b/solid/bluez/solid_bluez.desktop
+@@ -12,6 +12,7 @@
+ Comment[bg]=Bluetooth с BlueZ
+ Comment[de]=Bluetooth-Verwaltung mit Hilfe von Bluez
+ Comment[el]=Διαχείριση bluetooth με χρήση της στοίβας BlueZ
++Comment[et]=Bluetoothi haldamine BlueZi pinuga
+ Comment[fa]=مدیریت بلوتوث با استفاده از پشته BlueZ
+ Comment[he]=ניהול Bluetooth באמצעות מחסנית BlueZ
+ Comment[ja]=BlueZ スタックによる Bluetooth 管理
+--- a/solid/solidshell/main.cpp
++++ b/solid/solidshell/main.cpp
+@@ -399,7 +399,7 @@
+ 
+       cout << "  solidshell network set network 'device-uni' 'network-uni' [authentication 'key']" << endl;
+       cout << i18n("             # Activate the network 'network-uni' on 'device-uni'.\n"
+-                    "             # Optionally, use WEP128, open-system encryption with hex key 'key'. (Hardcoded)"
++                    "             # Optionally, use WEP128, open-system encryption with hex key 'key'. (Hardcoded)\n"
+                     "             # Where 'authentication' is one of:\n"
+                     "             # wep hex64|ascii64|hex128|ascii128|passphrase64|passphrase128 'key' [open|shared]\n"
+                     "             # wpapsk wpa|wpa2 tkip|ccmp-aes password\n"
+--- a/solid/hal/solid_hal_power.desktop
++++ b/solid/hal/solid_hal_power.desktop
+@@ -25,6 +25,7 @@
+ Comment[de]=Energieverwaltung mit Hilfe des HAL-Dienstes von freedesktop.org
+ Comment[el]=Διαχείριση ενέργειας υλικού με χρήση του δαίμονα HAL του freedesktop.org
+ Comment[es]=Gestión de energía del hardware usando el servicio HAL de freedesktop.org
++Comment[et]=Riistvara voolutarbe haldamine freedesktop.org-i HAL-deemoni abil
+ Comment[fa]=مدیریت توان سخت‌افزار با استفاده از شبح freedesktop.org HAL
+ Comment[he]=ניהול צריכת החשמל של החומרה בעזרת שירות HAL של freedesktop.org
+ Comment[ja]=freedesktop.org の HAL デーモンを用いたハードウェア電源管理
+--- a/solid/networkmanager/solid_networkmanager.desktop
++++ b/solid/networkmanager/solid_networkmanager.desktop
+@@ -10,6 +10,7 @@
+ Name[csb]=Menadżer logòwaniô
+ Name[de]=Netzwerkverwaltung
+ Name[el]=Διαχειριστής δικτύου
++Name[et]=Võrguhaldur
+ Name[km]=កម្មវិធី​គ្រប់គ្រង​បណ្តាញ​
+ Name[nb]=Nettverksstyring
+ Name[nds]=Nettwark-Pleger
+@@ -30,6 +31,7 @@
+ Comment[de]=Netzwerkverwaltung mit dem Netzwerkverwaltungs-Dienst
+ Comment[el]=Διαχείριση δικτύου με χρήση του δαίμονα HAL του freedesktop.org
+ Comment[es]=Gestión de red usando el servicio NetworkManager
++Comment[et]=Võrgu haldamine NetworkManageri deemoni abil
+ Comment[fa]=مدیریت شبکه با استفاده از شبح NetworkManager
+ Comment[he]=ניהול הרשת באמצעות השירות NetworkManager
+ Comment[ja]=NetworkManager デーモンを用いたネットワーク管理
+--- a/solid/networking/kded/networkstatus.desktop
++++ b/solid/networking/kded/networkstatus.desktop
+@@ -6,6 +6,7 @@
+ Name[de]=Netzwerkstatus-Dienst
+ Name[el]=Δαίμονας κατάστασης δικτύου
+ Name[es]=Servicio del estado de red
++Name[et]=Võrguoleku deemon
+ Name[fa]=شبح وضعیت شبکه
+ Name[he]=צג מצב הרשת
+ Name[it]=Demone dello stato della rete
+@@ -30,11 +31,12 @@
+ Comment[bg]=Проверява състоянието на мрежата и изпраща уведомление на програмите в мрежата
+ Comment[de]=Überprüft den Status von Netzwerkschnittstellen und benachrichtigt Programme, die das Netzwerk verwenden.
+ Comment[el]=Παρακολουθεί την κατάσταση των διασυνδέσεων δικτύου και προσφέρει ειδοποιήσεις σε εφαρμογές που χρησιμοποιούν το δίκτυο.
++Comment[et]=Võrguliideste oleku jälgimine ja märguannete edastamine rakendustele võrgu vahendusel.
+ Comment[fa]=وضعیت واسطهای شبکه را ردیابی کرده و با استفاده از شبکه برای کاربرد، اخطار فراهم می‌کند.
+ Comment[he]=עוקב אחר מצב ממשקי רשת ומספק עידכונים לתוכניות שמשתמשות ברשת
+ Comment[ja]=ネットワークインターフェースの状態を追跡し、ネットワークを使うアプリケーションに情報を提供します。
+ Comment[kk]=Желі интерфейстерінің күйін қадағалап желісін пайдаланатын қолданбаларды құлақтандырады.
+-Comment[km]=តាម​ដាន​ស្ថានភាព​ចំណុច​ប្រទាក់​បណ្តាញ និង​ផ្តល់​នូវ​សេចក្តី​ជូន​ដំណឹង​ទៅ​កម្មវិធី​ដោយ​ប្រើ​បណ្តាញ ។
++Comment[km]=តាម​ដាន​ស្ថានភាពរបស់​​ចំណុច​ប្រទាក់​បណ្តាញ និង​ផ្តល់​នូវ​សេចក្តី​ជូន​ដំណឹង​ទៅ​កម្មវិធី​ដោយ​ប្រើ​បណ្តាញ ។
+ Comment[ko]=네트워크 인터페이스의 상태를 추적하고 네트워크를 사용하는 프로그램에게 알려 줍니다.
+ Comment[lt]=Seka tinklo sąsajų būseną ir informuoja apie jas programas, naudojančias tinklą
+ Comment[nb]=Holder øye med status for nettverks-grensesnitt og varsler programmer som bruker nettverket.
+--- a/solid/kcm/kcm_solid.desktop
++++ b/solid/kcm/kcm_solid.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kcm_solid
++Exec=kcmshell4 kcm_solid
+ Icon=preferences-system-solid
+ Type=Service
+ ServiceTypes=KCModule
+@@ -27,6 +27,7 @@
+ Comment[de]=Einrichtung zur Hardware-Einbindung
+ Comment[el]=Ρυθμίσεις ενσωμάτωσης υλικού
+ Comment[es]=Configuración de la integración del hardware
++Comment[et]=Riistvara lõimimise seadistamine
+ Comment[fa]=پیکربندی مجتمع‌سازی سخت‌افزار
+ Comment[he]=הגדרות שילוב חומרה
+ Comment[it]=Configurazione dell'integrazione hardware
+@@ -54,12 +55,13 @@
+ Keywords[de]=Solid,Hardware,Energie,Netzwerk,Discovery,Management,Verwaltung,Erkennung
+ Keywords[el]=Solid,Υλικό,Hardware,Ενέργεια,Power,Δίκτυο,Network,Εντοπισμός,Discovery,Διαχείριση,Management
+ Keywords[es]=Solid,Hardware,Energía,Red,Detección,Gestión
++Keywords[et]=Solid,riistvara,voolutarve,võrg,tuvastamine,haldamine
+ Keywords[fa]=Solid، سخت‌افزار، توان، شبکه، اکتشاف، مدیریت
+ Keywords[ga]=Solid,Crua-earraí,Cumhacht,Líonra,Fionnachtain,Bainistíocht
+ Keywords[he]=Solid,Hardware,Power,Network,Discovery,Management,חומרה,צריכת חשמל,רשת,גילוי,ניהול
+ Keywords[it]=Solid,Hardware,Power,Network,Discovery,Management,Rete,Gestione,Esplorazione,Scoperta
+ Keywords[ja]=Solid,ハードウェア,電源,ネットワーク,ディスカバリ,発見,管理
+-Keywords[km]=តាន់,ផ្នែករឹង,ថាមពល,បណ្តាញ,ការ​រក​ឃើញ,ការ​គ្រប់គ្រង
++Keywords[km]=តាន់ ផ្នែករឹង ថាមពល បណ្តាញ ការ​រក​ឃើញ ការ​គ្រប់គ្រង
+ Keywords[ko]=Solid,하드웨어,전원,네트워크,발견,관리
+ Keywords[nb]=Solid,maskinvare,strøm,nettverk,oppdage,styring
+ Keywords[nds]=Solid,Hardware,Stroom,Nettwark,Opdecken,Pleeg,Pleger
+--- a/wallpapers/Time-For-Lunch-2.jpg.desktop
++++ b/wallpapers/Time-For-Lunch-2.jpg.desktop
+@@ -26,7 +26,7 @@
+ Name[ja]=昼食の時間
+ Name[ka]=სადილის დრო
+ Name[kk]=Түс кезі
+-Name[km]=ដល់​ពេល​អាហារ​ថ្ងៃ​ត្រង់
++Name[km]=ដល់​ពេល​អាហារ​ថ្ងៃ​ត្រង់​ហើយ
+ Name[ko]=점심 시간
+ Name[lt]=Laikas pietauti
+ Name[lv]=Laiks pusdienām
+--- a/wallpapers/kde_box.png.desktop
++++ b/wallpapers/kde_box.png.desktop
+@@ -8,6 +8,7 @@
+ Name[de]=KDE-Kiste
+ Name[el]=Σύστημα KDE
+ Name[es]=Caja KDE
++Name[et]=KDE boks
+ Name[fa]=جعبۀ KDE
+ Name[ga]=Bosca KDE
+ Name[kk]=KDE Бокс
+--- a/wallpapers/moon.svgz.desktop
++++ b/wallpapers/moon.svgz.desktop
+@@ -30,7 +30,7 @@
+ Name[ja]=ムーン
+ Name[ka]=მთვარე
+ Name[kk]=Ай
+-Name[km]=ព្រះចន្ទ
++Name[km]=ព្រះច័ន្ទ
+ Name[ko]=달
+ Name[mk]=Месечина
+ Name[nb]=Måne
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -35,10 +35,8 @@
+ )
+ 
+ include_directories(
+-    ${CMAKE_BINARY_DIR}/workspace/kicker/libkicker
+     ${CMAKE_CURRENT_BINARY_DIR}
+     ${CMAKE_CURRENT_SOURCE_DIR}/kdm
+-    ${CMAKE_CURRENT_SOURCE_DIR}/kicker/libkicker
+     ${CMAKE_CURRENT_SOURCE_DIR}/libs
+     ${CMAKE_CURRENT_SOURCE_DIR}/libs/workspace
+ )
+@@ -77,16 +75,6 @@
+ add_subdirectory( wallpapers )
+ add_subdirectory( menu )
+ 
+-# let it rest in peace for now. do not enable as it
+-# is not enabled anymore in the release tarballs and
+-# anything that depends on it would have to be fixed
+-# anyway
+-set(BUILD_KICKER FALSE)
+-
+-if(BUILD_KICKER)
+-  add_subdirectory( kicker)
+-endif(BUILD_KICKER)
+-
+ if(X11_Xau_FOUND AND X11_Xdmcp_FOUND)
+   	add_subdirectory( kdm )
+ else(X11_Xau_FOUND AND X11_Xdmcp_FOUND)
+--- a/krunner/lock/lockdlg.cc
++++ b/krunner/lock/lockdlg.cc
+@@ -65,7 +65,8 @@
+ #include <QX11Info>
+ #include <kauthorized.h>
+ 
+-#include <kxkb_interface.h>
++#include <KPluginLoader>
++#include <KPluginFactory>
+ 
+ #ifndef AF_LOCAL
+ # define AF_LOCAL	AF_UNIX
+@@ -73,6 +74,7 @@
+ 
+ #define PASSDLG_HIDE_TIMEOUT 10000
+ 
++
+ //===========================================================================
+ //
+ // Simple dialog for entering a password.
+@@ -91,10 +93,10 @@
+     QLabel *pixLabel = new QLabel( frame );
+     pixLabel->setPixmap(DesktopIcon("system-lock-screen"));
+ 
+-    KUser user;
+-    QLabel *greetLabel = new QLabel( user.fullName().isEmpty() ?
++    KUser user; QString fullName=user.property(KUser::FullName).toString();
++    QLabel *greetLabel = new QLabel( fullName.isEmpty() ?
+             i18n("<nobr><b>The session is locked</b></nobr><br />") :
+-            i18n("<nobr><b>The session was locked by %1</b></nobr><br />",  user.fullName() ), frame );
++            i18n("<nobr><b>The session was locked by %1</b></nobr><br />", fullName ), frame );
+ 
+     mStatusLabel = new QLabel( "<b> </b>", frame );
+     mStatusLabel->setAlignment( Qt::AlignCenter );
+@@ -109,8 +111,15 @@
+     cancel = new KPushButton( KStandardGuiItem::cancel(), frame );
+     mNewSessButton = new KPushButton( KGuiItem(i18n("Sw&itch User..."), "fork"), frame );
+ 
+-    mLayoutButton = new KPushButton( frame );
+-    mLayoutButton->setFlat( true );
++    // Using KXKB component
++    KPluginFactory *kxkbFactory = KPluginLoader("libkdeinit4_kxkb").factory();
++    QWidget *kxkbComponent = NULL;
++    if (kxkbFactory) {
++        kxkbComponent = kxkbFactory->create<QWidget>(this);
++    }
++    else {
++        kDebug() << "can't load kxkb component library";
++    }
+ 
+     QVBoxLayout *unlockDialogLayout = new QVBoxLayout(w);
+     unlockDialogLayout->addWidget( frame );
+@@ -119,7 +128,9 @@
+     layStatus->setSpacing( KDialog::spacingHint() );
+     layStatus->setMargin( 0 );
+     layStatus->addWidget( mStatusLabel );
+-    layStatus->addWidget( mLayoutButton );
++
++    if( kxkbComponent )
++        layStatus->addWidget( kxkbComponent );
+ 
+     QHBoxLayout *layButtons = new QHBoxLayout();
+     layButtons->setSpacing( KDialog::spacingHint() );
+@@ -139,7 +150,7 @@
+     frameLayout->addWidget( sep, 3, 0, 1, 2 );
+     frameLayout->addLayout( layButtons, 4, 0, 1, 2 );
+ 
+-    connect(mLayoutButton, SIGNAL(clicked()), this, SLOT(layoutClicked()));
++    setButtons(None);
+     connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+     connect(ok, SIGNAL(clicked()), SLOT(slotOK()));
+     connect(mNewSessButton, SIGNAL(clicked()), SLOT(slotSwitchUser()));
+@@ -154,24 +165,7 @@
+     connect(qApp, SIGNAL(activity()), SLOT(slotActivity()) );
+ 
+     greet->start();
+-
+-    org::kde::KXKB kxkb("org.kde.kxkb", "/kxkb" , QDBusConnection::sessionBus());
+-    if( kxkb.isValid() ) {
+-        QDBusReply<QStringList> replyLayouts = kxkb.getLayoutsList();
+-        layoutsList = replyLayouts;
+-        QDBusReply<QString> replyCurrentLayout = kxkb.getCurrentLayout();
+-        QString currentLayout = replyCurrentLayout;
+-        if( !currentLayout.isEmpty() && layoutsList.count() > 1 ) {
+-            currLayout = layoutsList.indexOf(currentLayout);
+-            if (currLayout < 0)
+-                setLayoutText("err");
+-            else
+-                setLayoutText(layoutsList[currLayout]);
+-        } else
+-            mLayoutButton->hide();
+-    } else {
+-        mLayoutButton->hide(); // no kxkb running
+-    }
++    
+     capsLocked();
+ }
+ 
+@@ -181,27 +175,6 @@
+     delete greet;
+ }
+ 
+-void PasswordDlg::layoutClicked()
+-{
+-
+-    if( ++currLayout == layoutsList.size() )
+-        currLayout = 0;
+-    org::kde::KXKB kxkb("org.kde.kxkb", "/kxkb" , QDBusConnection::sessionBus());
+-    if( kxkb.isValid() ) {
+-        const QString currentLayout = layoutsList.at(currLayout);
+-        QDBusReply<bool> setLayoutReply = kxkb.setLayout(currentLayout );
+-        setLayoutText( setLayoutReply ? currentLayout : "err" );
+-    }
+-}
+-
+-void PasswordDlg::setLayoutText( const QString &txt )
+-{
+-    mLayoutButton->setText( txt );
+-    QSize sz = mLayoutButton->fontMetrics().size( 0, txt );
+-    int mrg = mLayoutButton->style()->pixelMetric( QStyle::PM_ButtonMargin ) * 2;
+-    mLayoutButton->setFixedSize( sz.width() + mrg, sz.height() + mrg );
+-}
+-
+ void PasswordDlg::updateLabel()
+ {
+     if (mUnlockingFailed)
+--- a/krunner/lock/lockdlg.h
++++ b/krunner/lock/lockdlg.h
+@@ -12,7 +12,7 @@
+ #include <kgreeterplugin.h>
+ 
+ #include <KDialog>
+-//Added by qt3to4:
++
+ #include <QLabel>
+ #include <QTimerEvent>
+ #include <QFrame>
+@@ -59,11 +59,9 @@
+     void slotSessionActivated();
+     void slotStartNewSession();
+     void slotOK();
+-    void layoutClicked();
+     void slotActivity();
+ 
+ private:
+-    void setLayoutText( const QString &txt );
+     void capsLocked();
+     void updateLabel();
+     int Reader (void *buf, int count);
+@@ -83,13 +81,10 @@
+     QGridLayout *frameLayout;
+     QLabel      *mStatusLabel;
+     KPushButton *mNewSessButton, *ok, *cancel;
+-    KPushButton *mLayoutButton;
+     int         mFailedTimerId;
+     int         mTimeoutTimerId;
+     int         mCapsLocked;
+     bool        mUnlockingFailed;
+-    QStringList layoutsList;
+-    int         currLayout;
+     int         sPid, sFd;
+     Q3ListView   *lv;
+ };
+--- a/krunner/krunnerapp.h
++++ b/krunner/krunnerapp.h
+@@ -52,9 +52,7 @@
+     //UGLY
+     static bool s_haveCompositeManager;
+ 
+-public slots:
+-    /** Show taskmanager */
+-    void showTaskManager();
++public Q_SLOTS:
+     //void showWindowList();
+ 
+     void logout();
+@@ -63,8 +61,11 @@
+     void rebootWithoutConfirmation();
+ 
+     // DBUS interface. if you change these methods, you MUST run:
+-    // qdbuscpp2xml -s krunnerapp.h -o org.kde.krunner.App.xml
++    // qdbuscpp2xml -m krunnerapp.h -o org.kde.krunner.App.xml
+     Q_SCRIPTABLE void initializeStartupNotification();
++    
++    /** Show taskmanager */
++    Q_SCRIPTABLE void showTaskManager();
+ 
+ private slots:
+     /**
+--- a/krunner/CMakeLists.txt
++++ b/krunner/CMakeLists.txt
+@@ -41,7 +41,6 @@
+ endif(X11_Xss_LIB)
+ 
+ add_subdirectory( lock )
+-add_subdirectory( runners )
+ 
+ install(TARGETS krunner DESTINATION ${BIN_INSTALL_DIR})
+ install(FILES krunner.desktop  DESTINATION  ${AUTOSTART_INSTALL_DIR})
+--- a/krunner/org.kde.krunner.App.xml
++++ b/krunner/org.kde.krunner.App.xml
+@@ -3,5 +3,7 @@
+   <interface name="org.kde.krunner.App">
+     <method name="initializeStartupNotification">
+     </method>
++    <method name="showTaskManager">
++    </method>
+   </interface>
+ </node>
+--- a/krunner/runners/krunnerrunner.desktop
++++ /dev/null
+@@ -1,35 +0,0 @@
+-[Desktop Entry]
+-Encoding=UTF-8
+-Type=ServiceType
+-X-KDE-ServiceType=KRunner/Runner
+-
+-Comment=KRunner plugin
+-Comment[ar]=KRunner ملحق
+-Comment[be]=Утулка Krunner
+-Comment[bg]=Приставка за KRunner
+-Comment[csb]=Wtëkôcze zrëszôcza KRunner
+-Comment[de]=Programmstarter-Modul
+-Comment[el]=Πρόσθετο του KRunner
+-Comment[es]=Complementos de Konqueror
+-Comment[fa]=وصلۀ KRunner
+-Comment[ga]=Breiseáin KRunner
+-Comment[he]=תוסף של KRunner
+-Comment[it]=Plugin di KRunner
+-Comment[ja]=KRunner プラグイン
+-Comment[kk]=KRunner плагин модулі
+-Comment[km]=កម្មវិធី​ជំនួយ KRunner
+-Comment[nb]=KRunner-programtillegg
+-Comment[nds]=KRunner-Moduul
+-Comment[ne]=केडीई रनर प्लगइन
+-Comment[nl]=KRunner-plugin
+-Comment[nn]=KRunner-tillegg
+-Comment[pa]=ਕੇ-ਰਨਰ ਪਲੱਗਇਨ
+-Comment[pt]='Plugin' do KRunner
+-Comment[pt_BR]=Plugin do KRunner
+-Comment[sl]=Vstavek za KRunner
+-Comment[sv]=Krunner-insticksprogram
+-Comment[th]=ปลั๊กอินของ KRunner
+-Comment[vi]=Bổ sung KRunner
+-Comment[x-test]=xxKRunner pluginxx
+-Comment[zh_CN]=KRunner 插件
+-Comment[zh_TW]=KRunner 外掛程式
+--- a/krunner/runners/CMakeLists.txt
++++ /dev/null
+@@ -1,9 +0,0 @@
+-# the following two are included directly in krunner itself
+-#add_subdirectory(app)
+-#add_subdirectory(shell)
+-
+-# these are all loadable runners
+-add_subdirectory(search)
+-add_subdirectory(calculator)
+-
+-install( FILES  krunnerrunner.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}  )
+--- a/krunner/runners/services/servicerunner.cpp
++++ b/krunner/runners/services/servicerunner.cpp
+@@ -50,7 +50,7 @@
+ ServiceRunner::ServiceRunner( QObject* parent )
+     : Plasma::AbstractRunner( parent )
+ {
+-    setObjectName( i18n( "Application" ) );
++    setObjectName(i18n("Application"));
+ }
+ 
+ ServiceRunner::~ServiceRunner()
+@@ -62,7 +62,7 @@
+     KService::Ptr service = KService::serviceByName(term);
+     QAction* action = 0;
+ 
+-    if ( service && !service->exec().isEmpty() ) {
++    if (service && !service->exec().isEmpty()) {
+         action = new ServiceAction(service, this);
+     }
+ 
+@@ -76,13 +76,16 @@
+     Q_UNUSED( max )
+     Q_UNUSED( offset )
+ 
+-    QString query = QString("exist Exec and '%1' ~in Keywords and Name != '%2'").arg(term, term);
++    if (term.length() <  3) {
++        return;
++    }
+ 
+-    const KService::List services = KServiceTypeTrader::self()->query( "Application", query );
++    QString query = QString("exist Exec and ('%1' ~in Keywords or '%2' ~~ GenericName or '%3' ~~ Name) and Name != '%4'").arg(term, term, term, term);
++    const KService::List services = KServiceTypeTrader::self()->query("Application", query);
+ 
+     //kDebug() << "got " << services.count() << " services from " << query;
+ 
+-    foreach ( const KService::Ptr service, services ) {
++    foreach (const KService::Ptr service, services) {
+         ServiceAction* action = new ServiceAction(service, matches);
+         matches->addAction(service->name(), action);
+         connect(action, SIGNAL(triggered()), SLOT(launchService()));
+--- a/krunner/krunner.desktop
++++ b/krunner/krunner.desktop
+@@ -9,6 +9,7 @@
+ Name[de]=Programmstarter
+ Name[el]=Εκτελεστής εντολών
+ Name[es]=Ejecución de órdenes
++Name[et]=Käsu käivitaja
+ Name[fa]=اجراکننده فرمان
+ Name[he]=מפעיל פקודות
+ Name[ja]=コマンド Runner
+--- a/libs/plasma/karambamanager.h
++++ /dev/null
+@@ -1,39 +0,0 @@
+-/*
+- *   Copyright 2007 Alexander Wiedenbruch <wirr01 at gmail.com>
+- *
+- *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU Library General Public License as
+- *   published by the Free Software Foundation; either version 2, 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 Library General Public
+- *   License along with this program; if not, write to the
+- *   Free Software Foundation, Inc.,
+- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+- */
+-
+-#ifndef KARAMBA_MANAGER_H
+-#define KARAMBA_MANAGER_H
+-
+-#include <QtCore/QObject>
+-#include <QtGui/QGraphicsScene>
+-
+-#include <KUrl>
+-
+-#include <plasma/plasma_export.h>
+-
+-extern "C" {
+-    typedef QGraphicsItemGroup* (*startKaramba)(const KUrl &theme, QGraphicsView *view);
+-}
+-
+-namespace KarambaManager
+-{
+-PLASMA_EXPORT QGraphicsItemGroup* loadKaramba(const KUrl &themePath, QGraphicsScene *scene);
+-}
+-
+-#endif
+--- a/libs/plasma/karambamanager.cpp
++++ /dev/null
+@@ -1,47 +0,0 @@
+-/*
+- *   Copyright 2007 Alexander Wiedenbruch <wirr01 at gmail.com>
+- *
+- *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU Library General Public License as
+- *   published by the Free Software Foundation; either version 2, 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 Library General Public
+- *   License along with this program; if not, write to the
+- *   Free Software Foundation, Inc.,
+- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+- */
+-
+-#include "karambamanager.h"
+-
+-#include <QFile>
+-
+-#include <KLibLoader>
+-#include <KLibrary>
+-#include <KDebug>
+-
+-QGraphicsItemGroup* KarambaManager::loadKaramba(const KUrl &themePath, QGraphicsScene *scene)
+-{
+-    QString karambaLib = QFile::encodeName(KLibLoader::self()->findLibrary(QLatin1String("libsuperkaramba")));
+-
+-    QGraphicsItemGroup *karamba = 0;
+-
+-    KLibrary *lib = KLibLoader::self()->library(karambaLib);
+-    if (lib) {
+-        startKaramba createKaramba = 0;
+-        createKaramba = (startKaramba)lib->resolveFunction("startKaramba");
+-        if (createKaramba) {
+-            karamba = createKaramba(themePath, scene->views()[0]);
+-        }
+-    } else {
+-        kWarning() << "Could not load " << karambaLib ;
+-    }
+-
+-    return karamba;
+-}
+-
+--- a/libs/plasma/abstractrunner.h
++++ b/libs/plasma/abstractrunner.h
+@@ -163,8 +163,8 @@
+ 
+ } // Plasma namespace
+ 
+-#define K_EXPORT_KRUNNER_RUNNER( libname, classname )     \
++#define K_EXPORT_PLASMA_RUNNER( libname, classname )     \
+ K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
+-K_EXPORT_PLUGIN(factory("krunner_" #libname))
++K_EXPORT_PLUGIN(factory("plasma_runner_" #libname))
+ 
+ #endif
+--- a/libs/plasma/servicetypes/plasma-containment.desktop
++++ b/libs/plasma/servicetypes/plasma-containment.desktop
+@@ -5,6 +5,7 @@
+ 
+ Comment=Plasma applet container and background painter
+ Comment[el]=Περιέχει εφαρμογίδια Plasma και σχεδιάζει το φόντο
++Comment[et]=Plasma apleti konteiner ja tausta joonistaja
+ Comment[ja]=Plasma アプレットのコンテナおよび背景描画
+ Comment[km]=ឧបករណ៍​ផ្ទុក​អាប់ភ្លេត​ប្លាស្មា និង​ឧបករណ៍​គូរ​ផ្ទៃ​ខាងក្រោយ
+ Comment[ko]=Plasma 애플릿 컨테이너와 배경 칠하는 도구
+--- a/libs/plasma/servicetypes/plasma-dataengine.desktop
++++ b/libs/plasma/servicetypes/plasma-dataengine.desktop
+@@ -9,6 +9,7 @@
+ Comment[de]=Plasma Daten-Treiber
+ Comment[el]=Μηχανή δεδομένων Plasma
+ Comment[es]=Motor de datos de Plasma
++Comment[et]=Plasma andmete mootor
+ Comment[fa]=موتور داده پلاسما
+ Comment[ga]=Inneall Sonraí Plasma
+ Comment[he]=מנוע נתונים של Plasma
+@@ -18,7 +19,7 @@
+ Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ​ប្លាស្មា
+ Comment[ko]=Plasma 데이터 엔진
+ Comment[nb]=Plasma datamotor
+-Comment[nds]=Plasma-Datenhanteerkarn
++Comment[nds]=Plasma-Hanteerkarn
+ Comment[ne]=प्लाज्मा डेटा इन्जिन
+ Comment[nl]=Plasma data-engine
+ Comment[nn]=Plasma-datamotor
+--- a/libs/plasma/servicetypes/plasma-applet.desktop
++++ b/libs/plasma/servicetypes/plasma-applet.desktop
+@@ -10,12 +10,13 @@
+ Comment[de]=Plasma-Miniprogramm
+ Comment[el]=Εφαρμογίδιο plasma
+ Comment[es]=Miniaplicación de Plasma
++Comment[et]=Plasma aplett
+ Comment[fa]=برنامک پلاسما
+ Comment[ga]=Feidhmchláirín Plasma
+ Comment[he]=יישומון Plasma
+ Comment[ja]=Plasma アプレット
+ Comment[kk]=Plasma апплеті
+-Comment[km]=អាប់​ភ្លេត​​ប្លាស្មា​
++Comment[km]=អាប់ភ្លេត​​ប្លាស្មា​
+ Comment[ko]=Plasma 애플릿
+ Comment[nb]=Plasma miniprogram
+ Comment[nds]=Plasma-Lüttprogramm
+--- /dev/null
++++ b/libs/plasma/servicetypes/plasma-runner.desktop
+@@ -0,0 +1,40 @@
++[Desktop Entry]
++Encoding=UTF-8
++Type=ServiceType
++X-KDE-ServiceType=Plasma/Runner
++
++Comment=KRunner plugin
++Comment[ar]=KRunner ملحق
++Comment[be]=Утулка Krunner
++Comment[bg]=Приставка за KRunner
++Comment[csb]=Wtëkôcze zrëszôcza KRunner
++Comment[de]=Programmstarter-Modul
++Comment[el]=Πρόσθετο του KRunner
++Comment[es]=Complementos de Konqueror
++Comment[et]=KRunneri plugin
++Comment[fa]=وصلۀ KRunner
++Comment[ga]=Breiseáin KRunner
++Comment[he]=תוסף של KRunner
++Comment[it]=Plugin di KRunner
++Comment[ja]=KRunner プラグイン
++Comment[kk]=KRunner плагин модулі
++Comment[km]=កម្មវិធី​ជំនួយ KRunner
++Comment[nb]=KRunner-programtillegg
++Comment[nds]=KRunner-Moduul
++Comment[ne]=केडीई रनर प्लगइन
++Comment[nl]=KRunner-plugin
++Comment[nn]=KRunner-tillegg
++Comment[pa]=ਕੇ-ਰਨਰ ਪਲੱਗਇਨ
++Comment[pt]='Plugin' do KRunner
++Comment[pt_BR]=Plugin do KRunner
++Comment[sl]=Vstavek za KRunner
++Comment[sv]=Krunner-insticksprogram
++Comment[th]=ปลั๊กอินของ KRunner
++Comment[vi]=Bổ sung KRunner
++Comment[x-test]=xxKRunner pluginxx
++Comment[zh_CN]=KRunner 插件
++Comment[zh_TW]=KRunner 外掛程式
++
++[PropertyDef::X-Plasma-RunnerPhase]
++Type=QString
++
+--- a/libs/plasma/servicetypes/plasma-animator.desktop
++++ b/libs/plasma/servicetypes/plasma-animator.desktop
+@@ -8,6 +8,7 @@
+ Comment[de]=Plasma Animations-Treiber
+ Comment[el]=Μηχανή κίνησης του Plasma
+ Comment[es]=Motor de animaciones de Plasma
++Comment[et]=Plasma animatsiooni mootor
+ Comment[fa]=موتور پویانمایی پلاسما
+ Comment[ga]=Inneall Beochana Plasma
+ Comment[he]=מנוע האנימציה של Plasma
+--- a/libs/plasma/servicetypes/plasma-scriptengine.desktop
++++ b/libs/plasma/servicetypes/plasma-scriptengine.desktop
+@@ -8,13 +8,14 @@
+ Comment[de]=Skriptsprachen-Erweiterung für Plasma
+ Comment[el]=Επέκταση γλώσσας σεναρίων για το Plasma
+ Comment[es]=Extensión de lenguaje de programación para Plasma
++Comment[et]=Plasma skriptikeele laiend
+ Comment[fa]=پسوند زبان اسکریپتی برای پلاسما
+ Comment[ga]=Eisínteacht teanga scriptithe le haghaidh Plasma
+ Comment[he]=הרחבת שפת תסריטים של Plasma
+ Comment[it]=Estensione per i linguaggi di script per Plasma
+ Comment[ja]=Plasma のためのスクリプト言語拡張
+ Comment[kk]=Plasma-ның скрипт тілі
+-Comment[km]=ផ្នែក​បន្ថែម​ការ​ស្គ្រីប​ភាសា​សម្រាប់​ប្លាស្មា
++Comment[km]=ផ្នែក​បន្ថែម​​ភាសា​ស្គ្រីប​សម្រាប់​​ប្លាស្មា
+ Comment[ko]=Plasma를 위한 스크립트 언어 확장
+ Comment[nb]=Skriptspråk-utvidelse for Plasma
+ Comment[nds]=Skriptspraak-Verwiedern för Plasma
+--- a/libs/plasma/phase.h
++++ b/libs/plasma/phase.h
+@@ -39,7 +39,6 @@
+ {
+     Q_OBJECT
+     Q_ENUMS( Animation )
+-    Q_ENUMS( RenderOp )
+     Q_ENUMS( CurveShape )
+     Q_ENUMS( Movement )
+ 
+@@ -58,11 +57,6 @@
+         ElementDisappear /*<< Animate the disappearance of an element */
+     };
+ 
+-    enum RenderOp
+-    {
+-        RenderBackground = 0 /*<< Render the background of an item */
+-    };
+-
+     enum CurveShape
+     {
+         EaseInCurve = 0,
+@@ -89,12 +83,37 @@
+ 
+     Q_INVOKABLE void animateItem(QGraphicsItem* item, Animation anim);
+     Q_INVOKABLE void moveItem(QGraphicsItem* item, Movement movement, const QPoint &destination);
+-    Q_INVOKABLE void render(QGraphicsItem* item, QImage& image, RenderOp op);
+ 
+-    AnimId animateElement(QGraphicsItem *obj, ElementAnimation);
+-    void stopElementAnimation(AnimId id);
+-    void setAnimationPixmap(AnimId id, const QPixmap &pixmap);
+-    QPixmap animationResult(AnimId id);
++    /**
++     * Starts a custom animation, preventing the need to create a timeline
++     * with its own timer tick.
++     *
++     * @arg frames the number of frames this animation should persist for
++     * @arg duration the length, in milliseconds, the animation will take
++     * @arg curve the curve applied to the frame rate
++     * @arg receive the object that will handle the actual animation
++     * @arg method the method name of slot to be invoked on each update.
++     *             It must take a qreal. So if the slot is animate(qreal),
++     *             pass in "animate" as the method parameter.
++     *
++     * @return an id that can be used to identify this animation.
++     */
++    Q_INVOKABLE AnimId customAnimation(int frames, int duration, Phase::CurveShape curve,
++                                       QObject* receiver, const char* method);
++
++    /**
++     * Stops a custom animation. Note that it is not necessary to call
++     * this on object destruction, as custom animations associated with
++     * a given QObject are cleaned up automatically on QObject destruction.
++     *
++     * @arg id the id of the animation as returned by customAnimation
++     */
++    Q_INVOKABLE void stopCustomAnimation(AnimId id);
++
++    Q_INVOKABLE AnimId animateElement(QGraphicsItem *obj, ElementAnimation);
++    Q_INVOKABLE void stopElementAnimation(AnimId id);
++    Q_INVOKABLE void setAnimationPixmap(AnimId id, const QPixmap &pixmap);
++    Q_INVOKABLE QPixmap animationResult(AnimId id);
+ 
+ Q_SIGNALS:
+     void animationComplete(QGraphicsItem *item, Animation anim);
+@@ -105,6 +124,7 @@
+ 
+ protected Q_SLOTS:
+     void appletDestroyed(QObject*);
++    void customAnimReceiverDestroyed(QObject*);
+ 
+ private:
+     void init();
+--- a/libs/plasma/appletbrowser/Messages.sh
++++ /dev/null
+@@ -1,2 +0,0 @@
+-#! /usr/bin/env bash
+-$XGETTEXT *.cpp -o $podir/plasmaappletbrowser.pot
+--- a/libs/plasma/appletbrowser/CMakeLists.txt
++++ /dev/null
+@@ -1,16 +0,0 @@
+-
+-set(
+-  plasma_appletbrowser_SRCS
+-  kcategorizeditemsview.cpp
+-  kcategorizeditemsviewmodels.cpp
+-  kcategorizeditemsviewdelegate.cpp
+-  appletbrowserwindow.cpp
+-  plasmaappletitemmodel.cpp
+-)
+-
+-kde4_add_ui_files(
+-  plasma_appletbrowser_SRCS
+-  kcategorizeditemsviewbase.ui
+-  appletbrowserwindowbase.ui
+-)
+-
+--- a/libs/plasma/appletbrowser/kcategorizeditemsviewmodels_p.h
++++ b/libs/plasma/appletbrowser/kcategorizeditemsviewmodels_p.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/customdragtreeview.cpp
++++ b/libs/plasma/appletbrowser/customdragtreeview.cpp
+@@ -1,3 +1,22 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library/Lesser General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
+ #include "kcategorizeditemsview_p.h"
+ 
+ #define PIX_SIZE 64
+--- a/libs/plasma/appletbrowser/kcategorizeditemsviewdelegate.cpp
++++ b/libs/plasma/appletbrowser/kcategorizeditemsviewdelegate.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/plasmaappletitemmodel.cpp
++++ b/libs/plasma/appletbrowser/plasmaappletitemmodel.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+@@ -19,39 +19,19 @@
+ 
+ #include "plasmaappletitemmodel_p.h"
+ 
+-PlasmaAppletItem::PlasmaAppletItem(QObject * parent, QString name,
+-        QString pluginName, QString description, QString category, QIcon icon,
+-        FilterFlags flags) :
+-    QObject(parent)
+-{
+-    QMap<QString, QVariant> attrs;
+-    attrs.insert("name", QVariant(name));
+-    attrs.insert("pluginName", QVariant(pluginName));
+-    attrs.insert("description", QVariant(description));
+-    attrs.insert("category", QVariant(category));
+-    attrs.insert("favorite", flags & Favorite ? true : false);
+-    attrs.insert("used", flags & Used ? true : false);
+-    attrs.insert("recommended", flags & Recommended ? true : false);
+-    setText(name + " - "+ description);
+-    setData(QVariant(attrs));
+-    setIcon(icon);
+-}
++PlasmaAppletItem::PlasmaAppletItem(PlasmaAppletItemModel * model, const QMap<QString, QVariant>& info,
++        FilterFlags flags, QMap<QString, QVariant> * extraAttrs) :
++    QObject(model), m_model(model)
++{
++    QMap<QString, QVariant> attrs(info);
+ 
+-PlasmaAppletItem::PlasmaAppletItem(QObject *parent, const KPluginInfo& info,
+-        FilterFlags flags) :
+-    QObject(parent)
+-{
+-    QMap<QString, QVariant> attrs;
+-    attrs.insert("name", info.name());
+-    attrs.insert("pluginName", info.pluginName());
+-    attrs.insert("description", info.comment());
+-    attrs.insert("category", info.category());
+     attrs.insert("favorite", flags & Favorite ? true : false);
+     attrs.insert("used", flags & Used ? true : false);
+-    attrs.insert("recommended", flags & Recommended ? true : false);
+-    setText(info.name() + " - "+ info.category());
++    //attrs.insert("recommended", flags & Recommended ? true : false);
++    if (extraAttrs) attrs.unite(* extraAttrs);
++    setText(info["name"].toString() + " - "+ info["category"].toString());
+     setData(attrs);
+-    setIcon(KIcon(info.icon().isEmpty()?"application-x-plasma":info.icon()));
++    setIcon(qvariant_cast<QIcon>(info["icon"]));
+ }
+ 
+ QString PlasmaAppletItem::name() const
+@@ -74,6 +54,19 @@
+     QMap<QString, QVariant> attrs = data().toMap();
+     attrs.insert("favorite", favorite ? true : false);
+     setData(QVariant(attrs));
++
++    QString pluginName = attrs["pluginName"].toString();
++
++    if (pluginName == "skapplet" && attrs.contains("arguments")) {
++        // skapplet can be used with all SuperKaramba themes,
++        // so when setting skapplet as favorite it is also
++        // necessary to know which theme is meant
++        QString themePath = qvariant_cast<QVariantList>(attrs["arguments"])[0].toString();
++
++        m_model->setFavorite(pluginName + " - " + themePath, favorite);
++    } else {
++        m_model->setFavorite(pluginName, favorite);
++    }
+ }
+ 
+ bool PlasmaAppletItem::passesFiltering(
+@@ -82,30 +75,55 @@
+     return data().toMap()[filter.first] == filter.second;
+ }
+ 
+-PlasmaAppletItemModel::PlasmaAppletItemModel(QObject * parent) :
+-    KCategorizedItemsViewModels::DefaultItemModel(parent)
++QVariantList PlasmaAppletItem::arguments() const
+ {
+-    /* some test items that do have FilterFlags as well as overly long text
+-    appendRow(new PlasmaAppletItem(this, 
+-        i18n("This is a very long name for an applet, isn't it?"), "null", 
+-        i18n("This is a Graphics applet whose description is even longer than it's title. And it was hard to achieve!"), 
+-        QString("graph"),
+-        QIcon("/usr/share/icons/oxygen/64x64/apps/k3b.png"), PlasmaAppletItem::Used));
+-    appendRow(new PlasmaAppletItem(this, 
+-        i18n("This is a very long name for another applet, isn't it?"), "null", 
+-        i18n("This is a Graphics applet whose description is even longer than it's title. And it was hard to achieve!"), 
+-        QString("graph"),
+-        QIcon("/usr/share/icons/oxygen/64x64/apps/kfind.png"), PlasmaAppletItem::Used | PlasmaAppletItem::Recommended));
+-    appendRow(new PlasmaAppletItem(this, 
+-        i18n("This is my favorite item!"), "null",
+-        i18n("This is a Graphics applet whose description is even longer than it's title. And it was hard to achieve!"), 
+-        QString("graph"),
+-        QIcon("/usr/share/icons/oxygen/64x64/apps/okular.png"), PlasmaAppletItem::Favorite | PlasmaAppletItem::Recommended));
+-    */
++    return qvariant_cast<QVariantList>(data().toMap()["arguments"]);
++}
++
++PlasmaAppletItemModel::PlasmaAppletItemModel(KConfigGroup configGroup, QObject * parent) :
++    KCategorizedItemsViewModels::DefaultItemModel(parent),
++    m_configGroup(configGroup)
++{
++
++    // Recommended emblems and filters
++    QRegExp rx("recommended[.]([0-9A-Za-z]+)[.]plugins");
++    QMapIterator<QString, QString> i(m_configGroup.entryMap());
++    QMap < QString, QMap < QString, QVariant > > extraPluginAttrs;
++    while (i.hasNext()) {
++        i.next();
++        if (!rx.exactMatch(i.key())) continue;
++        QString id = rx.cap(1);
++
++        foreach (QString plugin, i.value().split(",")) {
++            extraPluginAttrs[plugin]["recommended." + id] = true;
++        }
++    }
++
++    m_favorites = m_configGroup.readEntry("favorites").split(",");
++    m_used = m_configGroup.readEntry("used").split(",");
+ 
+     //TODO: get recommended, favorit, used, etc out of knownApplets()
+     foreach (const KPluginInfo& info, Plasma::Applet::knownApplets()) {
+-        appendRow(new PlasmaAppletItem(this, info));
++        kDebug() << info.pluginName() << " is the name of the plugin\n";
++
++        QMap<QString, QVariant> attrs;
++        attrs.insert("name", info.name());
++        attrs.insert("pluginName", info.pluginName());
++        attrs.insert("description", info.comment());
++        attrs.insert("category", info.category());
++        attrs.insert("icon", static_cast<QIcon>(KIcon(info.icon().isEmpty()?"application-x-plasma":info.icon())));
++
++        appendRow(new PlasmaAppletItem(this, attrs,
++                ((m_favorites.contains(info.pluginName())) ? PlasmaAppletItem::Favorite : PlasmaAppletItem::NoFilter) |
++                ((m_used.contains(info.pluginName())) ? PlasmaAppletItem::Used : PlasmaAppletItem::NoFilter)
++                , &(extraPluginAttrs[info.pluginName()])));
++
++        // If there is the SuperKaramba applet,
++        // add SuperKaramba themes to the
++        // model too
++        if (info.pluginName() == "skapplet") {
++            loadSuperKarambaThemes(info);
++        }
+     }
+ }
+ 
+@@ -141,3 +159,63 @@
+ 
+     return data;
+ }
++
++void PlasmaAppletItemModel::setFavorite(QString plugin, bool favorite)
++{
++    if (favorite) {
++        if (!m_favorites.contains(plugin)) {
++            m_favorites.append(plugin);
++        }
++    } else {
++        if (m_favorites.contains(plugin)) {
++            m_favorites.removeAll(plugin);
++        }
++    }
++    m_configGroup.writeEntry("favorites", m_favorites.join(","));
++    m_configGroup.sync();
++
++}
++
++/*
++ * Define function type to get the SuperKaramba themes
++ * from skapplet (see skapplet.cpp in kdeutils/superkaramba)
++ */
++extern "C" {
++    typedef QList<QMap<QString, QVariant> > (*installedThemes)();
++}
++
++void PlasmaAppletItemModel::loadSuperKarambaThemes(const KPluginInfo &info)
++{
++    KService::Ptr service = info.service();
++    QString libName = service->library();
++
++    // Load the Plugin as library to get access
++    // to installedThemes() in skapplet
++    KLibrary *lib = KLibLoader::self()->library(libName);
++    if (lib) {
++        installedThemes loadThemes = 0;
++
++        loadThemes = (installedThemes)lib->resolveFunction("installedThemes");
++
++        if (loadThemes) {
++            // loadThemes() returns the name, description, the icon
++            // and one argument (file path) from the theme
++            QList<QMap<QString, QVariant> > themeMetadata = loadThemes();
++
++            QMap <QString, QVariant> metadata;
++            foreach (metadata, themeMetadata) {
++                metadata.insert("pluginName", "skapplet");
++                metadata.insert("category", "SuperKaramba");
++
++                QString favorite = info.pluginName() + " - " + qvariant_cast<QVariantList>(metadata["arguments"])[0].toString();
++
++                appendRow(new PlasmaAppletItem(this, metadata,
++                    ((m_favorites.contains(favorite)) ? PlasmaAppletItem::Favorite : PlasmaAppletItem::NoFilter) |
++                    ((m_used.contains(info.pluginName())) ? PlasmaAppletItem::Used : PlasmaAppletItem::NoFilter)));
++            }
++        }
++    } else {
++        kWarning() << "Could not load" << libName;
++    }
++}
++
+--- a/libs/plasma/appletbrowser/main.cpp
++++ b/libs/plasma/appletbrowser/main.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/customdragtreeview_p.h
++++ b/libs/plasma/appletbrowser/customdragtreeview_p.h
+@@ -1,3 +1,22 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library/Lesser General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
+ #include <QTreeView>
+ #include "kcategorizeditemsviewmodels_p.h"
+ 
+--- a/libs/plasma/appletbrowser/kcategorizeditemsviewdelegate_p.h
++++ b/libs/plasma/appletbrowser/kcategorizeditemsviewdelegate_p.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/plasmaappletitemmodel_p.h
++++ b/libs/plasma/appletbrowser/plasmaappletitemmodel_p.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+@@ -26,6 +26,8 @@
+ 
+ #include "kcategorizeditemsview_p.h"
+ 
++class PlasmaAppletItemModel;
++
+ /**
+  * Implementation of the KCategorizedItemsViewModels::AbstractItem
+  */
+@@ -35,17 +37,12 @@
+ public:
+     enum FilterFlag {NoFilter = 0,
+         Favorite = 1,
+-        Used = 2,
+-        Recommended = 4};
++        Used = 2};
+ 
+     Q_DECLARE_FLAGS(FilterFlags, FilterFlag)
+ 
+-    PlasmaAppletItem(QObject * parent, QString name, QString pluginName,
+-            QString description, QString category, QIcon icon,
+-            FilterFlags flags = NoFilter);
+-
+-    PlasmaAppletItem(QObject *parent, const KPluginInfo& info,
+-            FilterFlags flags = NoFilter);
++    PlasmaAppletItem(PlasmaAppletItemModel * model, const QMap<QString, QVariant>& info,
++            FilterFlags flags = NoFilter, QMap<QString, QVariant> * extraAttrs = NULL);
+ 
+     virtual QString name() const;
+     QString pluginName() const;
+@@ -53,17 +50,30 @@
+     virtual void setFavorite(bool favorite);
+     virtual bool passesFiltering(
+             const KCategorizedItemsViewModels::Filter & filter) const;
++    virtual QVariantList arguments() const;
++
++private:
++    PlasmaAppletItemModel * m_model;
+ };
+ 
+ class PlasmaAppletItemModel :
+     public KCategorizedItemsViewModels::DefaultItemModel
+ {
+ public:
+-    PlasmaAppletItemModel(QObject * parent = 0);
++    PlasmaAppletItemModel(KConfigGroup configGroup, QObject * parent = 0);
+ 
+     QStringList mimeTypes() const;
+ 
+     QMimeData* mimeData(const QModelIndexList & indexes) const;
++    
++    void setFavorite(QString plugin, bool favorite);
++
++private:
++    QStringList m_favorites;
++    QStringList m_used;
++    KConfigGroup m_configGroup;
++
++    void loadSuperKarambaThemes(const KPluginInfo &info);
+ };
+ 
+ Q_DECLARE_OPERATORS_FOR_FLAGS(PlasmaAppletItem::FilterFlags)
+--- a/libs/plasma/appletbrowser/kcategorizeditemsview.cpp
++++ b/libs/plasma/appletbrowser/kcategorizeditemsview.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/kcategorizeditemsview_p.h
++++ b/libs/plasma/appletbrowser/kcategorizeditemsview_p.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/appletbrowser/kcategorizeditemsviewmodels.cpp
++++ b/libs/plasma/appletbrowser/kcategorizeditemsviewmodels.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/animator.cpp
++++ b/libs/plasma/animator.cpp
+@@ -109,24 +109,19 @@
+     Q_UNUSED(drawable)
+ }
+ 
+-void Animator::slideIn(qreal progress, QGraphicsItem *item, const QPoint &destination)
++void Animator::slideIn(qreal progress, QGraphicsItem *item, const QPoint &start, const QPoint &destination)
+ {
+-    //FIXME: rewrite
+-    Q_UNUSED(progress);
+-    item->translate(-destination.x(), -destination.y());
++    int x = start.x() + (destination.x() - start.x()) * progress;
++    int y = start.y() + (destination.y() - start.y()) * progress;
++    item->setPos(x, y);
+ }
+ 
+-void Animator::slideOut(qreal progress, QGraphicsItem *item, const QPoint &destination)
++void Animator::slideOut(qreal progress, QGraphicsItem *item, const QPoint &start, const QPoint &destination)
+ {
+-    //FIXME: rewrite
+-    Q_UNUSED(progress);
+     //kDebug();
+-    item->translate(destination.x(), destination.y());
+-}
+-
+-void Animator::renderBackground(QImage& background)
+-{
+-    Q_UNUSED(background)
++    int x = start.x() + (destination.x() - start.x()) * progress;
++    int y = start.y() + (destination.y() - start.y()) * progress;
++    item->setPos(x, y);
+ }
+ 
+ } // Plasma namespace
+--- a/libs/plasma/corona.cpp
++++ b/libs/plasma/corona.cpp
+@@ -36,7 +36,6 @@
+ 
+ #include "containment.h"
+ #include "dataengine.h"
+-#include "karambamanager.h"
+ #include "phase.h"
+ #include "widgets/freelayout.h"
+ #include "widgets/boxlayout.h"
+@@ -153,7 +152,6 @@
+             if (c) {
+                 containments.insert(c->id(), c);
+                 c->initConstraints(&appletConfig);
+-                c->setGeometry(appletConfig.readEntry("geometry", QRectF()));
+                 kDebug() << "Containment" << c->id() << "geometry is" << c->geometry();
+             }
+         } else {
+@@ -176,12 +174,10 @@
+             continue;
+         }
+ 
+-        kDebug() << "loading containment " << cid;
+-
+-        kDebug() << "creating applet " << cg.name();
++        kDebug() << "creating applet " << cg.name() << "in containment" << cid;
+         int appId = cg.name().left(cg.name().indexOf('-')).toUInt();
+         c->addApplet(cg.readEntry("plugin", QString()), QVariantList(),
+-                        appId, cg.readEntry("geometry", QRectF()), true);
++                     appId, cg.readEntry("geometry", QRectF()), true);
+     }
+ 
+     foreach (Containment* c, containments) {
+@@ -192,13 +188,14 @@
+ 
+     if (d->containments.count() < 1) {
+         loadDefaultSetup();
+-    }
+-
+-    foreach (Containment* containment, d->containments) {
+-        containment->init(); //FIXME: is this being called twice?
++    } else {
++        foreach (Containment* containment, d->containments) {
++            containment->init();
++            addItem(containment);
+ 
+-        foreach(Applet* applet, containment->applets()) {
+-            applet->init();
++            foreach(Applet* applet, containment->applets()) {
++                applet->init();
++            }
+         }
+     }
+ 
+@@ -232,11 +229,6 @@
+     Plasma::Applet *clockApplet = panel->addApplet("digital-clock");
+ 
+     applets << tasksApplet << systemTrayApplet << clockApplet;
+-
+-    foreach (Plasma::Applet* applet , applets) {
+-        // If we have a Panel class (is a Container), this should move there
+-        applet->setDrawStandardBackground(false);
+-    }
+ }
+ 
+ Containment* Corona::containmentForScreen(int screen) const
+@@ -285,15 +277,11 @@
+         containment->setFailedToLaunch(false); // we want to provide something and don't care about the failure to launch
+     }
+ 
+-    addItem(containment);
+-
+     if (!delayedInit) {
+         containment->init();
++        addItem(containment);
+     }
+ 
+-    // in case it was set in the Containment (or Applet), we don't want this
+-    containment->setDrawStandardBackground(false);
+-
+     d->containments.append(containment);
+     connect(containment, SIGNAL(destroyed(QObject*)),
+             this, SLOT(containmentDestroyed(QObject*)));
+@@ -312,19 +300,6 @@
+     return d->containments[0]->addApplet(name, args, id, geometry);
+ }
+ 
+-void Corona::addKaramba(const KUrl& path)
+-{
+-    //FIXME: i think this is slightly broken now that we have containments?
+-    //       it should go into a containment...
+-    QGraphicsItemGroup* karamba = KarambaManager::loadKaramba(path, this);
+-    if (karamba) {
+-        addItem(karamba);
+-        Phase::self()->animateItem(karamba, Phase::Appear);
+-    } else {
+-        kDebug() << "Karamba " << path << " could not be loaded.";
+-    }
+-}
+-
+ void Corona::dragEnterEvent( QGraphicsSceneDragDropEvent *event)
+ {
+ //    kDebug() << "Corona::dragEnterEvent(QGraphicsSceneDragDropEvent* event)";
+--- a/libs/plasma/containment.h
++++ b/libs/plasma/containment.h
+@@ -61,6 +61,10 @@
+         typedef QList<Applet*> List;
+         typedef QHash<QString, Applet*> Dict;
+ 
++        enum Type { DesktopContainment = 0 /**< A desktop containment */,
++                    PanelContainment /**< A desktop panel */
++                  };
++
+         /**
+          * @arg parent the QGraphicsItem this applet is parented to
+          * @arg servideId the name of the .desktop file containing the
+@@ -92,6 +96,11 @@
+         void init();
+ 
+         /**
++         * Returns the type of containment
++         */
++        virtual Type type();
++
++        /**
+          * Paints a default background image. Nothing fancy, but that's what plugins
+          * are for. Reimplemented from Applet;
+          */
+@@ -187,11 +196,6 @@
+         void saveConstraints(KConfigGroup* group) const;
+ 
+         /**
+-         * Adds a Superkaramba theme to this Containment
+-         */
+-        void addKaramba(const KUrl& path);
+-
+-        /**
+          * @internal
+          */
+         void initConstraints(KConfigGroup* group);
+--- /dev/null
++++ b/libs/plasma/includes/AppletBrowser
+@@ -0,0 +1 @@
++#include "../../plasma/appletbrowser.h"
+--- a/libs/plasma/CMakeLists.txt
++++ b/libs/plasma/CMakeLists.txt
+@@ -37,12 +37,12 @@
+     shadowitem.cpp
+     svg.cpp
+     theme.cpp
+-    karambamanager.cpp
+     uiloader.cpp
+     widgets/boxlayout.cpp
+     widgets/borderlayout.cpp
+     widgets/checkbox.cpp
+     widgets/freelayout.cpp
++    widgets/nodelayout.cpp
+     widgets/flowlayout.cpp
+     widgets/flash.cpp
+     widgets/icon.cpp
+@@ -123,6 +123,7 @@
+ install(FILES
+     widgets/boxlayout.h
+     widgets/borderlayout.h
++    widgets/nodelayout.h
+     widgets/hboxlayout.h
+     widgets/vboxlayout.h
+     widgets/freelayout.h
+@@ -160,6 +161,7 @@
+     includes/UiLoader
+     includes/PackageMetadata
+     includes/Containment
++    includes/AppletBrowser
+     DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma)
+ 
+ if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
+@@ -173,6 +175,7 @@
+     servicetypes/plasma-animator.desktop
+     servicetypes/plasma-applet.desktop
+     servicetypes/plasma-dataengine.desktop
++    servicetypes/plasma-runner.desktop
+     servicetypes/plasma-scriptengine.desktop
+     DESTINATION ${SERVICETYPES_INSTALL_DIR})
+ 
+--- a/libs/plasma/abstractrunner.cpp
++++ b/libs/plasma/abstractrunner.cpp
+@@ -113,21 +113,32 @@
+ 
+ AbstractRunner::List AbstractRunner::loadRunners( QWidget* parent )
+ {
++    List firstRunners;
+     List runners;
+-    KService::List offers = KServiceTypeTrader::self()->query("KRunner/Runner");
++    List lastRunners;
++
++    KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner");
+     QString error;
+     foreach (KService::Ptr service, offers) {
+         AbstractRunner* runner = service->createInstance<AbstractRunner>(parent, QVariantList(), &error);
+-        if ( runner ) {
++        if (runner) {
+             kDebug() << "loaded runner : " << service->name();
+-            runners.append( runner );
++            QString phase = service->property("X-Plasma-RunnerPhase").toString();
++            if (phase == "last") {
++                lastRunners.append(runner);
++            } else if (phase == "first") {
++                firstRunners.append(runner);
++            } else {
++                runners.append(runner);
++            }
+         }
+         else {
+             kDebug() << "failed to load runner : " << service->name() << ". error reported: " << error;
+         }
+     }
+ 
+-    return runners;
++    firstRunners << runners << lastRunners;
++    return firstRunners;
+ }
+ 
+ } // Plasma namespace
+--- a/libs/plasma/appletbrowser.h
++++ b/libs/plasma/appletbrowser.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/Messages.sh
++++ b/libs/plasma/Messages.sh
+@@ -1,2 +1,2 @@
+ #! /usr/bin/env bash
+-$XGETTEXT *.cpp *.h -o $podir/libplasma.pot
++$XGETTEXT *.cpp *.h */*.h */*.cpp -o $podir/libplasma.pot
+--- a/libs/plasma/phase.cpp
++++ b/libs/plasma/phase.cpp
+@@ -32,6 +32,7 @@
+ namespace Plasma
+ {
+ 
++static const qreal MIN_TICK_RATE = 40;
+ 
+ struct AnimationState
+ {
+@@ -66,9 +67,22 @@
+     int currentInterval;
+     int frames;
+     int currentFrame;
++    QPoint start;
+     QPoint destination;
+ };
+ 
++struct CustomAnimationState
++{
++    Phase::CurveShape curve;
++    int frames;
++    int currentFrame;
++    int interval;
++    int currentInterval;
++    Phase::AnimId id;
++    QObject* receiver;
++    char* slot;
++};
++
+ class Phase::Private
+ {
+     public:
+@@ -84,10 +98,27 @@
+         {
+             qDeleteAll(animatedItems);
+             qDeleteAll(animatedElements);
++            qDeleteAll(movingItems);
++
++            QMutableMapIterator<AnimId, CustomAnimationState*> it(customAnims);
++            while (it.hasNext()) {
++                delete it.value()->slot;
++                delete it.value();
++                it.remove();
++            }
++
+             // Animator is a QObject
+             // and we don't own the items
+         }
+ 
++        qreal calculateProgress(int frames, int currentFrame)
++        {
++            qreal progress = frames;
++            progress = currentFrame / progress;
++            progress = qMin(1.0, qMax(0.0, progress));
++            return progress;
++        }
++
+         void performAnimation(qreal amount, const AnimationState* state)
+         {
+             switch (state->animation) {
+@@ -113,10 +144,12 @@
+         {
+             switch (state->movement) {
+                 case Phase::SlideIn:
+-                    animator->slideIn(amount, state->item, state->destination);
++                    //kDebug() << "performMovement, SlideIn";
++                    animator->slideIn(amount, state->item, state->start, state->destination);
+                     break;
+                 case Phase::SlideOut:
+-                    animator->slideOut(amount, state->item, state->destination);
++                    //kDebug() << "performMovement, SlideOut";
++                    animator->slideOut(amount, state->item, state->start, state->destination);
+                     break;
+             }
+         }
+@@ -131,6 +164,7 @@
+         QMap<QGraphicsItem*, AnimationState*> animatedItems;
+         QMap<QGraphicsItem*, MovementState*> movingItems;
+         QMap<Phase::AnimId, ElementAnimationState*> animatedElements;
++        QMap<AnimId, CustomAnimationState*> customAnims;
+ };
+ 
+ class PhaseSingleton
+@@ -181,6 +215,18 @@
+     }
+ }
+ 
++void Phase::customAnimReceiverDestroyed(QObject* o)
++{
++    QMutableMapIterator<AnimId, CustomAnimationState*> it(d->customAnims);
++    while (it.hasNext()) {
++        if (it.next().value()->receiver == o) {
++            delete it.value()->slot;
++            delete it.value();
++            it.remove();
++        }
++    }
++}
++
+ void Phase::animateItem(QGraphicsItem* item, Animation animation)
+ {
+      //kDebug();
+@@ -208,14 +254,14 @@
+     state->frames = frames / 3;
+     state->currentFrame = 0;
+     state->interval = 333 / state->frames;
+-    state->interval = (state->interval / 40) * 40;
++    state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
+     state->currentInterval = state->interval;
+ 
+     d->animatedItems[item] = state;
+     d->performAnimation(0, state);
+ 
+     if (!d->timerId) {
+-        d->timerId = startTimer(40);
++        d->timerId = startTimer(MIN_TICK_RATE);
+         d->time.restart();
+     }
+ }
+@@ -237,34 +283,69 @@
+      }
+ 
+      MovementState* state = new MovementState;
+-     state->destination=destination;
++     state->destination = destination;
++     state->start = item->pos().toPoint();
+      state->item = item;
+      state->movement = movement;
+      state->curve = d->animator->curve(movement);
+      //TODO: variance in times based on the value of animation
+      state->frames = frames / 2;
+      state->currentFrame = 0;
+-     state->interval = 500 / state->frames;
+-     state->interval = (state->interval / 40) * 40;
++     state->interval = 250 / state->frames;
++     state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
+      state->currentInterval = state->interval;
+ 
+      d->movingItems[item] = state;
+      d->performMovement(0, state);
+ 
+      if (!d->timerId) {
+-          d->timerId = startTimer(40);
++          d->timerId = startTimer(MIN_TICK_RATE);
+           d->time.restart();
+      }
+ }
+ 
+-void Phase::render(QGraphicsItem* item, QImage& image, RenderOp op)
++Phase::AnimId Phase::customAnimation(int frames, int duration, Phase::CurveShape curve,
++                                     QObject* receiver, const char* slot)
+ {
+-    Q_UNUSED(item);
+-    switch (op) {
+-        case RenderBackground:
+-            d->animator->renderBackground(image);
+-            break;
++    if (frames < 1 || duration < 1 || !receiver || !slot) {
++        return -1;
++    }
++
++    CustomAnimationState *state = new CustomAnimationState;
++    state->id = ++d->animId;
++    state->frames = frames;
++    state->currentFrame = 0;
++    state->curve = curve;
++    state->interval = duration / qreal(state->frames);
++    state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
++    state->currentInterval = state->interval;
++    state->receiver = receiver;
++    state->slot = qstrdup(slot);
++
++    d->customAnims[state->id] = state;
++
++    connect(receiver, SIGNAL(destroyed(QObject*)),
++            this, SLOT(customAnimReceiverDestroyed(QObject*)));
++
++    QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0));
++
++    if (!d->timerId) {
++        d->timerId = startTimer(MIN_TICK_RATE);
++        d->time.restart();
++    }
++
++    return state->id;
++}
++
++void Phase::stopCustomAnimation(AnimId id)
++{
++    QMap<AnimId, CustomAnimationState*>::iterator it = d->customAnims.find(id);
++    if (it != d->customAnims.end()) {
++        delete it.value()->slot;
++        delete it.value();
++        d->customAnims.erase(it);
+     }
++    //kDebug() << "stopCustomAnimation(AnimId " << id << ") done";
+ }
+ 
+ Phase::AnimId Phase::animateElement(QGraphicsItem *item, ElementAnimation animation)
+@@ -278,7 +359,7 @@
+     state->frames = d->animator->framesPerSecond(animation) / 5;
+     state->currentFrame = 0;
+     state->interval = 200 / state->frames;
+-    state->interval = (state->interval / 40) * 40;
++    state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
+     state->currentInterval = state->interval;
+     state->id = ++d->animId;
+ 
+@@ -297,7 +378,7 @@
+     if (needTimer && !d->timerId) {
+         // start a 20fps timer;
+         //TODO: should be started at the maximum frame rate needed only?
+-        d->timerId = startTimer(40);
++        d->timerId = startTimer(MIN_TICK_RATE);
+         d->time.restart();
+     }
+     return state->id;
+@@ -357,7 +438,7 @@
+ {
+     Q_UNUSED(event)
+     bool animationsRemain = false;
+-    int elapsed = 40;
++    int elapsed = MIN_TICK_RATE;
+     if (d->time.elapsed() > elapsed) {
+         elapsed = d->time.elapsed();
+     }
+@@ -370,9 +451,7 @@
+             state->currentFrame += qMax(1, elapsed / state->interval);
+ 
+             if (state->currentFrame < state->frames) {
+-                qreal progress = state->frames;
+-                progress = state->currentFrame / progress;
+-                progress = qMin(1.0, qMax(0.0, progress));
++                qreal progress = d->calculateProgress(state->frames, state->currentFrame);
+                 d->performAnimation(progress, state);
+                 state->currentInterval = state->interval;
+                 //TODO: calculate a proper interval based on the curve
+@@ -396,11 +475,8 @@
+             state->currentFrame += qMax(1, elapsed / state->interval);
+ 
+             if (state->currentFrame < state->frames) {
+-                qreal progress = state->frames;
+-                progress = state->currentFrame / progress;
+-                progress = qMin(1.0, qMax(0.0, progress));
+-                //kDebug()<<progress;
+-                d->performMovement(progress, state);
++                d->performMovement(d->calculateProgress(state->frames, state->currentFrame), state);
++                //TODO: calculate a proper interval based on the curve
+                 state->currentInterval = state->interval;
+                 animationsRemain = true;
+             } else {
+@@ -435,11 +511,36 @@
+             if (state->currentFrame < state->frames) {
+                 state->currentInterval = state->interval;
+                 //TODO: calculate a proper interval based on the curve
+-                qreal progress = state->frames;
+-                progress = state->currentFrame / progress;
+-                progress = qMin(1.0, qMax(0.0, progress));
+-                state->interval *= 1 - progress;
++                state->interval *= 1 - d->calculateProgress(state->frames, state->currentFrame);
++                animationsRemain = true;
++            }
++        } else {
++            state->currentInterval -= elapsed;
++            animationsRemain = true;
++        }
++    }
++
++    foreach (CustomAnimationState *state, d->customAnims) {
++        if (state->currentInterval <= elapsed) {
++            // advance the frame
++            state->currentFrame += qMax(1, elapsed / state->interval);
++            /*kDebug() << "custom anim for" << state->receiver << "to slot" << state->slot
++                     << "with interval of" << state->interval << "at frame" << state->currentFrame;*/
++
++            if (state->currentFrame < state->frames) {
++                //kDebug () << "not the final frame";
++                //TODO: calculate a proper interval based on the curve
++                state->currentInterval = state->interval;
+                 animationsRemain = true;
++                // signal the object
++                QMetaObject::invokeMethod(state->receiver, state->slot,
++                                          Q_ARG(qreal,
++                                                d->calculateProgress(state->frames, state->currentFrame)));
++            } else {
++                QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1));
++                d->customAnims.erase(d->customAnims.find(state->id));
++                delete state->slot;
++                delete state;
+             }
+         } else {
+             state->currentInterval -= elapsed;
+--- a/libs/plasma/dataengine.h
++++ b/libs/plasma/dataengine.h
+@@ -81,7 +81,7 @@
+          * Connects a source to an object for data updates. The object must
+          * have a slot with the following signature:
+          *
+-         * updated(QString sourceName, Plasma::DataEngine::Data data)
++         * updated(const QString &sourceName, const Plasma::DataEngine::Data &data)
+          *
+          * The data is a QHash of QVariants keyed by QString names, allowing
+          * one data source to provide sets of related data.
+--- a/libs/plasma/packagestructure.cpp
++++ b/libs/plasma/packagestructure.cpp
+@@ -148,6 +148,7 @@
+     ContentStructure s;
+     s.name = name;
+     s.path = path;
++    s.directory = true;
+ 
+     d->contents[key] = s;
+ }
+--- a/libs/plasma/animator.h
++++ b/libs/plasma/animator.h
+@@ -62,11 +62,8 @@
+     virtual void activate(qreal progress, QGraphicsItem* item);
+ 
+     // Item movements
+-    virtual void slideIn(qreal progress, QGraphicsItem* item, const QPoint &destination);
+-    virtual void slideOut(qreal progress, QGraphicsItem* item, const QPoint &destination);
+-
+-    // Rendering
+-    virtual void renderBackground(QImage& background);
++    virtual void slideIn(qreal progress, QGraphicsItem* item, const QPoint &start, const QPoint &destination);
++    virtual void slideOut(qreal progress, QGraphicsItem* item, const QPoint &start, const QPoint &destination);
+ 
+ private:
+     class Private;
+--- a/libs/plasma/containment.cpp
++++ b/libs/plasma/containment.cpp
+@@ -36,7 +36,6 @@
+ #include <KServiceTypeTrader>
+ 
+ #include "corona.h"
+-#include "karambamanager.h"
+ #include "phase.h"
+ #include "svg.h"
+ 
+@@ -55,7 +54,7 @@
+           layout(0),
+           background(0),
+           bitmapBackground(0),
+-          screen(-1),
++          screen(0),
+           immutable(false)
+     {
+     }
+@@ -103,24 +102,36 @@
+ {
+ //    setCachePaintMode(NoCacheMode);
+     setFlag(QGraphicsItem::ItemIsMovable, false);
+-    KConfigGroup config(KGlobal::config(), "General");
+-    d->wallpaperPath = config.readEntry("wallpaper", QString());
++    setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
++    setAcceptDrops(true);
+ 
+-    //kDebug() << "wallpaperPath is" << d->wallpaperPath << QFile::exists(d->wallpaperPath);
+-    if (d->wallpaperPath.isEmpty() ||
+-        !QFile::exists(d->wallpaperPath)) {
+-        //kDebug() << "SVG wallpaper!";
+-        d->background = new Plasma::Svg("widgets/wallpaper", this);
++    if (type() == DesktopContainment) {
++        KConfigGroup config(KGlobal::config(), "General");
++        d->wallpaperPath = config.readEntry("wallpaper", QString());
++
++        //kDebug() << "wallpaperPath is" << d->wallpaperPath << QFile::exists(d->wallpaperPath);
++        if (d->wallpaperPath.isEmpty() ||
++                !QFile::exists(d->wallpaperPath)) {
++            kDebug() << "SVG wallpaper!";
++            d->background = new Plasma::Svg("widgets/wallpaper", this);
++        }
++    }
++
++    if (type() == PanelContainment) {
++        //kDebug() << "we are a panel, let's move ourselves to a negative coordinate system";
++        QDesktopWidget desktop;
++        QRect r = desktop.screenGeometry(screen());
++        translate(0, -r.height());
+     }
+-    setAcceptDrops(true);
+ }
+ 
+ void Containment::initConstraints(KConfigGroup* group)
+ {
+-    //kDebug() << "initConstraints" << group->group();
+-    setScreen(group->readEntry("screen", -1));
+-    setFormFactor((Plasma::FormFactor)group->readEntry("formfactor", (int)Plasma::Planar));
++    //kDebug() << "initConstraints" << group->name() << type();
+     setLocation((Plasma::Location)group->readEntry("location", (int)Plasma::Desktop));
++    setGeometry(group->readEntry("geometry", QRectF()));
++    setFormFactor((Plasma::FormFactor)group->readEntry("formfactor", (int)Plasma::Planar));
++    setScreen(group->readEntry("screen", 0));
+ }
+ 
+ void Containment::saveConstraints(KConfigGroup* group) const
+@@ -130,10 +141,22 @@
+     group->writeEntry("location", (int)d->location);
+ }
+ 
++Containment::Type Containment::type()
++{
++    return DesktopContainment;
++}
++
+ void Containment::paintInterface(QPainter *painter,
+                                  const QStyleOptionGraphicsItem *option,
+                                  const QRect& contentsRect)
+ {
++    //FIXME: this should probably ALL move to the Desktop containment, save for drawing a rect
++    //       in case there is no other drawing going on
++    if (type() != DesktopContainment) {
++        return;
++    }
++
++    //kDebug() << "paintInterface of background";
+     //TODO: we should have a way to do this outside of the paint event!
+     if (d->background) {
+         d->background->resize(contentsRect.size());
+@@ -145,7 +168,8 @@
+         }
+     } else {
+         // got nothing to paint!
+-        painter->drawRect(contentsRect);
++        //kDebug() << "got nothing?";
++        painter->drawRect(contentsRect.adjusted(1, 1, -1, -1));
+         return;
+     }
+ 
+@@ -159,11 +183,13 @@
+     if (d->background) {
+         // Plasma::Svg doesn't support drawing only part of the image (it only
+         // supports drawing the whole image to a rect), so we blit to 0,0-w,h
+-        d->background->paint(painter, 0, 0);
++        d->background->paint(painter, contentsRect);
++    //kDebug() << "draw svg of background";
+     } else if (d->bitmapBackground) {
+         // for pixmaps we draw only the exposed part (untransformed since the
+         // bitmapBackground already has the size of the viewport)
+         painter->drawPixmap(option->exposedRect, *d->bitmapBackground, option->exposedRect);
++    //kDebug() << "draw pixmap of background";
+     }
+ 
+     // restore transformation and composition mode
+@@ -177,25 +203,13 @@
+ 
+ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
+ {
+-    kDebug() << "let's see if we manage to get a context menu here, huh";
++    //kDebug() << "let's see if we manage to get a context menu here, huh";
+     if (!scene() || !KAuthorized::authorizeKAction("desktop_contextmenu")) {
+         QGraphicsItem::contextMenuEvent(event);
+         return;
+     }
+ 
+     QPointF point = event->scenePos();
+-    /*
+-    * example for displaying the SuperKaramba context menu
+-    QGraphicsItem *item = itemAt(point);
+-    if(item) {
+-    QObject *object = dynamic_cast<QObject*>(item->parentItem());
+-    if(object && object->objectName().startsWith("karamba")) {
+-    QContextMenuEvent event(QContextMenuEvent::Mouse, point);
+-    contextMenuEvent(&event);
+-    return;
+-}
+-}
+-    */
+     QGraphicsItem* item = scene()->itemAt(point);
+     if (item == this) {
+         item = 0;
+@@ -269,7 +283,7 @@
+     }
+ 
+     event->accept();
+-    desktopMenu.exec(point.toPoint());
++    desktopMenu.exec(event->screenPos());
+ }
+ 
+ void Containment::setFormFactor(FormFactor formFactor)
+@@ -353,6 +367,10 @@
+     }
+ 
+     applet->setParentItem(this);
++    //panels don't want backgrounds, which is important when setting geometry
++    if (type() == PanelContainment) {
++        applet->setDrawStandardBackground(false);
++    }
+     //the applet needs to be given constraints before it can set its geometry
+     applet->updateConstraints(Plasma::AllConstraints);
+ 
+@@ -395,17 +413,6 @@
+     return applet;
+ }
+ 
+-void Containment::addKaramba(const KUrl& path)
+-{
+-    QGraphicsItemGroup* karamba = KarambaManager::loadKaramba(path, scene());
+-    if (karamba) {
+-        karamba->setParentItem(this);
+-        Phase::self()->animateItem(karamba, Phase::Appear);
+-    } else {
+-        kDebug() << "Karamba " << path << " could not be loaded.";
+-    }
+-}
+-
+ void Containment::appletDestroyed(QObject* object)
+ {
+     // we do a static_cast here since it really isn't an Applet by this
+@@ -434,9 +441,10 @@
+         screen = -1;
+     }
+ 
+-    if (screen > -1) {
++    //kDebug() << "setting scrreen to " << screen << "and type is" << type();
++    if (screen > -1 && type() == DesktopContainment) {
+         setGeometry(desktop.screenGeometry(screen));
+-        //kDebug() << "setting geometry to" << desktop.screenGeometry(screen);
++        //kDebug() << "setting geometry to" << desktop.screenGeometry(screen) << geometry();
+     }
+ 
+     d->screen = screen;
+--- a/libs/plasma/applet.cpp
++++ b/libs/plasma/applet.cpp
+@@ -696,6 +696,7 @@
+ 
+ QList<QAction*> Applet::contextActions()
+ {
++    kDebug() << "empty actions";
+     return QList<QAction*>();
+ }
+ 
+@@ -995,6 +996,8 @@
+         //      from the network at this point
+         kDebug() << "Applet::loadApplet: offers is empty for \"" << appletName << "\"";
+         return 0;
++    } else if (offers.count() > 1) {
++        kDebug() << "hey! we got more than one! let's blindly take the first one";
+     }
+ 
+     if (appletId == 0) {
+@@ -1089,7 +1092,7 @@
+ 
+ void Applet::setGeometry(const QRectF& geometry)
+ {
+-    if (size() != geometry.size()) {
++    if (geometry.size().width() > 0 && geometry.size().height() > 0 && size() != geometry.size()) {
+         prepareGeometryChange();
+         qreal width = qBound(minimumSize().width(), geometry.size().width(), maximumSize().width());
+         qreal height = qBound(minimumSize().height(), geometry.size().height(), maximumSize().height());
+--- a/libs/plasma/widgets/flash.h
++++ b/libs/plasma/widgets/flash.h
+@@ -1,5 +1,5 @@
+ /*
+- *   Copyright 2007 by André Duffeck <andre at duffeck.de>
++ *   Copyright 2007 by André Duffeck <duffeck at kde.org>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+  *   it under the terms of the GNU Library General Public License as
+@@ -43,9 +43,9 @@
+ 
+         void paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+         QRectF boundingRect() const;
+-        QSize size() const;
+-        int height() const;
+-        int width() const;
++        QSizeF minimumSize() const;
++        QSizeF maximumSize() const;
++        virtual QSizeF sizeHint() const;
+         void setSize(const QSize &size);
+         void setWidth(int width);
+         void setHeight(int height);
+--- a/libs/plasma/widgets/borderlayout.h
++++ b/libs/plasma/widgets/borderlayout.h
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2,
+- *   or (at your option) any later version, as published by the Free 
+- *   Software Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+--- a/libs/plasma/widgets/label.h
++++ b/libs/plasma/widgets/label.h
+@@ -24,6 +24,7 @@
+ 
+ #include <plasma/widgets/widget.h>
+ #include <QtGui/QPen>
++#include <QtGui/QFont>
+ 
+ class QGraphicsTextItem;
+ 
+@@ -107,6 +108,16 @@
+         QPen pen() const;
+ 
+         /**
++         * Sets the font used for the text.
++         */
++        void setFont(const QFont& font);
++
++        /**
++         * Returns the font used for the text.
++         */
++        QFont font() const;
++
++        /**
+          * Paint function.
+          */
+         void paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+--- a/libs/plasma/widgets/widget.h
++++ b/libs/plasma/widgets/widget.h
+@@ -45,7 +45,8 @@
+  * Widgets are rectangular, but can be in any visible shape by just using transparency to mask
+  * out non-rectangular areas.
+  *
+- * To implement a Widget, just subclass Plasma::Widget and implement at minimum, sizeHint() and paint()
++ * To implement a Widget, just subclass Plasma::Widget and implement at minimum,
++ * sizeHint() and paintWidget()
+  */
+ class PLASMA_EXPORT Widget  : public QObject,
+                               public QGraphicsItem,
+--- /dev/null
++++ b/libs/plasma/widgets/nodelayout.h
+@@ -0,0 +1,119 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library/Lesser General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef PLASMA_NODE_LAYOUT
++#define PLASMA_NODE_LAYOUT
++
++#include <QtCore/QMap>
++#include <cmath>
++
++#include <plasma/plasma_export.h>
++#include <plasma/plasma.h>
++#include <plasma/widgets/layout.h>
++
++namespace Plasma {
++
++/**
++ * Node layout has an advanced layouting mechanism. Every item's position
++ * is defined by two nodes - one for top-left corner, and the other one for
++ * bottom-right corner.
++ * 
++ * Each node is defined by a pair of relative (xr, yr) and a pair of 
++ * absolute (xa, ya) coordinates. The calculated node coordinates depend
++ * on the size and position of the NodeLayout object in the following
++ * manner:
++ *   x = layoutLeft + (xr * layoutWidth)  + xa
++ *   y = layoutTop  + (yr * layoutHeight) + ya
++ *
++ * Alternatively, the item's position can be defined by using one node and
++ * one pair of relative coordinates (xr, yr). In that case, the item is sized
++ * following the sizeHint(). The relative coordinates (this time they are 
++ * relative to the item's geometry, not the layout's) specify what point of
++ * the item will be bound to the defined node.
++ */
++
++class PLASMA_EXPORT NodeLayout : public Layout {
++public:
++    class PLASMA_EXPORT NodeCoordinate {
++    public:
++        /**
++         * Position is calculated:
++         * x = parentLeft + (xRelative * parentWidth)  + xAbsolute
++         * y = parentTop  + (yRelative * parentHeight) + yAbsolute
++         */
++        NodeCoordinate(qreal xRelative = 0, qreal yRelative = 0, qreal xAbsolute = 0, qreal yAbsolute = 0);
++
++        enum CoordinateType {
++            Relative = 0,
++            Absolute = 1,
++            InnerRelative = 2 };
++
++        static NodeCoordinate simple(qreal x, qreal y, CoordinateType xType = Relative, CoordinateType yType = Relative);
++
++        float xr, xa;
++        float yr, ya;
++    };
++
++    // reimplemented
++    virtual Qt::Orientations expandingDirections() const;
++
++    explicit NodeLayout(LayoutItem * parent = 0);
++    virtual ~NodeLayout();
++
++    virtual QRectF geometry() const;
++    void setGeometry(const QRectF& geometry);
++
++    QSizeF sizeHint() const;
++
++    /**
++     * Adds item at top-left corner, with automatic sizing
++     * (using sizeHint of the item)
++     */
++    void addItem (LayoutItem * item);
++
++    /**
++     * Adds item with specified top-left and bottom right corners.
++     */
++    void addItem (LayoutItem * item,
++            NodeCoordinate topLeft, NodeCoordinate bottomRight);
++
++    /**
++     * Adds item with automatic sizing turned on. xr and yr specify
++     * which point of the item is bound to node coordinate. Those
++     * are relative coordinates so (0, 0) represent top left corner,
++     * (0.5, 0.5) represent the center of the item etc.
++     */
++    void addItem (LayoutItem * item,
++            NodeCoordinate node, qreal xr = 0, qreal yr = 0);
++
++    void removeItem (LayoutItem * item);
++
++    virtual int count() const;
++    virtual int indexOf(LayoutItem * item) const;
++    virtual LayoutItem * itemAt(int i) const;
++    virtual LayoutItem * takeAt(int i);
++
++private:
++    class Private;
++    Private * const d;
++};
++
++}
++
++#endif /* PLASMA_NODE_LAYOUT */
+--- a/libs/plasma/widgets/flash.cpp
++++ b/libs/plasma/widgets/flash.cpp
+@@ -1,5 +1,5 @@
+ /*
+- *   Copyright 2007 by André Duffeck <andre at duffeck.de>
++ *   Copyright 2007 by André Duffeck <duffeck at kde.org>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+  *   it under the terms of the GNU Library General Public License as
+@@ -74,6 +74,8 @@
+     d->width = 100 ;
+     d->animId = 0;
+     d->state = Private::Invisible;
++
++    setCachePaintMode( NoCacheMode );
+ }
+ 
+ Flash::~Flash()
+@@ -86,16 +88,6 @@
+     return QRectF(0,0,d->width,d->height);
+ }
+ 
+-int Flash::height() const
+-{
+-    return d->height;
+-}
+-
+-int Flash::width() const
+-{
+-    return d->width;
+-}
+-
+ void Flash::setHeight(int h)
+ {
+     prepareGeometryChange ();
+@@ -115,7 +107,12 @@
+     d->defaultDuration = duration;
+ }
+ 
+-QSize Flash::size() const
++QSizeF Flash::minimumSize() const
++{
++    return QSize(d->width,d->height);
++}
++
++QSizeF Flash::maximumSize() const
+ {
+     return QSize(d->width,d->height);
+ }
+@@ -128,6 +125,11 @@
+     update();
+ }
+ 
++QSizeF Flash::sizeHint() const
++{
++    return minimumSize();
++}
++
+ void Flash::setColor( const QColor &color )
+ {
+     d->color = color;
+@@ -140,8 +142,9 @@
+ 
+ void Flash::flash( const QString &text, int duration, const QTextOption &option)
+ {
++    kDebug() << duration << endl;
+     d->type = Private::Text;
+-    d->duration = (duration == 0) ? duration : d->defaultDuration;
++    d->duration = (duration == 0) ? d->defaultDuration : duration;
+     d->text = text;
+     d->textOption = option;
+     QTimer::singleShot( 0, this, SLOT(fadeIn()) );
+@@ -150,7 +153,7 @@
+ void Flash::flash( const QPixmap &pixmap, int duration, Qt::Alignment align )
+ {
+     d->type = Private::Pixmap;
+-    d->duration = (duration == 0) ? duration : d->defaultDuration;
++    d->duration = (duration == 0) ? d->defaultDuration : duration;
+     d->pixmap = pixmap;
+     d->alignment = align;
+     QTimer::singleShot( 0, this, SLOT(fadeIn()) );
+@@ -184,14 +187,14 @@
+ 
+ QPixmap Flash::renderPixmap()
+ {
+-    QPixmap pm( width(), height() );
++    QPixmap pm( size().toSize() );
+     pm.fill(Qt::transparent);
+ 
+     QPainter painter( &pm );
+     if( d->type == Private::Text ) {
+         painter.setPen( d->color );
+         painter.setFont( d->font );
+-        painter.drawText( QRect( 0, 0, width(), height() ), d->text, d->textOption);
++        painter.drawText( QRect( QPoint(0, 0), size().toSize() ), d->text, d->textOption);
+     } else if( d->type == Private::Pixmap ) {
+         QPoint p;
+         if( d->alignment & Qt::AlignLeft )
+@@ -212,7 +215,6 @@
+     }
+     return pm;
+ }
+-
+ void Flash::paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+     Q_UNUSED(option)
+--- a/libs/plasma/widgets/borderlayout.cpp
++++ b/libs/plasma/widgets/borderlayout.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2,
+- *   or (at your option) any later version, as published by the Free 
+- *   Software Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+@@ -83,39 +83,45 @@
+ 
+ void BorderLayout::invalidate()
+ {
+-
+-    QPointF origin = d->geometry.topLeft();
+-    qreal top = 0, bottom = 0, left = 0, right = 0;
++    QRectF geometry = d->geometry;
++    geometry.setTopLeft(geometry.topLeft() + QPointF(margin(), margin()));
++    geometry.setBottomRight(geometry.bottomRight() - QPointF(margin(), margin()));
++
++    QPointF origin = geometry.topLeft();
++    qreal top, bottom, left, right;
++    top    = (d->sizes[TopPositioned] >= 0)    ? d->sizes[TopPositioned]    : 0;
++    left   = (d->sizes[LeftPositioned] >= 0)   ? d->sizes[LeftPositioned]   : 0;
++    bottom = geometry.height() - ((d->sizes[BottomPositioned] >= 0) ? d->sizes[BottomPositioned] : 0);
++    right  = geometry.width()  - ((d->sizes[RightPositioned] >= 0)  ? d->sizes[RightPositioned]  : 0);
+ 
+     if (d->itemPositions[TopPositioned] /*&& d->itemPositions[TopPositioned]->isVisible()*/) {
+         top = (d->sizes[TopPositioned] >= 0) ? d->sizes[TopPositioned] : d->itemPositions[TopPositioned]->sizeHint().height();
+         d->itemPositions[TopPositioned]->setGeometry(QRectF(origin, QSizeF(
+-                d->geometry.width(), top)));
+-	top += spacing();
+-
++                geometry.width(), top)));
++        top += spacing();
+     }
+ 
+     if (d->itemPositions[BottomPositioned] /*&& d->itemPositions[BottomPositioned]->isVisible()*/) {
+         bottom = (d->sizes[BottomPositioned] >= 0) ? d->sizes[BottomPositioned]
+                 : d->itemPositions[BottomPositioned]->sizeHint().height();
+         d->itemPositions[BottomPositioned]->setGeometry(QRectF(origin + QPointF(0,
+-                d->geometry.height() - bottom), QSizeF(d->geometry.width(),
++                geometry.height() - bottom), QSizeF(geometry.width(),
+                 bottom)));
+-        bottom = d->geometry.height() - bottom - spacing();
++        bottom = geometry.height() - bottom - spacing();
+     }
+ 
+     if (d->itemPositions[LeftPositioned] /*&& d->itemPositions[LeftPositioned]->isVisible()*/) {
+         left = (d->sizes[LeftPositioned] >= 0) ? d->sizes[LeftPositioned] : d->itemPositions[LeftPositioned]->sizeHint().width();
+         d->itemPositions[LeftPositioned]->setGeometry(QRectF(origin + QPointF(0, top),
+                 QSizeF(left, bottom - top)));
+-	left += spacing();
++        left += spacing();
+     }
+ 
+     if (d->itemPositions[RightPositioned] /*&& d->itemPositions[RightPositioned]->isVisible()*/) {
+         right = (d->sizes[RightPositioned] >= 0) ? d->sizes[RightPositioned] : d->itemPositions[RightPositioned]->sizeHint().width();
+         d->itemPositions[RightPositioned]->setGeometry(QRectF(origin + QPointF(
+-                d->geometry.width() - right, top), QSizeF(right, bottom - top)));
+-        right = d->geometry.width() - right - spacing();
++                geometry.width() - right, top), QSizeF(right, bottom - top)));
++        right = geometry.width() - right - spacing();
+     }
+ 
+     if (d->itemPositions[CenterPositioned] /*&& d->itemPositions[CenterPositioned]->isVisible()*/) {
+@@ -151,7 +157,7 @@
+         hintWidth += d->itemPositions[CenterPositioned]->sizeHint().width();
+     }
+ 
+-    return QSizeF(hintWidth, hintHeight);
++    return QSizeF(hintWidth + 2 * margin(), hintHeight + 2 * margin());
+ }
+ 
+ void BorderLayout::addItem(Plasma::LayoutItem * item)
+--- a/libs/plasma/widgets/label.cpp
++++ b/libs/plasma/widgets/label.cpp
+@@ -14,6 +14,7 @@
+         QString text;
+         Qt::Alignment alignment;
+         QPen textPen;
++        QFont textFont;
+ };
+ 
+ Label::Label(Widget *parent)
+@@ -47,9 +48,9 @@
+ 
+ QSizeF Label::sizeHint() const
+ {
+-    QFontMetricsF m(QFont("Arial", 12));
++    QFontMetricsF m(d->textFont);
+ 
+-    return m.boundingRect(d->text).size();
++    return m.boundingRect(QRectF(0,0,9999,9999), d->alignment | Qt::TextWordWrap, d->text).size();
+ }
+ 
+ void Label::setText(const QString& text)
+@@ -82,12 +83,23 @@
+     return d->textPen;
+ }
+ 
++void Label::setFont(const QFont& font)
++{
++    d->textFont = font;
++}
++
++QFont Label::font() const
++{
++    return d->textFont;
++}
++
+ void Label::paintWidget(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
+ {
+     Q_UNUSED(option);
+     Q_UNUSED(widget);
+ 
+     p->setPen(d->textPen);
++    p->setFont(d->textFont);
+     p->drawText(option->rect, d->alignment | Qt::TextWordWrap, d->text);
+ }
+ 
+--- /dev/null
++++ b/libs/plasma/widgets/nodelayout.cpp
+@@ -0,0 +1,240 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library/Lesser General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "nodelayout.h"
++
++#include <QPair>
++#include <QMap>
++
++namespace Plasma
++{
++NodeLayout::NodeCoordinate::NodeCoordinate(qreal xRelative, qreal yRelative, qreal xAbsolute, qreal yAbsolute)
++    : xr(xRelative), xa(xAbsolute), yr(yRelative), ya(yAbsolute) {}
++
++NodeLayout::NodeCoordinate NodeLayout::NodeCoordinate::simple(qreal x, qreal y,
++        CoordinateType xType, CoordinateType yType)
++{
++    NodeLayout::NodeCoordinate coo;
++    switch (xType) {
++    case Relative:
++        coo.xr = x;
++        coo.xa = 0;
++        break;
++    case Absolute:
++        coo.xr = 0;
++        coo.xa = x;
++        break;
++    case InnerRelative:
++        coo.xr = x;
++        coo.xa = INFINITY;
++        break;
++    }
++
++    switch (yType) {
++    case Relative:
++        coo.yr = y;
++        coo.ya = 0;
++        break;
++    case Absolute:
++        coo.yr = 0;
++        coo.ya = y;
++        break;
++    case InnerRelative:
++        coo.yr = y;
++        coo.ya = INFINITY;
++        break;
++    }
++    return coo;
++}
++
++class NodeLayout::Private {
++public:
++    QMap <LayoutItem * , QPair < NodeCoordinate, NodeCoordinate > > items;
++    QRectF geometry;
++    QSizeF sizeHint;
++
++    qreal calculateXPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
++    {
++        return parentGeometry.left() + (coo.xr * parentGeometry.width())  + coo.xa;
++    }
++
++    qreal calculateYPosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
++    {
++        return parentGeometry.top() + (coo.yr * parentGeometry.height())  + coo.ya;
++    }
++
++    QPointF calculatePosition(const NodeCoordinate & coo, const QRectF & parentGeometry) const
++    {
++        return QPointF(
++            calculateXPosition(coo, geometry),
++            calculateYPosition(coo, geometry)
++        );
++    }
++
++
++    QRectF calculateRectangle(LayoutItem * item, QRectF geometry = QRectF()) const
++    {
++        if (geometry == QRectF()) geometry = this->geometry;
++
++        QRectF result;
++        if (!item || !items.contains(item)) return QRectF();
++
++        result.setTopLeft(calculatePosition(items[item].first, geometry));
++
++        if (items[item].second.xa != INFINITY) {
++            result.setRight(calculateXPosition(items[item].second, geometry));
++        } else {
++            result.setWidth(item->sizeHint().width());
++            result.moveLeft(result.left() - items[item].second.xr * result.width());
++        }
++
++        if (items[item].second.ya != INFINITY) {
++            result.setBottom(calculateYPosition(items[item].second, geometry));
++        } else {
++            result.setHeight(item->sizeHint().height());
++            result.moveTop(result.top() - items[item].second.yr * result.height());
++        }
++
++        return result;
++    }
++
++    void invalidate()
++    {
++        foreach (LayoutItem * item, items.keys()) {
++            if (item) {
++                item->setGeometry(calculateRectangle(item));
++            }
++        }
++    }
++
++    void calculateSizeHint(LayoutItem * item = NULL) {
++        if (item == NULL) {
++            // Recalculate the sizeHint using all items
++            sizeHint = QSizeF();
++            foreach (LayoutItem * item, items.keys()) {
++                if (item) {
++                    calculateSizeHint(item);
++                }
++            }
++        } else {
++            // Calculate size hint for current item
++            QRectF scaled = calculateRectangle(item, QRectF(0, 0, 1, 1));
++
++            // qMin(..., 1.0) so that for autosized elements we don't get smaller
++            // size than the item's size itself. The sizeHint for NodeLayout can
++            // not do anything smarter concerning the sizeHint when there are
++            // autosized elements.
++
++            qreal width  = item->sizeHint().width()  / qMin(scaled.width(), 1.0);
++            qreal height = item->sizeHint().height() / qMin(scaled.height(), 1.0);
++
++            if (width > sizeHint.width())   sizeHint.setWidth(width);
++            if (height > sizeHint.height()) sizeHint.setHeight(height);
++        }
++    }
++
++};
++
++
++NodeLayout::NodeLayout(LayoutItem * parent) 
++  : Layout(parent), d(new Private())
++{
++}
++
++NodeLayout::~NodeLayout()
++{
++    delete d;
++}
++
++Qt::Orientations NodeLayout::expandingDirections() const
++{
++    return Qt::Horizontal | Qt::Vertical;
++}
++
++QRectF NodeLayout::geometry() const
++{
++    return d->geometry;
++}
++
++void NodeLayout::setGeometry(const QRectF& geometry)
++{
++    if (!geometry.isValid() || geometry.isEmpty()) {
++        return;
++    }
++
++    d->geometry = geometry;
++    d->invalidate();
++}
++
++QSizeF NodeLayout::sizeHint() const
++{
++    return d->sizeHint;
++}
++
++void NodeLayout::addItem (LayoutItem * item)
++{
++    NodeLayout::addItem (item, NodeCoordinate());
++}
++
++void NodeLayout::addItem (LayoutItem * item, NodeCoordinate topLeft, NodeCoordinate bottomRight)
++{
++    if (!item) return;
++    d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(topLeft, bottomRight);
++    d->calculateSizeHint(item);
++}
++
++void NodeLayout::addItem (LayoutItem * item, NodeCoordinate node, qreal xr, qreal yr)
++{
++    if (!item) return;
++    d->items[item] = QPair<NodeCoordinate, NodeCoordinate>(node,
++        NodeCoordinate::simple(xr, yr, NodeCoordinate::InnerRelative, NodeCoordinate::InnerRelative));
++    d->calculateSizeHint(item);
++}
++
++void NodeLayout::removeItem (LayoutItem * item)
++{
++    if (!item) return;
++    d->items.remove(item);
++    d->calculateSizeHint();
++}
++
++int NodeLayout::count() const
++{
++    return d->items.count();
++}
++
++int NodeLayout::indexOf(LayoutItem * item) const
++{
++    if (!item) return -1;
++    return d->items.keys().indexOf(item);
++}
++
++LayoutItem * NodeLayout::itemAt(int i) const
++{
++    return d->items.keys()[i];
++}
++
++LayoutItem * NodeLayout::takeAt(int i)
++{
++    LayoutItem * item = itemAt(i);
++    removeItem(item);
++    return item;
++}
++
++}
+--- a/libs/plasma/widgets/widget.cpp
++++ b/libs/plasma/widgets/widget.cpp
+@@ -208,7 +208,7 @@
+ 
+ void Widget::setGeometry(const QRectF& geometry)
+ {
+-    if (d->size != geometry.size()) {
++    if (geometry.size().width() > 0 && geometry.size().height() > 0 && d->size != geometry.size()) {
+         prepareGeometryChange();
+         qreal width = qBound(d->minimumSize.width(), geometry.size().width(), d->maximumSize.width());
+         qreal height = qBound(d->minimumSize.height(), geometry.size().height(), d->maximumSize.height());
+@@ -233,6 +233,8 @@
+ {
+     if (managingLayout()) {
+         managingLayout()->invalidate();
++    } else {
++        setGeometry(QRectF(pos(), sizeHint()));
+     }
+ }
+ 
+@@ -241,7 +243,7 @@
+     if (layout()) {
+         return layout()->sizeHint();
+     } else {
+-        return QSizeF();
++        return boundingRect().size();
+     }
+ }
+ 
+@@ -325,7 +327,7 @@
+         // Recreate the pixmap if it's gone.
+         if (pix.isNull()) {
+             pix = QPixmap(d->cacheSize);
+- 	    pix.fill(Qt::transparent);
++            pix.fill(Qt::transparent);
+             exposed = brect;
+         }
+ 
+--- a/libs/plasma/widgets/boxlayout.cpp
++++ b/libs/plasma/widgets/boxlayout.cpp
+@@ -396,12 +396,11 @@
+         else
+             expansionSpace[i] = 0;
+ 
++        available -= sizes[i];
+         // adjust the per-item size if the space was over or under used
+         if ( sizes[i] != perItemSize && i != sizes.count()-1 ) {
+             perItemSize = available / (sizes.count()-i-1);
+         }
+-
+-        available -= sizes[i];
+     }
+ 
+     // distribute out any remaining space to items which can still expand
+--- a/libs/plasma/widgets/lineedit.cpp
++++ b/libs/plasma/widgets/lineedit.cpp
+@@ -186,7 +186,6 @@
+ 
+ QSizeF LineEdit::sizeHint() const
+ {
+-    kDebug() << "LineEdit::sizeeHint() " << document()->size();
+     return document()->size();
+ }
+ 
+--- a/libs/plasma/corona.h
++++ b/libs/plasma/corona.h
+@@ -146,13 +146,6 @@
+     QList<Containment*> containments() const;
+ 
+     /**
+-     * Adds a SuperKaramba theme to the scene
+-     *
+-     * @param path the path to the theme file
+-     */
+-    void addKaramba(const KUrl& path);
+-
+-    /**
+      * Sets if the applets are Immutable
+      */
+     void setImmutable(bool immutable_);
+--- a/libs/plasma/appletbrowser.cpp
++++ b/libs/plasma/appletbrowser.cpp
+@@ -2,16 +2,16 @@
+  *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
+  *
+  *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License version 2 (or,
+- *   at your option, any later version) as published by the Free Software
+- *   Foundation
++ *   it under the terms of the GNU Library/Lesser General Public License
++ *   version 2, or (at your option) any later version, as published by the
++ *   Free Software Foundation
+  *
+  *   This program is distributed in the hope that it will be useful,
+  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *   GNU General Public License for more details
+  *
+- *   You should have received a copy of the GNU Library General Public
++ *   You should have received a copy of the GNU Library/Lesser General Public
+  *   License along with this program; if not, write to the
+  *   Free Software Foundation, Inc.,
+  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+@@ -21,6 +21,8 @@
+ 
+ #include <KAction>
+ #include <KStandardAction>
++#include <KConfig>
++#include <KConfigGroup>
+ 
+ 
+ #include "plasma/corona.h"
+@@ -38,17 +40,24 @@
+         : corona(co),
+           containment(cont),
+           appletList(0),
+-          itemModel(q),
++          config("plasmarc"),
++          configGroup(&config, "Applet Browser"),
++          itemModel(configGroup, q),
+           filterModel(q)
+     {
+-
+     }
+ 
+     Plasma::Corona *corona;
+     Plasma::Containment *containment;
+     KCategorizedItemsView *appletList;
++    
++    KConfig config;
++    KConfigGroup configGroup;
++
+     PlasmaAppletItemModel itemModel;
+     KCategorizedItemsViewModels::DefaultFilterModel filterModel;
++    
++
+ };
+ 
+ AppletBrowser::AppletBrowser(Plasma::Corona * corona, QWidget * parent, Qt::WindowFlags f)
+@@ -70,6 +79,8 @@
+     d->appletList = new KCategorizedItemsView(this);
+     setMainWidget(d->appletList);
+ 
++    setWindowTitle("Add Applets");
++
+     setButtons(KDialog::Apply | KDialog::Close | KDialog::User1);
+     setButtonText(KDialog::Apply, i18n("Add Applet"));
+     setButtonText(KDialog::User1, i18n("Get New Applets")); //TODO: not overly happy with this text
+@@ -81,20 +92,38 @@
+     QAction* quit = KStandardAction::quit(qApp, SLOT(quit()), this);
+     addAction(quit);
+ 
+-    // Emblems
+-    d->appletList->addEmblem(i18n("Recommended by KDE"), new KIcon("about-kde"), 
+-                                KCategorizedItemsViewModels::Filter("recommended", true));
+-    d->appletList->addEmblem(i18n("Used in past"), new KIcon("history"), 
++    d->filterModel.addFilter(i18n("All Applets"),
++        KCategorizedItemsViewModels::Filter(), new KIcon("application-x-plasma"));
++    
++    // Recommended emblems and filters
++    QRegExp rx("recommended[.]([0-9A-Za-z]+)[.]caption");
++    QMapIterator<QString, QString> i(d->configGroup.entryMap());
++    while (i.hasNext()) {
++        i.next();
++        if (!rx.exactMatch(i.key())) continue;
++        kDebug() << "These are the key/vals in rc file " << rx.cap(1) << "\n";
++        
++        QString id = rx.cap(1);
++        QString caption = d->configGroup.readEntry("recommended." + id + ".caption");
++        QString icon    = d->configGroup.readEntry("recommended." + id + ".icon");
++        QString plugins = d->configGroup.readEntry("recommended." + id + ".plugins");
++        
++        d->appletList->addEmblem(i18n("Recommended by %1", caption), new KIcon(icon), 
++            KCategorizedItemsViewModels::Filter("recommended." + id, true));
++        d->filterModel.addFilter(i18n("Recommended by %1", caption),
++            KCategorizedItemsViewModels::Filter("recommended." + id, true), new KIcon(icon));
++        
++        //foreach (QString plugin, plugins.split(",")) {}
++    }
++
++    // Other Emblems
++    d->appletList->addEmblem(i18n("Used in Past"), new KIcon("history"), 
+                                 KCategorizedItemsViewModels::Filter("used", true));
+ 
+     // Filters: Special
+-    d->filterModel.addFilter(i18n("All applets"),
+-        KCategorizedItemsViewModels::Filter(), new KIcon("application-x-plasma"));
+-    d->filterModel.addFilter(i18n("Recommended by KDE"),
+-        KCategorizedItemsViewModels::Filter("recommended", true), new KIcon("about-kde"));
+     d->filterModel.addFilter(i18n("Favorites"),
+         KCategorizedItemsViewModels::Filter("favorite", true), new KIcon("bookmark"));
+-    d->filterModel.addFilter(i18n("Used in past"),
++    d->filterModel.addFilter(i18n("Used in Past"),
+         KCategorizedItemsViewModels::Filter("used", true), new KIcon("history"));
+ 
+     d->filterModel.addSeparator(i18n("Categories:"));
+@@ -124,10 +153,12 @@
+         kDebug() << "Adding applet " << selectedItem->name();
+         if (d->corona) {
+             kDebug() << " to corona\n";
+-            d->corona->addApplet(selectedItem->pluginName());
++            d->corona->addApplet(selectedItem->pluginName(),
++                    selectedItem->arguments());
+         } else if (d->containment) {
+-            kDebug() << " to conatainment\n";
+-            d->containment->addApplet(selectedItem->pluginName());
++            kDebug() << " to containment\n";
++            d->containment->addApplet(selectedItem->pluginName(),
++                    selectedItem->arguments());
+         }
+ 
+     }
+--- a/libs/taskmanager/taskrmbmenu.cpp
++++ b/libs/taskmanager/taskrmbmenu.cpp
+@@ -63,79 +63,80 @@
+ 
+ void TaskRMBMenu::fillMenu(Task::TaskPtr t)
+ {
+-    int id;
+-    setCheckable(true);
++    QAction *a;
+ 
+-    insertItem(i18n("Ad&vanced"), makeAdvancedMenu(t));
++    addMenu(makeAdvancedMenu(t));
+     bool checkActions = KWindowSystem::allowedActionsSupported();
+ 
+     if (TaskManager::self()->numberOfDesktops() > 1)
+     {
+-        id = insertItem(i18n("To &Desktop"), makeDesktopsMenu(t));
++        a = addMenu(makeDesktopsMenu(t));
+ 
+         if (showAll)
+         {
+-            id = insertItem(i18n("&To Current Desktop"),
++            a = addAction(i18n("&To Current Desktop"),
+                             t.data(), SLOT(toCurrentDesktop()));
+-            setItemEnabled( id, !t->isOnCurrentDesktop() );
++            a->setEnabled(!t->isOnCurrentDesktop());
+         }
+ 
+         if (checkActions)
+         {
+-            setItemEnabled(id, t->info().actionSupported(NET::ActionChangeDesktop));
++            a->setEnabled(t->info().actionSupported(NET::ActionChangeDesktop));
+         }
+     }
+ 
+-    id = insertItem(KIcon("move"), i18n("&Move"), t.data(), SLOT(move()));
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMove));
++    a = addAction(KIcon("move"), i18n("&Move"), t.data(), SLOT(move()));
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionMove));
+ 
+-    id = insertItem(i18n("Re&size"), t.data(), SLOT(resize()));
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionResize));
++    a = addAction(i18n("Re&size"), t.data(), SLOT(resize()));
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionResize));
+ 
+-    id = insertItem(i18n("Mi&nimize"), t.data(), SLOT(toggleIconified()));
+-    setItemChecked(id, t->isIconified());
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMinimize));
+-
+-    id = insertItem(i18n("Ma&ximize"), t.data(), SLOT(toggleMaximized()));
+-    setItemChecked(id, t->isMaximized());
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMax));
+-
+-    id = insertItem(i18n("&Shade"), t.data(), SLOT(toggleShaded()));
+-    setItemChecked(id, t->isShaded());
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionShade));
++    a = addAction(i18n("Mi&nimize"), t.data(), SLOT(toggleIconified()));
++    a->setCheckable(true);
++    a->setChecked(t->isIconified());
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionMinimize));
++
++    a = addAction(i18n("Ma&ximize"), t.data(), SLOT(toggleMaximized()));
++    a->setCheckable(true);
++    a->setChecked(t->isMaximized());
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionMax));
++
++    a = addAction(i18n("&Shade"), t.data(), SLOT(toggleShaded()));
++    a->setCheckable(true);
++    a->setChecked(t->isShaded());
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionShade));
+ 
+     addSeparator();
+ 
+-    id = insertItem(KIcon("window-close"), i18n("&Close"), t.data(), SLOT(close()));
+-    setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionClose));
++    a = addAction(KIcon("window-close"), i18n("&Close"), t.data(), SLOT(close()));
++    a->setEnabled(!checkActions || t->info().actionSupported(NET::ActionClose));
+ }
+ 
+ void TaskRMBMenu::fillMenu()
+ {
+-	int id;
+-	setCheckable( true );
++    QAction *a;
+ 
+     Task::List::iterator itEnd = tasks.end();
+     for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+     {
+-		Task::TaskPtr t = (*it);
++        Task::TaskPtr t = (*it);
+ 
+-		id = insertItem( QIcon( t->pixmap() ),
+-				 t->visibleNameWithState(),
+-		                 new TaskRMBMenu(t, this) );
+-		setItemChecked( id, t->isActive() );
+-		connectItem( id, t.data(), SLOT( activateRaiseOrIconify() ) );
+-	}
++        a = addMenu( new TaskRMBMenu(t, this) );
++        a->setIcon( QIcon( t->pixmap() ) );
++        a->setText( t->visibleNameWithState() );
++        a->setChecked(t->isActive());
++        connect( a, SIGNAL(triggered()), t.data(), SLOT( activateRaiseOrIconify() ) );
++    }
+ 
+-	addSeparator();
++    addSeparator();
+ 
+     bool enable = false;
+ 
+     if (TaskManager::self()->numberOfDesktops() > 1)
+     {
+-        id = insertItem(i18n("All to &Desktop"), makeDesktopsMenu());
++        a = addMenu(makeDesktopsMenu());
+ 
+-        id = insertItem(i18n("All &to Current Desktop"), this, SLOT(slotAllToCurrentDesktop()));
++        a = addAction(i18n("All &to Current Desktop"), this, SLOT(slotAllToCurrentDesktop()));
+         Task::List::iterator itEnd = tasks.end();
+         for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+         {
+@@ -145,80 +146,82 @@
+                 break;
+             }
+         }
+-        setItemEnabled(id, enable);
++        a->setEnabled(enable);
+     }
+ 
+     enable = false;
+ 
+-	id = insertItem( i18n( "Mi&nimize All" ), this, SLOT( slotMinimizeAll() ) );
++    a = addAction( i18n( "Mi&nimize All" ), this, SLOT( slotMinimizeAll() ) );
+     itEnd = tasks.end();
+     for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+     {
+-		if( !(*it)->isIconified() ) {
+-			enable = true;
+-			break;
+-		}
+-	}
+-	setItemEnabled( id, enable );
++        if( !(*it)->isIconified() ) {
++            enable = true;
++            break;
++        }
++    }
++    a->setEnabled( enable );
+ 
+-	enable = false;
++    enable = false;
+ 
+-	id = insertItem( i18n( "Ma&ximize All" ), this, SLOT( slotMaximizeAll() ) );
++    a = addAction( i18n( "Ma&ximize All" ), this, SLOT( slotMaximizeAll() ) );
+     itEnd = tasks.end();
+     for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+     {
+         if( !(*it)->isMaximized() ) {
+-			enable = true;
+-			break;
+-		}
+-	}
+-	setItemEnabled( id, enable );
++            enable = true;
++            break;
++        }
++    }
++    a->setEnabled( enable );
+ 
+-	enable = false;
++    enable = false;
+ 
+-	id = insertItem( i18n( "&Restore All" ), this, SLOT( slotRestoreAll() ) );
++    a = addAction( i18n( "&Restore All" ), this, SLOT( slotRestoreAll() ) );
+     itEnd = tasks.end();
+     for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+     {
+-		if( (*it)->isIconified() || (*it)->isMaximized() ) {
+-			enable = true;
+-			break;
+-		}
+-	}
+-	setItemEnabled( id, enable );
++        if( (*it)->isIconified() || (*it)->isMaximized() ) {
++            enable = true;
++            break;
++        }
++    }
++    a->setEnabled( enable );
+ 
+-	addSeparator();
++    addSeparator();
+ 
+-	enable = false;
++    enable = false;
+ 
+-	insertItem( KIcon( "list-remove" ), i18n( "&Close All" ), this, SLOT( slotCloseAll() ) );
++    addAction( KIcon( "list-remove" ), i18n( "&Close All" ), this, SLOT( slotCloseAll() ) );
+ }
+ 
+ QMenu* TaskRMBMenu::makeAdvancedMenu(Task::TaskPtr t)
+ {
+-    int id;
++    QAction *a;
+     QMenu* menu = new QMenu(this);
++    menu->setTitle(i18n("Ad&vanced"));
+ 
+-    menu->setCheckable(true);
+-
+-    id = menu->insertItem(KIcon("go-up"),
++    a = menu->addAction(KIcon("go-up"),
+                           i18n("Keep &Above Others"),
+                           t.data(), SLOT(toggleAlwaysOnTop()));
+-    menu->setItemChecked(id, t->isAlwaysOnTop());
++    a->setCheckable(true);
++    a->setChecked(t->isAlwaysOnTop());
+ 
+-    id = menu->insertItem(KIcon("go-down"),
++    a = menu->addAction(KIcon("go-down"),
+                           i18n("Keep &Below Others"),
+                           t.data(), SLOT(toggleKeptBelowOthers()));
+-    menu->setItemChecked(id, t->isKeptBelowOthers());
++    a->setCheckable(true);
++    a->setChecked(t->isKeptBelowOthers());
+ 
+-    id = menu->insertItem(KIcon("view-fullscreen"),
++    a = menu->addAction(KIcon("view-fullscreen"),
+                           i18n("&Fullscreen"),
+                           t.data(), SLOT(toggleFullScreen()));
+-    menu->setItemChecked(id, t->isFullScreen());
++    a->setCheckable(true);
++    a->setChecked(t->isFullScreen());
+ 
+     if (KWindowSystem::allowedActionsSupported())
+     {
+-        menu->setItemEnabled(id, t->info().actionSupported(NET::ActionFullScreen));
++        a->setEnabled(t->info().actionSupported(NET::ActionFullScreen));
+     }
+ 
+     return menu;
+@@ -226,39 +229,44 @@
+ 
+ QMenu* TaskRMBMenu::makeDesktopsMenu(Task::TaskPtr t)
+ {
+-	QMenu* m = new QMenu( this );
+-	m->setCheckable( true );
+-
+-	int id = m->insertItem( i18n("&All Desktops"), t.data(), SLOT( toDesktop(int) ) );
+-	m->setItemParameter( id, 0 ); // 0 means all desktops
+-	m->setItemChecked( id, t->isOnAllDesktops() );
+-
+-	m->addSeparator();
+-
+-	for (int i = 1; i <= TaskManager::self()->numberOfDesktops(); i++) {
+-		QString name = QString("&%1 %2").arg(i).arg(TaskManager::self()->desktopName(i).replace('&', "&&"));
+-		id = m->insertItem( name, t.data(), SLOT( toDesktop(int) ) );
+-		m->setItemParameter( id, i );
+-		m->setItemChecked( id, !t->isOnAllDesktops() && t->desktop() == i );
+-	}
++    QMenu* m = new QMenu( this );
++    int it = toDesktopMap.size() + 1;
++    m->setTitle( i18n("To &Desktop") );
++
++    QAction *a = m->addAction( i18n("&All Desktops"), this, SLOT( slotToDesktop() ) );
++    a->setCheckable(true);
++    toDesktopMap.append( QPair<KSharedPtr<Task>, int>( t, 0 ) ); // 0 means all desktops
++    a->setData( it++ );
++    a->setChecked( t->isOnAllDesktops() );
++
++    m->addSeparator();
++
++    for (int i = 1; i <= TaskManager::self()->numberOfDesktops(); i++) {
++        QString name = QString("&%1 %2").arg(i).arg(TaskManager::self()->desktopName(i).replace('&', "&&"));
++        a = m->addAction( name, this, SLOT( slotToDesktop() ) );
++        a->setCheckable(true);
++        toDesktopMap.append( QPair<KSharedPtr<Task>, int>( t, i ) );
++        a->setData( i );
++        a->setChecked( !t->isOnAllDesktops() && t->desktop() == i );
++    }
+ 
+-	return m;
++    return m;
+ }
+ 
+ QMenu* TaskRMBMenu::makeDesktopsMenu()
+ {
+ 	QMenu* m = new QMenu( this );
+-	m->setCheckable( true );
++	QAction *a;
+ 
+-	int id = m->insertItem( i18n("&All Desktops"), this, SLOT( slotAllToDesktop(int) ) );
+-	m->setItemParameter( id, 0 ); // 0 means all desktops
++	a = m->addAction( i18n("&All Desktops"), this, SLOT( slotAllToDesktop() ) );
++	a->setData( 0 ); // 0 means all desktops
+ 
+ 	m->addSeparator();
+ 
+ 	for (int i = 1; i <= TaskManager::self()->numberOfDesktops(); i++) {
+ 		QString name = QString("&%1 %2").arg(i).arg(TaskManager::self()->desktopName(i).replace('&', "&&"));
+-		id = m->insertItem( name, this, SLOT( slotAllToDesktop(int) ) );
+-		m->setItemParameter( id, i );
++		a = m->addAction( name, this, SLOT( slotAllToDesktop() ) );
++		a->setData( i );
+ 	}
+ 
+ 	return m;
+@@ -309,12 +317,16 @@
+     }
+ }
+ 
+-void TaskRMBMenu::slotAllToDesktop( int desktop )
++void TaskRMBMenu::slotAllToDesktop()
+ {
+-    Task::List::iterator itEnd = tasks.end();
+-    for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+-    {
+-        (*it)->toDesktop( desktop );
++    QAction *action = qobject_cast<QAction *>( sender() );
++    if( action ) {
++      int desktop = action->data().toInt();
++      Task::List::iterator itEnd = tasks.end();
++      for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
++      {
++          (*it)->toDesktop( desktop );
++      }
+     }
+ }
+ 
+@@ -326,3 +338,12 @@
+         (*it)->toCurrentDesktop();
+     }
+ }
++
++void TaskRMBMenu::slotToDesktop()
++{
++    QAction *action = qobject_cast<QAction *>( sender() );
++    if( action ) {
++        QPair<KSharedPtr<Task>, int> pair = toDesktopMap[action->data().toInt()];
++        pair.first->toDesktop( pair.second );
++    }
++}
+--- a/libs/taskmanager/CMakeLists.txt
++++ b/libs/taskmanager/CMakeLists.txt
+@@ -3,7 +3,7 @@
+ 
+ ########### next target ###############
+ 
+-set(taskmanager_LIB_SRCS taskmanager.cpp) 
++set(taskmanager_LIB_SRCS taskmanager.cpp taskrmbmenu.cpp) 
+ 
+ kde4_add_library(taskmanager SHARED ${taskmanager_LIB_SRCS})
+ 
+--- a/libs/taskmanager/taskmanager.cpp
++++ b/libs/taskmanager/taskmanager.cpp
+@@ -145,7 +145,7 @@
+     connect( d->startupInfo,
+         SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
+         SLOT( killStartup( const KStartupInfoId& )));
+-    c.changeGroup( "TaskbarButtonSettings" );
++    c=KConfigGroup(&_c, "TaskbarButtonSettings");
+     d->startupInfo->setTimeout( c.readEntry( "Timeout", 30 ));
+ }
+ 
+--- a/libs/taskmanager/taskrmbmenu.h
++++ b/libs/taskmanager/taskrmbmenu.h
+@@ -26,6 +26,8 @@
+ #define __taskrmbmenu_h__
+ 
+ #include <QMenu>
++#include <QList>
++#include <QPair>
+ 
+ class KDE_EXPORT TaskRMBMenu : public QMenu
+ {
+@@ -48,12 +50,14 @@
+ 	void slotRestoreAll();
+ 	void slotShadeAll();
+ 	void slotCloseAll();
+-	void slotAllToDesktop( int desktop );
++	void slotAllToDesktop();
+ 	void slotAllToCurrentDesktop();
++	void slotToDesktop();
+ 
+ private:
+ 	Task::List tasks;
+ 	bool showAll;
++	QList< QPair<KSharedPtr<Task>, int> > toDesktopMap;
+ };
+ 
+ #endif
+--- a/libs/workspace/kworkspace.cpp
++++ b/libs/workspace/kworkspace.cpp
+@@ -31,6 +31,7 @@
+ #include <stdlib.h> // getenv()
+ #include <ksmserver_interface.h>
+ #include <kdefakes.h>
++#include <QSocketNotifier>
+ 
+ #ifdef Q_WS_X11
+ #include <X11/Xlib.h>
+@@ -46,17 +47,113 @@
+ #define DISPLAY "QWS_DISPLAY"
+ #endif
+ 
++#include <unistd.h>
++#include <pwd.h>
++#include <sys/types.h>
++
++#include "kworkspace_p.h"
++
+ namespace KWorkSpace
+ {
+ 
+-static SmcConn tmpSmcConnection = 0;
++static void save_yourself_callback( SmcConn conn_P, SmPointer, int, Bool , int, Bool )
++    {
++    SmcSaveYourselfDone( conn_P, True );
++    }
++
++static void dummy_callback( SmcConn, SmPointer )
++    {
++    }
++
++KRequestShutdownHelper::KRequestShutdownHelper()
++    {
++    SmcCallbacks calls;
++    calls.save_yourself.callback = save_yourself_callback;
++    calls.die.callback = dummy_callback;
++    calls.save_complete.callback = dummy_callback;
++    calls.shutdown_cancelled.callback = dummy_callback;
++    char* id = NULL;
++    char err[ 11 ];
++    conn = SmcOpenConnection( NULL, NULL, 1, 0,
++        SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
++        | SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err );
++    if( id != NULL )
++        free( id );
++    if( conn == NULL )
++        return; // no SM
++    // set the required properties, mostly dummy values
++    SmPropValue propvalue[ 5 ];
++    SmProp props[ 5 ];
++    propvalue[ 0 ].length = sizeof( int );
++    int value0 = SmRestartNever; // so that this extra SM connection doesn't interfere
++    propvalue[ 0 ].value = &value0;
++    props[ 0 ].name = const_cast< char* >( SmRestartStyleHint );
++    props[ 0 ].type = const_cast< char* >( SmCARD8 );
++    props[ 0 ].num_vals = 1;
++    props[ 0 ].vals = &propvalue[ 0 ];
++    struct passwd* entry = getpwuid( geteuid() );
++    propvalue[ 1 ].length = entry != NULL ? strlen( entry->pw_name ) : 0;
++    propvalue[ 1 ].value = (SmPointer)( entry != NULL ? entry->pw_name : "" );
++    props[ 1 ].name = const_cast< char* >( SmUserID );
++    props[ 1 ].type = const_cast< char* >( SmARRAY8 );
++    props[ 1 ].num_vals = 1;
++    props[ 1 ].vals = &propvalue[ 1 ];
++    propvalue[ 2 ].length = 0;
++    propvalue[ 2 ].value = (SmPointer)( "" );
++    props[ 2 ].name = const_cast< char* >( SmRestartCommand );
++    props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
++    props[ 2 ].num_vals = 1;
++    props[ 2 ].vals = &propvalue[ 2 ];
++    propvalue[ 3 ].length = strlen( "requestshutdownhelper" );
++    propvalue[ 3 ].value = (SmPointer)"requestshutdownhelper";
++    props[ 3 ].name = const_cast< char* >( SmProgram );
++    props[ 3 ].type = const_cast< char* >( SmARRAY8 );
++    props[ 3 ].num_vals = 1;
++    props[ 3 ].vals = &propvalue[ 3 ];
++    propvalue[ 4 ].length = 0;
++    propvalue[ 4 ].value = (SmPointer)( "" );
++    props[ 4 ].name = const_cast< char* >( SmCloneCommand );
++    props[ 4 ].type = const_cast< char* >( SmLISTofARRAY8 );
++    props[ 4 ].num_vals = 1;
++    props[ 4 ].vals = &propvalue[ 4 ];
++    SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
++    SmcSetProperties( conn, 5, p );
++    notifier = new QSocketNotifier( IceConnectionNumber( SmcGetIceConnection( conn )),
++        QSocketNotifier::Read, this );
++    connect( notifier, SIGNAL( activated( int )), SLOT( processData()));
++    }
++
++KRequestShutdownHelper::~KRequestShutdownHelper()
++    {
++    if( conn != NULL )
++        {
++        delete notifier;
++        SmcCloseConnection( conn, 0, NULL );
++        }
++    }
++
++void KRequestShutdownHelper::processData()
++    {
++    if( conn != NULL )
++        IceProcessMessages( SmcGetIceConnection( conn ), 0, 0 );
++    }
++
++bool KRequestShutdownHelper::requestShutdown( ShutdownConfirm confirm )
++    {
++    if( conn == NULL )
++        return false;
++    SmcRequestSaveYourself( conn, SmSaveBoth, True, SmInteractStyleAny,
++        confirm == ShutdownConfirmNo, True );
++    // flush the request
++    IceFlush(SmcGetIceConnection(conn));
++    return true;
++    }
++
++static KRequestShutdownHelper* helper = NULL;
+ 
+ static void cleanup_sm()
+ {
+-  if (tmpSmcConnection) {
+-      SmcCloseConnection( tmpSmcConnection, 0, 0 );
+-      tmpSmcConnection = 0;
+-  }
++    delete helper;
+ }
+ 
+ bool requestShutDown(
+@@ -73,51 +170,12 @@
+         QDBusReply<void> reply = ksmserver.logout((int)confirm,  (int)sdtype,  (int)sdmode);
+         return (reply.isValid());
+     }
+-
+-    if (! tmpSmcConnection) {
+-	char cerror[256];
+-	char* myId = 0;
+-	char* prevId = 0;
+-	SmcCallbacks cb;
+-	tmpSmcConnection = SmcOpenConnection( 0, 0, 1, 0,
+-					      0, &cb,
+-					      prevId,
+-					      &myId,
+-					      255,
+-					      cerror );
+-	::free( myId ); // it was allocated by C
+-	if (!tmpSmcConnection )
+-	    return false;
+-
++    if( helper == NULL )
++    {
++        helper = new KRequestShutdownHelper();
+         qAddPostRoutine(cleanup_sm);
+     }
+-
+-    if ( tmpSmcConnection ) {
+-        // we already have a connection to the session manager, use it.
+-        SmcRequestSaveYourself( tmpSmcConnection, SmSaveBoth, True,
+-				SmInteractStyleAny,
+-				confirm == ShutdownConfirmNo, True );
+-
+-	// flush the request
+-	IceFlush(SmcGetIceConnection(tmpSmcConnection));
+-        return true;
+-    }
+-
+-    // open a temporary connection, if possible
+-
+-    propagateSessionManager();
+-    QByteArray smEnv = ::getenv("SESSION_MANAGER");
+-    if (smEnv.isEmpty())
+-        return false;
+-
+-    SmcRequestSaveYourself( tmpSmcConnection, SmSaveBoth, True,
+-			    SmInteractStyleAny, False, True );
+-
+-    // flush the request
+-    IceFlush(SmcGetIceConnection(tmpSmcConnection));
+-    SmcCloseConnection( tmpSmcConnection, 0, 0 );
+-
+-    return true;
++    return helper->requestShutdown( confirm );
+ }
+ 
+ static QTime smModificationTime;
+@@ -156,3 +214,4 @@
+ 
+ } // end namespace
+ 
++#include "kworkspace_p.moc"
+--- /dev/null
++++ b/libs/workspace/kworkspace_p.h
+@@ -0,0 +1,49 @@
++/* This file is part of the KDE libraries
++    Copyright (C) 2007 Lubos Lunak <l.lunak at kde.org>
++
++    This library is free software; you can redistribute it and/or
++    modify it under the terms of the GNU Library General Public
++    License as published by the Free Software Foundation; either
++    version 2 of the License, or (at your option) any later version.
++
++    This library is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++    Library General Public License for more details.
++
++    You should have received a copy of the GNU Library General Public License
++    along with this library; see the file COPYING.LIB.  If not, write to
++    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++    Boston, MA 02110-1301, USA.
++*/
++
++#ifndef KWORKSPACE_P_H
++#define KWORKSPACE_P_H
++
++#include "kworkspace.h"
++
++class QSocketNotifier;
++
++namespace KWorkSpace
++{
++
++// A class that creates another connection to ksmserver and handles it properly.
++class KRequestShutdownHelper
++    : public QObject
++    {
++    Q_OBJECT
++    public:
++        KRequestShutdownHelper();
++        virtual ~KRequestShutdownHelper();
++        bool requestShutdown( ShutdownConfirm confirm );
++    private slots:
++        void processData();
++    private:
++        SmcConn connection() const { return conn; }
++        QSocketNotifier* notifier;
++        SmcConn conn;
++    };
++ 
++}
++
++#endif
+--- a/kscreensaver/libkscreensaver/main.cpp
++++ b/kscreensaver/libkscreensaver/main.cpp
+@@ -115,7 +115,7 @@
+        args->clear();
+        dlg->exec();
+        delete dlg;
+-       exit(0);
++       return 0;
+     }
+ 
+     if (args->isSet("window-id"))
+--- a/kscreensaver/libkscreensaver/screensaver.desktop
++++ b/kscreensaver/libkscreensaver/screensaver.desktop
+@@ -9,6 +9,7 @@
+ Comment[csb]=Wëgaszôcz ekranu
+ Comment[de]=Bildschirmschoner
+ Comment[el]=Προφύλαξη οθόνης
++Comment[et]=Ekraanisäästja
+ Comment[fa]=محافظ صفحه نمایش
+ Comment[ga]=Spárálaí Scáileáin
+ Comment[he]=שומר מסך
+--- a/kscreensaver/krandom_screensaver/random.cpp
++++ b/kscreensaver/krandom_screensaver/random.cpp
+@@ -52,6 +52,15 @@
+ 
+ static const char version[] = "2.0.0";
+ 
++static QString exeFromActionGroup(const QList<KServiceAction>& actions, const char* name)
++{
++    foreach(const KServiceAction& action, actions) {
++        if (action.name() == name)
++            return action.exec();
++    }
++    return QString();
++}
++
+ //----------------------------------------------------------------------------
+ 
+ int main(int argc, char *argv[])
+@@ -93,76 +102,54 @@
+ 		windowId = RootWindow(QX11Info::display(), info.screen());
+ 	}
+ 	args->clear();
+-	KService::List lst = KServiceTypeTrader::self()->query( "ScreenSaver");
+-	QStringList saverFileList;
++	const KService::List lst = KServiceTypeTrader::self()->query( "ScreenSaver");
++        KService::List availableSavers;
+ 
+ 	KConfig type("krandom.kssrc", KConfig::CascadeConfig);
+         const KConfigGroup configGroup = type.group("Settings");
+-	bool opengl = configGroup.readEntry("OpenGL", false);
+-	bool manipulatescreen = configGroup.readEntry("ManipulateScreen", false);
+-        bool fortune = !KStandardDirs::findExe("fortune").isEmpty();
+-        for( KService::List::const_iterator it = lst.begin();
+-            it != lst.end(); ++it)
+-	{
+-		QString file = KStandardDirs::locate("services", (*it)->entryPath());
+-		kDebug() << "Looking at " << file;
+-		KDesktopFile saver( file );
+-		kDebug() << "read X-KDE-Type";
+-		QString saverType = saver.desktopGroup().readEntry("X-KDE-Type");
+-		if (saverType.isEmpty()) // no X-KDE-Type defined so must be OK
+-		{
+-			saverFileList.append(file);
+-		}
+-		else
+-		{
+-			QStringList saverTypes = saverType.split( ";");
+-			for (QStringList::ConstIterator it =  saverTypes.begin(); it != saverTypes.end(); ++it )
+-			{
+-				kDebug() << "saverTypes is "<< *it;
+-				if (*it == "ManipulateScreen")
+-				{
+-					if (manipulatescreen)
+-					{
+-						saverFileList.append(file);
+-					}
+-				}
+-				else
+-				if (*it == "OpenGL")
+-				{
+-					if (opengl)
+-					{
+-						saverFileList.append(file);
+-					}
+-				}
+-				if (*it == "Fortune")
+-				{
+-					if (fortune)
+-					{
+-						saverFileList.append(file);
+-					}
+-				}
+-
+-			}
++	const bool opengl = configGroup.readEntry("OpenGL", false);
++	const bool manipulatescreen = configGroup.readEntry("ManipulateScreen", false);
++        // TODO replace this with TryExec=fortune in the desktop files
++        const bool fortune = !KStandardDirs::findExe("fortune").isEmpty();
++        foreach( const KService::Ptr& service, lst ) {
++            //QString file = KStandardDirs::locate("services", service->entryPath());
++            //kDebug() << "Looking at " << file;
++            const QString saverType = service->property("X-KDE-Type").toString();
++            if (saverType.isEmpty()) { // no X-KDE-Type defined so must be OK
++                availableSavers.append(service);
++            } else {
++                const QStringList saverTypes = saverType.split( ";");
++                for (QStringList::ConstIterator it =  saverTypes.begin(); it != saverTypes.end(); ++it ) {
++                    kDebug() << "saverTypes is "<< *it;
++                    if (*it == "ManipulateScreen") {
++                        if (manipulatescreen) {
++                            availableSavers.append(service);
++                        }
++                    } else if (*it == "OpenGL") {
++                        if (opengl) {
++                            availableSavers.append(service);
++                        }
++                    } else if (*it == "Fortune") {
++                        if (fortune) {
++                            availableSavers.append(service);
++                        }
++                    }
+ 		}
++            }
+ 	}
+ 
+ 	KRandomSequence rnd;
+-	int indx = rnd.getLong(saverFileList.count());
+-	QString filename = saverFileList.at(indx);
++	const int indx = rnd.getLong(availableSavers.count());
++        const KService::Ptr service = availableSavers.at(indx);
++        const QList<KServiceAction> actions = service->actions();
+ 
+-	KDesktopFile config( filename );
+-
+-        KConfigGroup cg = config.desktopGroup();
+ 	QString cmd;
+-	if (windowId && config.hasActionGroup("InWindow"))
+-	{
+-		cg = config.actionGroup("InWindow");
+-	}
+-	else if ((windowId == 0) && config.hasActionGroup("Root"))
+-	{
+-		cg = config.actionGroup("Root");
+-	}
+-	cmd = cg.readPathEntry("Exec");
++	if (windowId)
++            cmd = exeFromActionGroup(actions, "InWindow");
++        if (cmd.isEmpty() && windowId == 0)
++            cmd = exeFromActionGroup(actions, "Root");
++        if (cmd.isEmpty())
++            cmd = service->exec();
+ 
+ 	QTextStream ts(&cmd, QIODevice::ReadOnly);
+ 	QString word;
+--- a/khotkeys/data/konqueror_gestures_kde321.khotkeys
++++ b/khotkeys/data/konqueror_gestures_kde321.khotkeys
+@@ -9,6 +9,7 @@
+ Comment[csb]=Pòdspòdlowé gestë Konquerora
+ Comment[de]=Grundlegende Gesten für Konqueror
+ Comment[el]=Βασικές χειρονομίες Konqueror.
++Comment[et]=Konquerori põhilised žestid.
+ Comment[fa]=وضعیتهای Konqueror پایه‌ای
+ Comment[fy]=Basis stjoerrings foar Konqueror.
+ Comment[ga]=Bunghothaí Konqueror.
+@@ -38,6 +39,7 @@
+ Name[csb]=Gestë Konquerora
+ Name[de]=Konqueror-Gesten
+ Name[el]=Χειρονομίες Konqueror
++Name[et]=Konquerori žestid
+ Name[fa]=وضعیتهای Konqueror
+ Name[fy]=Konqueror stjoerrings
+ Name[ga]=Gothaí Konqueror
+@@ -71,6 +73,7 @@
+ Comment[de]=Konqueror-Fenster
+ Comment[el]=Παράθυρο του Konqueror
+ Comment[es]=Ventana de Konqueror
++Comment[et]=Konquerori aken
+ Comment[fa]=پنجرۀ Konqueror
+ Comment[fy]=Konqueror finster
+ Comment[ga]=Fuinneog Konqueror
+@@ -127,6 +130,7 @@
+ Comment[bg]=Натискане, движение наляво, пускане.
+ Comment[de]=Drücken, nach links, loslassen.
+ Comment[el]=Πιέστε, μετακινηθείτε αριστερά, ελευθερώστε.
++Comment[et]=Vajuta, liiguta vasakule, vabasta.
+ Comment[fa]=فشار، حرکت به چپ، رها کردن
+ Comment[fy]=Yndrukke, nei lofts, loslitte
+ Comment[he]=לחץ, הזז שמאלה, שחרר
+@@ -157,6 +161,7 @@
+ Name[de]=Zurück
+ Name[el]=Πίσω
+ Name[es]=Atrás
++Name[et]=Tagasi
+ Name[fa]=عقب
+ Name[fy]=Werom
+ Name[ga]=Siar
+@@ -188,6 +193,7 @@
+ Comment[bg]=Стил Opera: натискане, движение нагоре, пускане.\nЗАБЕЛЕЖКА:Има конфликт с "Нов подпрозорец" и затова е изключено по подразбиране.
+ Comment[de]=Opera-Stil: Drücken, nach oben, loslassen.\nHinweis: Dies steht in Konflikt mit der Aktion "Neues Unterfenster" und ist daher in der Voreinstellung nicht aktiviert.
+ Comment[el]=Στυλ Opera: Πιέστε, μετακινήστε πάνω, ελευθερώστε.\nΣΗΜΕΙΩΣΗ: Αυτό συγκρούεται με την 'Νέα καρτέλα', και οπότε είναι προκαθορισμένα απενεργοποιημένο.
++Comment[et]=Opera stiilis: vajuta, liiguta üles, vabasta.\nMärkus: konfliktis toiminguga 'Uus kaart' ja seetõttu vaikimisi välja lülitatud.
+ Comment[fa]=سبک اَپرا: فشار، حرکت به بالا، رها کردن.\nنکته: ناسازگار با »تب جدید«، و به طور پیش‌فرض غیر فعال.
+ Comment[fy]=Opera-styl: yndrukke, nei omheech, loslitte.\nTink derom: Konflikten mei 'Nije ljepper', en sa binne standert útskeakele.
+ Comment[he]=נוסח Opera: לחץ, הזז למעלה, שחרר.\nשים לב: מחווה זו מתנגשת עם "לשונית חדשה" ולכן היא אינה מאופשרת כברירת מחדל.
+@@ -204,6 +210,7 @@
+ Name[de]=Ladevorgang abbrechen
+ Name[el]=Σταμάτημα φόρτωσης
+ Name[es]=Detener la carga
++Name[et]=Laadimise peatamine
+ Name[fa]=ایست بارگذاری
+ Name[fy]=it laden stopje
+ Name[he]=הפסק טעינה
+@@ -244,6 +251,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -269,6 +277,7 @@
+ Comment[bg]=Едно ниво нагоре в директорията..\nСтил Мозила: натискане, движение нагоре, движение наляво, движение нагоре, пускане.
+ Comment[de]=Geht in der Adress-/Ordnerstruktur eine Ebene höher.\nMozilla-Stil: Drücken, nach oben, nach links, nach oben, loslassen.
+ Comment[el]=Μετάβαση προς τα πάνω στη δομή URL/καταλόγου.\nΣτυλ Mozilla: Πιέστε, μετακίνηση πάνω, μετακίνηση αριστερά, μετακίνηση πάνω, ελευθέρωση.
++Comment[et]=Liikumine URL-i/kataloogistruktuuris üles.\nMozilla stiilis: vajuta, liiguta üles, liiguta vasakule, liiguta üles, vabasta.
+ Comment[fa]=بالا رفتن در ساختار نشانی وب/فهرست راهنما. \nسبک موزیلا: فشار، حرکت به بالا، حرکت به چپ، حرکت به بالا، رها کردن.
+ Comment[fy]=Omheech gean yn adres-/triemtafelstruktuer.\nMozilla-styl: Yndrukke, nei omheech, nei lofts, nei omheech, loslitte. 
+ Comment[it]=Risale nella struttura dell'URL o delle directory.\nStile Mozilla: Premi, sposta in su, sposta a sinistra, sposta in su, rilascia.
+@@ -296,6 +305,7 @@
+ Name[de]=Aufwärts
+ Name[el]=Πάνω
+ Name[es]=Arriba
++Name[et]=Üles
+ Name[fa]=بالا
+ Name[fy]=Omheech
+ Name[ga]=Suas
+@@ -338,6 +348,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -363,6 +374,7 @@
+ Comment[bg]=Едно ниво нагоре.\nСтил Opera: натискане, движение нагоре, движение наляво, движение нагоре, пускане.\nЗАБЕЛЕЖКА:Има конфликт с "Активиране на предишен подпрозорец" и затова е изключено по подразбиране.
+ Comment[de]=Geht in der Adress-/Ordnerstruktur eine Ebene höher.\nOpera-Stil: Drücken, nach oben, nach links, nach oben, loslassen.\nHinweis: Dies steht in Konflikt mit der Aktion "Vorheriges Unterfenster aktivieren und ist daher in der Voreinstellung nicht aktiviert.
+ Comment[el]=Μετάβαση προς τα πάνω στη δομή URL/καταλόγου.\nΣτυλ Opera: Πιέστε, μετακίνηση πάνω, μετακίνηση αριστερά, μετακίνηση πάνω, ελευθέρωση.\nΣΗΜΕΙΩΣΗ: Συγκρούεται με το "Ενεργοποίηση προηγούμενης καρτέλας", οπότε είναι προκαθορισμένα απενεργοποιημένο.
++Comment[et]=Liikumine URL-i/kataloogistruktuuris üles.\nOpera stiilis: vajuta, liiguta üles, liiguta vasakule, liiguta üles, vabasta.\nMärkus: konfliktis toiminguga "Eelmise kaardi aktiveerimine" ja seetõttu vaikimisi välja lülitatud.
+ Comment[fa]=بالا رفتن در ساختار نشانی وب/فهرست راهنما.\nسبک اَپرا: فشار، حرکت به بالا، حرکت به چپ، حرکت به بالا، رها کردن.\nنکته: ناسازگار با  »تب فعال قبلی«، و به طور پیش‌فرض غیر فعال است.
+ Comment[fy]=Omheech gean yn adres-/triemtafelstruktuer.\nOpera-styl: Yndrukke, nei omheech, nei lofts, nei omheech, loslitte. \nTink derom: Konflikten mei "Foarige ljepper aktivearje", en sa is standert útskeakele.
+ Comment[it]=Risale nella struttura dell'URL o directory.\nStile Opera: Premi, sposta in su, sposta a sinistra, sposta in su, rilascia.\nNOTA: È in conflitto con "Attiva scheda precedente", e quindi è normalmente disabilitato.
+@@ -386,12 +398,13 @@
+ Name[bg]=Нагоре #2
+ Name[de]=Nach oben (2)
+ Name[el]=Πάνω #2
++Name[et]=Üles nr. 2
+ Name[fy]=Omheech #2
+ Name[he]=למעלה 2
+ Name[it]=Su #2
+ Name[ja]=上 #2
+ Name[kk]=Жоғары #2
+-Name[km]=ឡើង​លើ #2
++Name[km]=ឡើងលើ #2
+ Name[nb]=Opp nr. 2
+ Name[nds]=Na baven (2)
+ Name[nl]=Omhoog #2
+@@ -422,6 +435,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -447,6 +461,7 @@
+ Comment[bg]=Натискане, движение нагоре, движение надясно, пускане.
+ Comment[de]=Drücken, nach oben, nach rechts, loslassen.
+ Comment[el]=Πίεση, μετακίνηση πάνω, μετακίνηση δεξιά, ελευθέρωση.
++Comment[et]=Vajuta, liiguta üles, liiguta paremale, vabasta.
+ Comment[fa]=فشار، حرکت به بالا، حرکت به راست، رها کردن.
+ Comment[fy]=Yndrukke, nei omheech, nei rjochts, loslitte.
+ Comment[it]=Premi, sposta in su, sposta a destra, rilascia.
+@@ -475,6 +490,7 @@
+ Name[de]=Nächstes Unterfenster aktivieren
+ Name[el]=Ενεργοποίηση επόμενης καρτέλας
+ Name[es]=Activar la siguiente solapa
++Name[et]=Järgmise kaardi aktiveerimine
+ Name[fa]=فعال کردن تب بعدی
+ Name[fy]=Folgjende ljepper aktivearje
+ Name[ga]=Gníomhachtaigh an Chéad Chluaisín Eile
+@@ -517,6 +533,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -542,6 +559,7 @@
+ Comment[bg]=Натискане, движение нагоре, движение наляво, пускане.
+ Comment[de]=Drücken, nach oben, nach links, loslassen.
+ Comment[el]=Πίεση, μετακίνηση πάνω, μετακίνηση αριστερά, ελευθέρωση.
++Comment[et]=Vajuta, liiguta üles, liiguta vasakule, vabasta.
+ Comment[fa]=فشار، حرکت به بالا، حرکت به چپ، رها کردن.
+ Comment[fy]=Yndrukke, nei omheech, neo lofts, loslitte.
+ Comment[it]=Premi, sposta in su, sposta a sinistra, rilascia.
+@@ -568,6 +586,7 @@
+ Name[de]=Vorheriges Unterfenster aktivieren
+ Name[el]=Ενεργοποίηση προηγούμενης καρτέλας
+ Name[es]=Activar la solapa anterior
++Name[et]=Eelmise kaardi aktiveerimine
+ Name[fa]=فعال کردن تب قبلی
+ Name[fy]=Foarige ljepper aktivearje
+ Name[ga]=Gníomhachtaigh an Cluaisín Roimhe Seo
+@@ -610,6 +629,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -647,6 +667,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -672,6 +693,7 @@
+ Comment[bg]=Натискане, движение надолу, движение нагоре, движение надолу, пускане.
+ Comment[de]=Drücken, nach unten, nach oben, nach unten, loslassen.
+ Comment[el]=Πίεση, μετακίνηση κάτω, μετακίνηση πάνω, μετακίνηση κάτω, ελευθέρωση.
++Comment[et]=Vajuta, liiguta alla, liiguta üles, liiguta alla, vabasta.
+ Comment[fa]=فشار، حرکت به پایین، حرکت به بالا، حرکت به پایین، رها کردن.
+ Comment[fy]=Yndrukke, nei omleech, nei omheech, nei omleech, loslitte.
+ Comment[it]=Premi, sposta in giù, sposta in su, sposta in giù, rilascia.
+@@ -697,6 +719,7 @@
+ Name[de]=Unterfenster duplizieren
+ Name[el]=Αντίγραφο καρτέλας
+ Name[es]=Duplicar la solapa
++Name[et]=Kaardi dubleerimine
+ Name[fa]=تب مضاعف
+ Name[fy]=Ljepper duplisearje
+ Name[he]=שכפל לשונית
+@@ -738,6 +761,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -763,6 +787,7 @@
+ Comment[bg]=Натискане, движение надолу, движение нагоре, пускане.
+ Comment[de]=Drücken, nach unten, nach oben, loslassen.
+ Comment[el]=Πίεση, μετακίνηση κάτω, μετακίνηση πάνω, ελευθέρωση.
++Comment[et]=Vajuta, liiguta alla, liiguta üles, vabasta.
+ Comment[fa]=فشار، حرکت به پایین، حرکت به بالا، رها کردن.
+ Comment[fy]=Yndrukke, nei omleech, nei omheech, loslitte.
+ Comment[it]=Premi, sposta in giù, sposta in su, rilascia.
+@@ -791,6 +816,7 @@
+ Name[de]=Fenster duplizieren
+ Name[el]=Αντίγραφο παραθύρου
+ Name[es]=Duplicar la ventana
++Name[et]=Akna dubleerimine
+ Name[fa]=پنجرۀ تکراری
+ Name[fy]=Finster duplisearje
+ Name[he]=שכפל חלון
+@@ -833,6 +859,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -858,6 +885,7 @@
+ Comment[bg]=Натискане, движение надясно, пускане.
+ Comment[de]=Drücken, nach rechts, loslassen
+ Comment[el]=Πίεση, μετακίνηση δεξιά, ελευθέρωση.
++Comment[et]=Vajuta, liiguta paremale, vabasta.
+ Comment[fa]=فشار، حرکت به راست، رها کردن.
+ Comment[fy]=Yndrukke, nei rjochts, loslitte.
+ Comment[it]=Premi, sposta a desta, rilascia.
+@@ -885,6 +913,7 @@
+ Name[de]=Nach vorne
+ Name[el]=Εμπρός
+ Name[es]=Adelante
++Name[et]=Edasi
+ Name[fa]=پیش‌سو
+ Name[fy]=Foarút
+ Name[ga]=Ar Aghaidh
+@@ -927,6 +956,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -952,6 +982,7 @@
+ Comment[bg]=Натискане, движение надясно, полудвижение нагоре, движение надясно, движение надолу, пускане.\n(Пише се малка буква "h".)
+ Comment[de]=Drücken, nach unten, halb nach oben, nach rechts, nach unten, loslassen. (ein kleines "h" zeichnen")
+ Comment[el]=Πίεση, μετακίνηση κάτω, μετακίνηση κατά το ήμισυ πάνω, μετακίνηση δεξιά, μετακίνηση κάτω,ελευθέρωση.\n(Σχεδίαση ενός μικρού 'h'.)
++Comment[et]=Vajuta, liiguta alla, liiguta pool teed üles, liiguta paremale, liiguta alla, vabasta.\n(Väikese h-tähe joonistamine.)
+ Comment[fa]=فشار، حرکت به پایین، نیم حرکت به بالا، حرکت به راست، حرکت به پایین، رها کردن.\n)ترسیم حرف کوچک »h«.(
+ Comment[fy]=Yndrukke, nei omleech, heal nei omheech, nei rjochts, nei omleech, loslitte.\n(Tekenje in lytse letter 'h'.)
+ Comment[it]=Premi, sposta in giù, sposta in su a metà, sposta a destra, sposta in giù, rilascia.\n(Disegna un'"h" minuscola.)
+@@ -1054,6 +1085,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -1083,6 +1115,7 @@
+ Comment[bg]=Натискане, движение надолу, движение нагоре, движение надолу, пускане.
+ Comment[de]=Drücken, nach rechts, nach unten, nach rechts, loslassen.\nMozilla-Stil: Drücken, nach unten, nach rechts, loslassen.
+ Comment[el]=Πίεση, μετακίνηση δεξιά, μετακίνηση κάτω, μετακίνηση δεξιά, ελευθέρωση.\nΣτυλ Mozilla: Πίεση, μετακίνηση κάτω, μετακίνηση δεξιά, ελευθέρωση.
++Comment[et]=Vajuta, liiguta paremale, liiguta alla, liiguta paremale, vabasta.\nMozilla stiilis: vajuta, liiguta alla, liiguta paremale, vabasta.
+ Comment[fa]=فشار، حرکت به راست، حرکت به پایین، حرکت به راست، رها کردن.\nسبک موزیلا: فشار، حرکت به پایین، حرکت به راست، رها کردن.
+ Comment[fy]=Yndrukke, nei rjochts, nei omleech, nei rjochts, loslitte.\nMozilla-styl: Yndrukke, nei omleech, nei rjochts, loslitte.
+ Comment[it]=Premi, sposta a destra, sposta in giù, sposta a destra, rilascia.\nStile Mozilla: Premi, sposta in giù, sposta a destra, rilascia.
+@@ -1111,6 +1144,7 @@
+ Name[de]=Unterfenster schließen
+ Name[el]=Κλείσιμο καρτέλας
+ Name[es]=Cerrar la solapa
++Name[et]=Kaardi sulgemine
+ Name[fa]=بستن تب
+ Name[fy]=Ljepper slute
+ Name[ga]=Dún an Cluaisín
+@@ -1154,6 +1188,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -1183,6 +1218,7 @@
+ Comment[bg]=Натискане, движение нагоре, пускане.\nИма конфликт със стила на Opera "Нагоре 2", който е по подразбиране.
+ Comment[de]=Drücken, nach oben, loslassen.\nSteht in Konflikt mit dem Opera-Stil von "Nach oben (2)", der aber in der Voreinstellung nicht aktiviert ist.
+ Comment[el]=Πίεση, μετακίνηση πάνω, ελευθέρωση.\nΣύγκρουση με το στυλ Opera 'Πάνω #2', το οποίο είναι προκαθορισμένα απενεργοποιημένο.
++Comment[et]=Vajuta, liiguta üles, vabasta.\nKonfliktis Opera stiilis 'Üles nr. 2', mis on vaikimisi välja lülitatud.
+ Comment[fa]=فشار، حرکت به بالا، رها کردن\nمتناقض با سبک اَپرا »بالا #۲«، که به طور پیش‌فرض غیرفعال است.
+ Comment[fy]=Yndrukke, nei omheech, loslitte.\nKonflikt mei Opera-styl 'nei omheech #2', hokker standert útskeakele is.
+ Comment[it]=Premi, sposta in su, rilascia.\nÈ in conflitto con il gesto in stile Opera "Su #2", che è disabilitato normalmente.
+@@ -1212,6 +1248,7 @@
+ Name[de]=Neues Unterfenster
+ Name[el]=Νέα καρτέλα
+ Name[es]=Nueva solapa
++Name[et]=Uus kaart
+ Name[fa]=تب جدید
+ Name[fy]=Nije ljepper
+ Name[ga]=Cluaisín Nua
+@@ -1255,6 +1292,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -1280,6 +1318,7 @@
+ Comment[bg]=Натискане, движение надолу, пускане.
+ Comment[de]=Drücken, nach unten, loslassen.
+ Comment[el]=Πίεση, μετακίνηση κάτω, ελευθέρωση.
++Comment[et]=Vajuta, liiguta alla, vabasta.
+ Comment[fa]=فشار، حرکت به پایین، رها کردن.
+ Comment[fy]=Yndrukke, nei omleech, loslitte
+ Comment[it]=Premi, sposta in giù, rilascia.
+@@ -1384,6 +1423,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+@@ -1409,6 +1449,7 @@
+ Comment[bg]=Натискане, движение нагоре, движение надолу, пускане.
+ Comment[de]=Drücken, nach oben, nach unten, loslassen.
+ Comment[el]=Πίεση, μετακίνηση πάνω, μετακίνηση κάτω, ελευθέρωση.
++Comment[et]=Vajuta, liiguta üles, liiguta alla, vabasta.
+ Comment[fa]=فشار، حرکت به بالا، حرکت به پایین، رها کردن.
+ Comment[fy]=Yndrukke, nei omheech, nei omleech, loslitte.
+ Comment[it]=Premi, sposta in su, sposta in giù, rilascia.
+@@ -1437,6 +1478,7 @@
+ Name[de]=Dokument erneut laden
+ Name[el]=Επαναφόρτωση
+ Name[es]=Recargar
++Name[et]=Laadi uuesti
+ Name[fa]=بارگذاری مجدد
+ Name[fy]=Ferfarskje
+ Name[ga]=Athluchtaigh
+@@ -1479,6 +1521,7 @@
+ Comment[bg]=Жестове
+ Comment[de]=Gesten_Aktivierung
+ Comment[el]=Ενεργοποιήσεις χειρονομίας
++Comment[et]=Žesti käivitajad
+ Comment[fy]=Stjoerring_starters
+ Comment[it]=Interruttori_gesti
+ Comment[kk]=Ым_Қимыл_жіберушілері
+--- a/khotkeys/data/printscreen.khotkeys
++++ b/khotkeys/data/printscreen.khotkeys
+@@ -6,6 +6,7 @@
+ Comment[bg]=Тази група съдържа действия, които са зададени по подразбирани.
+ Comment[de]=Diese Gruppe enthält einige voreingestellte Aktionen.
+ Comment[el]=Η ομάδα αυτή περιέχει ενέργειες που είναι προκαθορισμένα καθορισμένες.
++Comment[et]=See grupp sisaldab vaikimisi määratud toiminguid.
+ Comment[fa]=این گروه شامل کنشهایی است که به طور پیش‌فرض برپا می‌شوند.
+ Comment[fy]=Dizze groep befettet aksjes dy standert ynsteld binne. 
+ Comment[he]=קבוצה זו כוללת פעולות המוגדרות כברירת מחדל
+@@ -36,6 +37,7 @@
+ Name[de]=Voreingestellte Aktionen
+ Name[el]=Προκαθορισμένες ενέργειες
+ Name[es]=Acciones predefinidas
++Name[et]=Valmistoimingud
+ Name[fa]=پیش‌تنظیم کنشها
+ Name[fy]=Foarynstelde aksjes
+ Name[ga]=Gníomhartha Réamhshocraithe
+@@ -71,6 +73,7 @@
+ Comment[bg]=Стартиране на KSnapShot при натискане на клавиша "PrintScrn"
+ Comment[de]=Startet KSnapShot wenn "Bildschirm Drucken" gedrückt wurde.
+ Comment[el]=Εκτέλεση του KSnapShot όταν πατηθεί το PrintScrn.
++Comment[et]=Käivitab PrintSrcni vajutamisel KSnapShoti.
+ Comment[fa]=وقتی PrintScrn فشار داده می‌شود، KSnapShot را راه می‌اندازد.
+ Comment[fy]=Set útein mei KSnapShot as PrintScrn yndrukt wurdt.
+ Comment[he]=הפעלת KSnapShot בעת הקשה על PrintScrn.
+@@ -130,6 +133,7 @@
+ Comment[de]=Einfache_Aktion
+ Comment[el]=Απλή_ενέργεια
+ Comment[es]=Acción sencilla
++Comment[et]=Lihtne toiming
+ Comment[fy]=Ienfâldige_aksje
+ Comment[ga]=Gníomh simplí
+ Comment[he]=פעולה פשוטה
+--- a/khotkeys/kcontrol/khotkeys.desktop
++++ b/khotkeys/kcontrol/khotkeys.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell khotkeys
++Exec=kcmshell4 khotkeys
+ Icon=preferences-desktop-keyboard-khotkeys
+ Type=Service
+ ServiceTypes=KCModule
+--- a/kstartupconfig/kstartupconfig.cpp
++++ b/kstartupconfig/kstartupconfig.cpp
+@@ -90,7 +90,7 @@
+     strlcat( filename, "/share/config/startupconfig", 1024 );
+     if( access( filename, R_OK ) != 0 )
+         {
+-        int ret = system( "kdostartupconfig" );
++        int ret = system( "kdostartupconfig4" );
+         return WEXITSTATUS( ret );
+         }
+     strlcpy( filename, kdehome, 1024 );
+@@ -98,14 +98,14 @@
+     struct stat st;
+     if( stat( filename, &st ) != 0 )
+         {
+-        int ret = system( "kdostartupconfig" );
++        int ret = system( "kdostartupconfig4" );
+         return WEXITSTATUS( ret );
+         }
+     time_t config_time = st.st_mtime;
+     FILE* config = fopen( filename, "r" );
+     if( config == NULL )
+         {
+-        int ret = system( "kdostartupconfig" );
++        int ret = system( "kdostartupconfig4" );
+         return WEXITSTATUS( ret );
+         }
+     strlcpy( filename, kdehome, 1024 );
+@@ -169,7 +169,7 @@
+     fclose( config );
+     if( need_update )
+         {
+-        int ret = system( "kdostartupconfig" );
++        int ret = system( "kdostartupconfig4" );
+         return WEXITSTATUS( ret );
+         }
+     return 0;
+--- a/kstartupconfig/CMakeLists.txt
++++ b/kstartupconfig/CMakeLists.txt
+@@ -2,19 +2,19 @@
+ 
+ set(kstartupconfig_SRCS kstartupconfig.cpp )
+ 
+-kde4_add_executable(kstartupconfig NOGUI ${kstartupconfig_SRCS})
++kde4_add_executable(kstartupconfig4 NOGUI ${kstartupconfig_SRCS})
+ 
+-target_link_libraries(kstartupconfig kdefakes ${KDE4_KDECORE_LIBS})
++target_link_libraries(kstartupconfig4 kdefakes ${KDE4_KDECORE_LIBS})
+ 
+-install(TARGETS kstartupconfig DESTINATION ${BIN_INSTALL_DIR} )
++install(TARGETS kstartupconfig4 DESTINATION ${BIN_INSTALL_DIR} )
+ 
+ ########### kdostartupconfig ###############
+ 
+ set(kdostartupconfig_SRCS kdostartupconfig.cpp )
+ 
+-kde4_add_executable(kdostartupconfig NOGUI ${kdostartupconfig_SRCS})
++kde4_add_executable(kdostartupconfig4 NOGUI ${kdostartupconfig_SRCS})
+ 
+-target_link_libraries(kdostartupconfig ${KDE4_KDECORE_LIBS} )
++target_link_libraries(kdostartupconfig4 ${KDE4_KDECORE_LIBS} )
+ 
+-install(TARGETS kdostartupconfig DESTINATION ${BIN_INSTALL_DIR} )
++install(TARGETS kdostartupconfig4 DESTINATION ${BIN_INSTALL_DIR} )
+ 
+--- a/ksplash/kcm/ksplashthememgr.desktop
++++ b/ksplash/kcm/ksplashthememgr.desktop
+@@ -1,7 +1,7 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+ Icon=preferences-system-splash
+-Exec=kcmshell ksplashthememgr
++Exec=kcmshell4 ksplashthememgr
+ DocPath=ksplashml/themes.html
+ 
+ Type=Service
+@@ -150,7 +150,7 @@
+ Keywords[el]=αρχική οθόνη,θέμα αρχικής οθόνης,ξεκίνημα
+ Keywords[eo]=Kcm_salutŝildo,Salutŝildo,Saluto
+ Keywords[es]=pantalla de inicio,tema de inicio,inicio
+-Keywords[et]=käivitusekraan,käivutusteema,käivitamine
++Keywords[et]=käivitusekraan,käivitusteema,käivitamine
+ Keywords[eu]=splash pantaila,splash gaia,abioa
+ Keywords[fa]=رنگ‌پاشی پرده، چهرۀ رنگ‌پاشی، راه‌اندازی
+ Keywords[fi]=aloitusruutu,aloitusruututeema,käynnistys
+@@ -163,7 +163,7 @@
+ Keywords[hu]=nyitókép,indítási téma,indulás
+ Keywords[it]=schermata di avvio,splash screen,splash theme,tema schermata di avvio,avvio,startup
+ Keywords[ja]=スプラッシュスクリーン,スプラッシュテーマ,起動
+-Keywords[km]=អេក្រង់​ស្វាគមន៍, ស្បែក​ពេល​ស្វាគមន៍, ដំឡើង​
++Keywords[km]=អេក្រង់​ស្វាគមន៍ ស្បែក​ពេល​ស្វាគមន៍ ដំឡើង​
+ Keywords[ko]=시작 화면,시작,테마
+ Keywords[lt]=splash screen,splash theme,startup,pasveikinimo ekranas,pasveikinimo tema
+ Keywords[lv]=šļakstekrāns,šļakstekrāna tēma,palaišanās
+--- a/config-workspace.h.cmake
++++ b/config-workspace.h.cmake
+@@ -91,13 +91,13 @@
+ #cmakedefine HAVE_VSNPRINTF 1
+ 
+ /* KDE's binaries directory */
+-#define KDE_BINDIR "${CMAKE_INSTALL_PREFIX}/bin"
++#define KDE_BINDIR "${BIN_INSTALL_DIR}"
+ 
+ /* KDE's configuration directory */
+-#define KDE_CONFDIR "${CMAKE_INSTALL_PREFIX}/share/config"
++#define KDE_CONFDIR "${CONFIG_INSTALL_DIR}"
+ 
+ /* KDE's static data directory */
+-#define KDE_DATADIR "${CMAKE_INSTALL_PREFIX}/share/apps"
++#define KDE_DATADIR "${DATA_INSTALL_DIR}"
+ 
+ /* Define where your java executable is */
+ #undef PATH_JAVA
+--- a/kwin/effects/invert.desktop
++++ b/kwin/effects/invert.desktop
+@@ -6,6 +6,7 @@
+ Name[de]=Invertieren
+ Name[el]=Αντιστροφή
+ Name[es]=Invertir
++Name[et]=Teistpidi
+ Name[fa]=وارونه
+ Name[he]=הפוך צבעים
+ Name[ja]=色調反転
+@@ -30,6 +31,7 @@
+ Comment[de]=Invertiert Farben der Arbeitsfläche
+ Comment[el]=Αντιστρέφει τα χρώματα της επιφάνειας εργασίας
+ Comment[es]=Invierte (niega) los colores del escritorio
++Comment[et]=Muudab töölaua värvid vastupidiseks
+ Comment[fa]=رنگهای رومیزی را وارونه )خنثی( می‌کند
+ Comment[he]=הופך את צבעי שולחן העבודה
+ Comment[ja]=デスクトップの色を反転させます
+--- a/kwin/effects/dialogparent.desktop
++++ b/kwin/effects/dialogparent.desktop
+@@ -6,6 +6,7 @@
+ Name[de]=Eltern-Dialog
+ Name[el]=Γονικός διάλογος
+ Name[es]=Padre de la ventana
++Name[et]=Dialoogi eellane
+ Name[fa]=پدر محاوره
+ Name[ga]=Máthairdialóg
+ Name[he]=חלונות־אב של תיבות דו־שיח
+@@ -31,6 +32,7 @@
+ Comment[bg]=Потъмнение на главните от активните прозорци
+ Comment[de]=Dunkelt den Eltern-Dialog des aktiven Fensters ab
+ Comment[el]=Σκίαση γονικών παραθύρων των ενεργών διαλόγων
++Comment[et]=Tumendab aktiivsete dialoogide eellasaknad
+ Comment[fa]=پنجره‌های پدر محاوره‌های فعال را تیره می‌کند
+ Comment[he]=מחשיך חלונות־אב של תיבות דו־שיח פעילות
+ Comment[ja]=アクティブなダイアログの親ウィンドウを暗くします
+--- a/kwin/effects/trackmouse.desktop
++++ b/kwin/effects/trackmouse.desktop
+@@ -6,6 +6,7 @@
+ Name[de]=Mausspur
+ Name[el]=Ανίχνευση ποντικιού
+ Name[es]=Seguir el ratón
++Name[et]=Hiire jälgimine
+ Name[fa]=ردگیری موشی
+ Name[he]=עקבות עכבר
+ Name[ja]=トラックマウス
+--- a/kwin/effects/desktopgrid.desktop
++++ b/kwin/effects/desktopgrid.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Arbeitsflächen-Raster
+ Name[el]=Πλέγμα επιφάνειας εργασίας
+ Name[es]=Rejilla del escritorio
++Name[et]=Töölauavõrgustik
+ Name[fa]=توری رومیزی
+ Name[he]=רשת שולחנות עבודה
+ Name[it]=Griglia dei Desktop
+@@ -32,6 +33,7 @@
+ Comment[bg]=Превключване между работните плотове в мрежа
+ Comment[de]=Arbeitsflächenumschaltung (Fensteranordnung in einem Raster)
+ Comment[el]=Εναλλαγή επιφάνειας εργασίας με τοποθέτηση των επιφανειών σε έναν κάνναβο
++Comment[et]=Töölauavahetaja, mis näitab töölaudu võrgustikus
+ Comment[fa]=سوده رومیزی که رومیزیها را به بیرون توری می‌کشد
+ Comment[he]=מחליף שולחנות עבודה שמסדר את שולחנות העבודה ברשת
+ Comment[ja]=デスクトップを格子状に並べるデスクトップスイッチャー
+--- a/kwin/effects/presentwindows_config.cpp
++++ b/kwin/effects/presentwindows_config.cpp
+@@ -59,7 +59,7 @@
+     KGlobalAccel::self()->overrideMainComponentData(componentData());
+     KActionCollection* actionCollection = new KActionCollection( this );
+     KAction* a = (KAction*)actionCollection->addAction( "Expose" );
+-    a->setText( i18n("Toggle Expose effect" ));
++    a->setText( i18n("Toggle Expose Effect" ));
+     a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10));
+     KAction* b = (KAction*)actionCollection->addAction( "ExposeAll" );
+     b->setText( i18n("Toggle Expose effect (incl other desktops)" ));
+--- a/kwin/effects/lookingglass.desktop
++++ b/kwin/effects/lookingglass.desktop
+@@ -2,6 +2,7 @@
+ Encoding=UTF-8
+ Name=Looking Glass
+ Name[es]=Espejo
++Name[et]=Suurendusklaas
+ Name[he]=מראה
+ Name[kk]=Айна
+ Name[km]=កញ្ចក់​មើល
+@@ -20,6 +21,7 @@
+ Comment[de]=Looking Glass erweiterte Lupe
+ Comment[el]=Βελτιωμένος μεγεθυντικός φακός Looking Glass
+ Comment[es]=Lupa de espejo mejorada
++Comment[et]=Suurendusklaas on täiustatud suurendaja
+ Comment[he]=זכוכית מגדלת משופרת
+ Comment[kk]=Айнамен күшейткен ұлғайтқыш
+ Comment[km]=​កញ្ចក់​មើល​ដែល​បាន​បន្ថែម​ទៅ​ក្នុង​កែវ​ពង្រីក​
+--- a/kwin/effects/fade.desktop
++++ b/kwin/effects/fade.desktop
+@@ -5,6 +5,7 @@
+ Name[de]=Verblassen
+ Name[el]=Ομαλή εμφάνιση
+ Name[es]=Fundido
++Name[et]=Hääbumine
+ Name[fa]=محو کردن
+ Name[he]=חשיפה והיעלמות
+ Name[ja]=フェード
+@@ -29,6 +30,7 @@
+ Comment[de]=Blendet Fenster beim Öffnen/Schließen langsam ein bzw. aus.
+ Comment[el]=Κάνει τα παράθυρα να εμφανίζονται/αποκρύπτονται ομαλά
+ Comment[es]=Hace que las ventanas aparezcan suavemente o se desvanezcan al mostrarlas u ocultarlas
++Comment[et]=Paneb aknad sujuvalt hääbuma või tugevnema, kui need peidetakse või nähtavale tuuakse
+ Comment[fa]=پنجره‌ها را هنگام نمایش یا مخفی شدن، به صورت هموار به درون/بیرون محو می‌کند
+ Comment[he]=חשיפה והיעלמות חלקה של חלונות בעת הצגתם או הסתרתם
+ Comment[ja]=ウィンドウの表示/非表示を切り替えるときに滑らかにフェードイン/フェードアウトします
+--- a/kwin/effects/maketransparent.desktop
++++ b/kwin/effects/maketransparent.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Transparent machen
+ Name[el]=Εμφάνιση διαφανούς
+ Name[es]=Hacer transparente
++Name[et]=Läbipaistvus
+ Name[fa]=ایجاد شفافیت
+ Name[he]=הפוך לשקוף
+ Name[ja]=透明
+--- a/kwin/effects/sharpen.desktop
++++ b/kwin/effects/sharpen.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Отчетливост
+ Name[de]=Schärfen
+ Name[el]=Όξυνση
++Name[et]=Teravdus
+ Name[fa]=تیز کردن
+ Name[he]=חדד
+ Name[ja]=シャープ化
+@@ -27,6 +28,7 @@
+ Comment[bg]=Прави работния плот по-отчетлив
+ Comment[de]=Lässt Ihre Arbeitsfläche schärfer erscheinen
+ Comment[el]=Κάνει την επιφάνεια εργασίας σας να δείχνει πιο οξεία
++Comment[et]=Muudab töölaua välimuse teravamaks
+ Comment[fa]=رومیزیتان تیزتر به نظر می‌رسد
+ Comment[he]=מחדד את מראה שולחן העבודה שלך
+ Comment[it]=Rende il desktop più nitido
+--- a/kwin/effects/blur.desktop
++++ b/kwin/effects/blur.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Замъгляване
+ Name[de]=Verwischen
+ Name[el]=Θόλωμα
++Name[et]=Hägu
+ Name[fa]=محو
+ Name[he]=טשטש
+ Name[it]=Sfocatura
+@@ -30,6 +31,7 @@
+ Comment[bg]=Замъгляване на фона на полупрозрачни прозорци
+ Comment[de]=Verwischt den Hintergrund halbtransparenter Fenster
+ Comment[el]=Θόλωμα φόντου των ημιδιαφανών παραθύρων
++Comment[et]=Poolläbipaistvate akende tausta hägustamine
+ Comment[fa]=زمینه پنجره‌های نیمه شفاف را محو می‌کند
+ Comment[he]=טישטוש הרקע של חלונות שקופים למחצה
+ Comment[it]=Sfoca lo sfondo delle finestre semitrasparenti
+--- a/kwin/effects/fallapart.desktop
++++ b/kwin/effects/fallapart.desktop
+@@ -4,6 +4,7 @@
+ Name[de]=Auseinanderfallen
+ Name[el]=Κατάρρευση
+ Name[es]=Desmenuzar
++Name[et]=Lagunemine
+ Name[he]=התפרקות
+ Name[ja]=崩壊
+ Name[kk]=Қирау
+--- a/kwin/effects/boxswitch.desktop
++++ b/kwin/effects/boxswitch.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Превключване между прозорци
+ Name[de]=Würfel-Fensterwechsel
+ Name[el]=Εναλλαγή πλαισίου
++Name[et]=Aknavahetaja
+ Name[fa]=سودهی جعبه
+ Name[he]=מחליף מבוסס תיבה
+ Name[ja]=ボックススイッチ
+@@ -24,12 +25,13 @@
+ Comment[bg]=Подобрено превключване между прозорците с Alt-табулация
+ Comment[de]=Verbesserter Fensterwechsel mittels Alt-Tabulator
+ Comment[el]=Βελτιωμένη εναλλαγή παραθύρου Alt-tab
++Comment[et]=Täiustatud Alt+TAB akende vahetaja
+ Comment[fa]=سوده پنجره دگرساز-تب بهبودیافته
+ Comment[he]=מחליף חלונות משופר מבוסס Alt-tab
+ Comment[it]=Scambiafinestre Alt-Tab migliorato
+ Comment[ja]=Alt+Tab によるウィンドウ切り替えの改良版
+ Comment[kk]=Жетілдірген Alt-Tab терезе ауыстырғышы
+-Comment[km]=កម្មវិធី​ប្តូរ​បង្អួច​ ជំនួស (Alt) ​- ថេប (Tab) ​ដែល​បាន​ធ្វើ​ឲ្យ​ប្រសើរ​ឡើង​
++Comment[km]=កម្មវិធី​ប្តូរ​បង្អួច​ ជំនួស(Alt)​-ថេប(Tab) ​ដែល​បាន​ធ្វើ​ឲ្យ​ប្រសើរ​ឡើង​
+ Comment[nb]=Forbedret Alt-tab vindusveksler
+ Comment[nds]=Verbetert Wesseln vun Finster mit Alt+Tabtast
+ Comment[ne]=सुधार गरिएको Alt-tab सञ्झ्याल स्विचकर्ता
+--- a/kwin/effects/explosion.desktop
++++ b/kwin/effects/explosion.desktop
+@@ -1,9 +1,11 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+ Name=Explosion
++Name[br]=Tarzhad
+ Name[csb]=Wëbùch
+ Name[el]=Έκρηξη
+ Name[es]=Explosión
++Name[et]=Plahvatus
+ Name[fa]=انفجار
+ Name[he]=התפוצצות
+ Name[it]=Esplosione
+@@ -31,6 +33,7 @@
+ Comment[de]=Lässt Fenster beim Schließen explodieren
+ Comment[el]=Έκρηξη των παραθύρων κατά το κλείσιμο
+ Comment[es]=Hace que las ventanas exploten al cerrarlas
++Comment[et]=Paneb aknad sulgemisel plahvatama
+ Comment[fa]=پنجره‌ها وقتی که بسته می‌شوند، منفجر می‌سازد
+ Comment[he]=פיצוץ חלונות בעת סגירתם
+ Comment[it]=Fa esplodere le finestre alla chiusura
+--- a/kwin/effects/presentwindows_config.desktop
++++ b/kwin/effects/presentwindows_config.desktop
+@@ -14,6 +14,7 @@
+ Name[csb]=Prezentëjë òkna
+ Name[de]=Fenster zeigen
+ Name[el]=Παρουσίαση παραθύρων
++Name[et]=Olemasolevad aknad
+ Name[fa]=پنجره‌های موجود
+ Name[he]=הצג חלונות
+ Name[ja]=すべてのウィンドウを表示
+--- a/kwin/effects/zoom.desktop
++++ b/kwin/effects/zoom.desktop
+@@ -8,6 +8,7 @@
+ Name[de]=Vergrößerung
+ Name[el]=Εστίαση
+ Name[es]=Ampliación
++Name[et]=Suurendus
+ Name[fa]=بزرگ‌نمایی
+ Name[ga]=Súmáil
+ Name[he]=התקרבות
+--- a/kwin/effects/shadow.desktop
++++ b/kwin/effects/shadow.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Schatten
+ Name[el]=Σκιά
+ Name[es]=Sombra
++Name[et]=Vari
+ Name[fa]=سایه
+ Name[he]=צל
+ Name[it]=Ombra
+@@ -37,6 +38,7 @@
+ Comment[de]=Lässt Fenster einen Schatten werfen
+ Comment[el]=Προσθήκη σκιάς κάτω από τα παράθυρα
+ Comment[es]=Añade una sombra bajo las ventanas
++Comment[et]=Lisab akende alla varju
+ Comment[fa]=زیر پنجره‌ها سایه اضافه می‌کند
+ Comment[he]=הוספת צל מתחת לחלונות
+ Comment[it]=Aggiunge l'ombra sotto le finestre
+--- a/kwin/effects/thumbnailaside.desktop
++++ b/kwin/effects/thumbnailaside.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Манипулатор на мини изображения
+ Name[de]=Seitliche Vorschaubilder
+ Name[el]=Εικόνα επισκόπησης στο πλάι
++Name[et]=Pisipildid kõrval
+ Name[he]=דוגמית בצד
+ Name[ja]=サムネイルをわきに表示
+ Name[kk]=Нобайды шеттеу
+--- a/kwin/effects/diminactive.desktop
++++ b/kwin/effects/diminactive.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Замъгляване на неактивния
+ Name[de]=Inaktive abdunkeln
+ Name[el]=Θαμπάδα ανενεργού
++Name[et]=Tuhm mitteaktiivne
+ Name[he]=עמעם חלונות לא פעילים
+ Name[ja]=非アクティブを暗く
+ Name[kk]=Белсенді еместі күңгірттеу
+@@ -27,6 +28,7 @@
+ Comment[cs]=Ztmavuje neaktivní okna
+ Comment[de]=Dunkelt inaktive Fenster ab
+ Comment[el]=Σκίαση μη ενεργών παραθύρων
++Comment[et]=Tumendab mitteaktiivsed aknad
+ Comment[fa]=پنجره‌های غیرفعال را تیره می‌کند
+ Comment[he]=עימעום חלונות לא פעילים
+ Comment[it]=Oscura le finestre inattive
+--- a/kwin/effects/magnifier.desktop
++++ b/kwin/effects/magnifier.desktop
+@@ -6,6 +6,7 @@
+ Name[de]=Lupe
+ Name[el]=Μεγεθυντικός φακός
+ Name[es]=Lupa
++Name[et]=Suurendaja
+ Name[fa]=ذره‌بین
+ Name[ga]=Formhéadaitheoir
+ Name[he]=זכוכית מגדלת
+@@ -33,6 +34,7 @@
+ Comment[de]=Vergrößert den Arbeitsflächenbereich unter der Maus
+ Comment[el]=Μεγέθυνση του τμήματος της οθόνη κάτω από το ποντίκι
+ Comment[es]=Amplía la parte de la pantalla que esté bajo el ratón
++Comment[et]=Suurendab hiire all olevat ekraaniosa
+ Comment[fa]=جزئی از پرده را که زیر موشی است درشت‌نما می‌کند
+ Comment[he]=הגדלת החלק של המסך שנמצא מתחת למצביע העכבר
+ Comment[it]=Ingrandisce la parte dello schermo sotto il mouse
+--- a/kwin/effects/presentwindows.cpp
++++ b/kwin/effects/presentwindows.cpp
+@@ -45,7 +45,7 @@
+ 
+     KActionCollection* actionCollection = new KActionCollection( this );
+     KAction* a = (KAction*)actionCollection->addAction( "Expose" );
+-    a->setText( i18n("Toggle Expose effect" ));
++    a->setText( i18n("Toggle Expose Effect" ));
+     a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10));
+     connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleActive()));
+     KAction* b = (KAction*)actionCollection->addAction( "ExposeAll" );
+--- a/kwin/effects/videorecord.desktop
++++ b/kwin/effects/videorecord.desktop
+@@ -8,6 +8,7 @@
+ Name[de]=Video-Aufnahme
+ Name[el]=Εγγραφή βίντεο
+ Name[es]=Grabación de vídeo
++Name[et]=Videosalvestus
+ Name[fa]=ضبط ویدیو
+ Name[he]=הקלטת סרט
+ Name[it]=Registra video
+@@ -35,6 +36,7 @@
+ Comment[de]=Zeichnet Videos von der Arbeitsfläche auf
+ Comment[el]=Επιτρέπει την εγγραφή βίντεο της επιφάνειας εργασίας σας
+ Comment[es]=Le permite grabar vídeos de su escritorio
++Comment[et]=Võimaldab salvestada videoid töölauast
+ Comment[fa]=اجازه ضبط تصویری رومیزیتان را می‌دهد
+ Comment[he]=מאפשר לך להקליט סרטי וידאו של שולחן העבודה שלך
+ Comment[it]=Permette di registrare video del desktop
+--- a/kwin/effects/shadow_config.desktop
++++ b/kwin/effects/shadow_config.desktop
+@@ -14,6 +14,7 @@
+ Name[de]=Schatten
+ Name[el]=Σκιά
+ Name[es]=Sombra
++Name[et]=Vari
+ Name[fa]=سایه
+ Name[he]=צל
+ Name[it]=Ombra
+--- a/kwin/effects/presentwindows.desktop
++++ b/kwin/effects/presentwindows.desktop
+@@ -7,6 +7,7 @@
+ Name[csb]=Prezentëjë òkna
+ Name[de]=Fenster zeigen
+ Name[el]=Παρουσίαση παραθύρων
++Name[et]=Olemasolevad aknad
+ Name[fa]=پنجره‌های موجود
+ Name[he]=הצג חלונות
+ Name[ja]=すべてのウィンドウを表示
+@@ -32,6 +33,7 @@
+ Comment[csb]=Wëskrzëni wszëtczé òkna, starna pò stranie
+ Comment[de]=Zeigt alle Fenster nebeneinander an
+ Comment[el]=Εμφάνιση όλων των παραθύρων σε παράθεση
++Comment[et]=Näitab kõiki aknaid üksteise kõrval
+ Comment[fa]=همه پنجره‌ها را در کنار هم نمایش می‌دهد
+ Comment[he]=מציג את כל החלונות זה לצד זה
+ Comment[it]=Mostra tutte le finestre affiancate
+--- a/kwin/effects/desktopgrid_config.desktop
++++ b/kwin/effects/desktopgrid_config.desktop
+@@ -14,6 +14,7 @@
+ Name[de]=Arbeitsflächen-Raster
+ Name[el]=Πλέγμα επιφάνειας εργασίας
+ Name[es]=Rejilla del escritorio
++Name[et]=Töölauavõrgustik
+ Name[fa]=توری رومیزی
+ Name[he]=רשת שולחנות עבודה
+ Name[it]=Griglia dei Desktop
+--- a/kwin/effects/drunken.desktop
++++ b/kwin/effects/drunken.desktop
+@@ -4,6 +4,7 @@
+ Name[de]=Betrunken
+ Name[el]=Κούνημα
+ Name[es]=Borracho
++Name[et]=Purjus
+ Name[he]=שתוי
+ Name[it]=Ubriaco
+ Name[ja]=酔っぱらい
+--- a/kwin/effects/scalein.desktop
++++ b/kwin/effects/scalein.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Увеличаване
+ Name[de]=Hineinzoomen
+ Name[el]=Εστίαση
++Name[et]=Skaleerimine
+ Name[fa]=مقیاس در
+ Name[he]=התקרב
+ Name[ja]=スケールイン
+--- a/kwin/effects/minimizeanimation.desktop
++++ b/kwin/effects/minimizeanimation.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Minimieren-Animation
+ Name[el]=Κίνηση ελαχιστοποίησης
+ Name[es]=Animación de minimización
++Name[et]=Minimeerimise animatsioon
+ Name[fa]=پویانمایی کمینه‌سازی
+ Name[he]=אנימציית מיזעור
+ Name[ja]=最小化のアニメーション
+@@ -33,6 +34,7 @@
+ Comment[de]=Animiert den Minimieren-Vorgang von Fenstern
+ Comment[el]=Κίνηση στα παράθυρα που ελαχιστοποιούνται
+ Comment[es]=Anima la minimización de ventanas
++Comment[et]=Animeerib akende minimeerimise
+ Comment[fa]=کمینه‌سازی پنجره‌ها را پویا می‌کند
+ Comment[he]=הנפשת מיזעור חלונות
+ Comment[ja]=ウィンドウの最小化をアニメーション化します
+--- a/kwin/effects/flame.desktop
++++ b/kwin/effects/flame.desktop
+@@ -5,6 +5,7 @@
+ Name[de]=Flamme
+ Name[el]=Φλόγα
+ Name[es]=Llama
++Name[et]=Leek
+ Name[fa]=شعله
+ Name[he]=להבה
+ Name[it]=Fiamma
+--- a/kwin/effects/kwineffect.desktop
++++ b/kwin/effects/kwineffect.desktop
+@@ -11,6 +11,7 @@
+ Comment[de]=KWin-Effekt
+ Comment[el]=Εφέ KWin
+ Comment[es]=Efecto de KWin
++Comment[et]=KWin'i efektid
+ Comment[fa]=جلوه‌های KWin
+ Comment[ga]=Maisíocht KWin
+ Comment[he]=אפקט של KWin
+--- a/kwin/effects/desktopgrid.cpp
++++ b/kwin/effects/desktopgrid.cpp
+@@ -403,8 +403,16 @@
+         else // current position is not on current desktop, do full progress
+             progress = 0;
+         diffPos = rect.topLeft() - currentPos;
+-        // Compute starting point for this new move (given current and end positions)
+-        slide_start_pos = rect.topLeft() - diffPos * 1 / ( 1 - progress );
++        if( progress <= 0 )
++            {
++            // Compute starting point for this new move (given current and end positions)
++            slide_start_pos = rect.topLeft() - diffPos * 1 / ( 1 - progress );
++            }
++        else
++            { // at the end, stop
++            slide = false;
++            progress = 0;
++            }
+         }
+     else
+         {
+--- a/kwin/effects/showfps.desktop
++++ b/kwin/effects/showfps.desktop
+@@ -6,6 +6,7 @@
+ Name[csb]=Wëskrzëni FPS
+ Name[de]=Bilder pro Sekunde anzeigen
+ Name[el]=Εμφάνιση καρέ ανά δευτερόλεπτο
++Name[et]=FPS-i näitamine
+ Name[fa]=نمایش FPS
+ Name[he]=הצג מסגרות לשנייה
+ Name[it]=Mostra FPS
+@@ -35,6 +36,7 @@
+ Comment[de]=Zeigt die Leistung von KWin
+ Comment[el]=Εμφάνιση επίδοσης του KWin
+ Comment[es]=Muestra el rendimiento de KWin
++Comment[et]=KWin'i jõudluse näitamine
+ Comment[fa]=کارایی KWin را نشان می‌دهد
+ Comment[he]=מציג את הביצועים של KWin
+ Comment[it]=Mostra le prestazioni di KWin
+--- a/kwin/effects/mousemark.desktop
++++ b/kwin/effects/mousemark.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Mausspur
+ Name[el]=Σήμανση ποντικιού
+ Name[es]=Marcación con el ratón
++Name[et]=Hiirejälg
+ Name[fa]=نشان موشی
+ Name[he]=סימון בעזרת העכבר
+ Name[ja]=マウスマーク
+@@ -31,6 +32,7 @@
+ Comment[de]=Zeichnet Mausspuren auf der Arbeitsfläche
+ Comment[el]=Σας επιτρέπει τη σχεδίαση γραμμών στην επιφάνεια εργασίας σας
+ Comment[es]=Le deja dibujar líneas en el escritorio
++Comment[et]=Võimaldab tõmmata töölauale jooni
+ Comment[fa]=به شما اجازه ترسیم خطوط بر روی رومیزیتان را می‌دهد
+ Comment[he]=מאפשר לך לצייר קווים על גבי שולחן העבודה שלך
+ Comment[it]=Permette di disegnare sul desktop
+--- a/kwin/composite.cpp
++++ b/kwin/composite.cpp
+@@ -266,12 +266,13 @@
+     // The event loop apparently tries to fire a QTimer as often as possible, even
+     // at the expense of not processing many X events. This means that the composite
+     // repaints can seriously impact performance of everything else, therefore throttle
+-    // them - leave at least 5msec time after one repaint is finished and next one
++    // them - leave at least 1msec time after one repaint is finished and next one
+     // is started.
+-    if( lastCompositePaint.elapsed() < 5 )
++    if( lastCompositePaint.elapsed() < 1 )
+         return;
+     checkCursorPos();
+-    if( repaints_region.isEmpty() && !windowRepaintsPending()) // no damage
++    if(( repaints_region.isEmpty() && !windowRepaintsPending()) // no damage
++        || !overlay_visible ) // nothing is visible anyway
+         {
+         scene->idle();
+         return;
+@@ -365,6 +366,7 @@
+         XMapWindow( display(), w );
+         }
+     XMapRaised( display(), overlay );
++    XSelectInput( display(), overlay, VisibilityChangeMask );
+     }
+ 
+ void Workspace::destroyOverlay()
+--- a/kwin/workspace.h
++++ b/kwin/workspace.h
+@@ -715,6 +715,7 @@
+         int compositeRate;
+         QRegion repaints_region;
+         Window overlay; // XComposite overlay window
++        bool overlay_visible;
+         QSlider *transSlider;
+         QPushButton *transButton;
+ 
+--- a/kwin/events.cpp
++++ b/kwin/events.cpp
+@@ -246,7 +246,7 @@
+             was_user_interaction = true;
+             int keyQt;
+             KKeyServer::xEventToQt(e, &keyQt);
+-            kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
++//            kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
+             if (movingClient)
+                 {
+                 movingClient->keyPressEvent(keyQt);
+@@ -455,8 +455,16 @@
+                 return true;
+             break;
+         case Expose:
+-            if( e->xexpose.window == rootWindow() && compositing())  // root window needs repainting
++            if( compositing()
++                && ( e->xexpose.window == rootWindow()  // root window needs repainting
++                    || overlay != None && e->xexpose.window == overlay )) // overlay needs repainting
++                {
+                 addRepaint( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height );
++                }
++            break;
++        case VisibilityNotify:
++            if( compositing() && overlay != None && e->xvisibility.window == overlay )
++                overlay_visible = ( e->xvisibility.state != VisibilityFullyObscured );
+             break;
+         default:
+             if( e->type == Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
+--- a/kwin/clients/b2/b2client.cpp
++++ b/kwin/clients/b2/b2client.cpp
+@@ -13,9 +13,9 @@
+  */
+ 
+ #include "b2client.h"
++
+ #include <QApplication>
+ #include <QLayout>
+-#include <qdrawutil.h>
+ #include <QPixmap>
+ #include <QPaintEvent>
+ #include <QPolygon>
+@@ -31,7 +31,6 @@
+ #include <QTextStream>
+ #include <kicontheme.h>
+ #include <kiconeffect.h>
+-//#include <kdrawutil.h>
+ #include <klocale.h>
+ #include <kconfig.h>
+ #include <QBitmap>
+@@ -115,10 +114,10 @@
+ {
+     // Force button size to be in a reasonable range.
+     // If the frame width is large, the button size must be large too.
+-    buttonSize = (QFontMetrics(options()->font(true)).height() + 1) & 0x3e;
++    buttonSize = (QFontMetrics(options()->font(true)).height() - 1) & 0x3e;
+     if (buttonSize < 16) buttonSize = 16;
+ 
+-    KConfig _conf( "kwinb2rc" );
++    KConfig _conf("kwinb2rc");
+     KConfigGroup conf(&_conf, "General");
+     colored_frame = conf.readEntry("UseTitleBarBorderColors", false);
+     do_draw_handle = conf.readEntry("DrawGrabHandle", true);
+@@ -206,7 +205,7 @@
+     for (i = 0; i < NUM_PIXMAPS; i++) {
+ 
+         switch (i / NumStates) {
+-	case P_MAX: // will be initialized by copying P_CLOSE
++	case P_CLOSE: // will be initialized by copying P_MAX
+ 	case P_RESIZE:
+ 	    pixmap[i] = new QPixmap();
+ 	    break;
+@@ -214,7 +213,8 @@
+ 	    pixmap[i] = new QPixmap(10, 10);
+ 	    break;
+ 	case P_SHADE:
+-	case P_CLOSE:
++	case P_MAX:
++	case P_HELP:
+ 	    pixmap[i] = new QPixmap(bsize, bsize);
+ 	    break;
+ 	default:
+@@ -236,11 +236,9 @@
+     QBitmap pinupMask = QBitmap::fromData(QSize(16, 16), pinup_mask_bits);
+     QBitmap pindownMask = QBitmap::fromData(QSize(16, 16), pindown_mask_bits);
+     QBitmap menuMask = QBitmap::fromData(QSize(16, 16), menu_mask_bits);
+-    QBitmap helpMask = QBitmap::fromData(QSize(16, 16), help_mask_bits);
+     for (i = 0; i < NumStates; i++) {
+ 	bool isDown = (i == Down) || (i == IDown);
+ 	pixmap[P_MENU * NumStates + i]->setMask(menuMask);
+-	pixmap[P_HELP * NumStates + i]->setMask(helpMask);
+ 	pixmap[P_PINUP * NumStates + i]->setMask(isDown ? pindownMask: pinupMask);
+     }
+ 
+@@ -319,21 +317,22 @@
+ bool B2ClientFactory::supports(Ability ability)
+ {
+     switch (ability) {
+-        case AbilityAnnounceButtons:
+-        case AbilityButtonMenu:
+-        case AbilityButtonOnAllDesktops:
+-        case AbilityButtonSpacer:
+-        case AbilityButtonHelp:
+-        case AbilityButtonMinimize:
+-        case AbilityButtonMaximize:
+-        case AbilityButtonClose:
+-        case AbilityButtonAboveOthers:
+-        case AbilityButtonBelowOthers:
+-        case AbilityButtonShade:
+-        case AbilityButtonResize:
+-            return true;
+-        default:
+-            return false;
++    case AbilityAnnounceButtons:
++    case AbilityButtonMenu:
++    case AbilityButtonOnAllDesktops:
++    case AbilityButtonSpacer:
++    case AbilityButtonHelp:
++    case AbilityButtonMinimize:
++    case AbilityButtonMaximize:
++    case AbilityButtonClose:
++    case AbilityButtonShade:
++    case AbilityButtonResize:
++	return true;
++    // These are not (yet) supported.
++    case AbilityButtonAboveOthers:
++    case AbilityButtonBelowOthers:
++    default:
++	return false;
+     };
+ }
+ 
+@@ -382,10 +381,9 @@
+     // Check this early, otherwise the preview will be rendered badly.
+     resizable = isResizable();
+ 
+-    createMainWidget(Qt::WResizeNoErase | Qt::WRepaintNoErase);
+-    widget()->installEventFilter(this);
+-
++    createMainWidget();
+     widget()->setAttribute(Qt::WA_NoSystemBackground);
++    widget()->installEventFilter(this);
+ 
+     // Set button pointers to NULL so we know what has been created
+     for (int i = 0; i < BtnCount; i++)
+@@ -976,14 +974,14 @@
+     QColor inactiveColor = iPal.color(QPalette::Button);
+     QColor activeColor = aPal.color(QPalette::Button);
+ 
+-    // close
+-    drawB2Rect(PIXMAP_A(P_CLOSE), activeColor, false);
+-    drawB2Rect(PIXMAP_AH(P_CLOSE), activeColor, true);
+-    drawB2Rect(PIXMAP_AD(P_CLOSE), activeColor, true);
+-
+-    drawB2Rect(PIXMAP_I(P_CLOSE), inactiveColor, false);
+-    drawB2Rect(PIXMAP_IH(P_CLOSE), inactiveColor, true);
+-    drawB2Rect(PIXMAP_ID(P_CLOSE), inactiveColor, true);
++    // maximize
++    for (int i = 0; i < NumStates; i++) {
++	bool is_act = (i < 2);
++	bool is_down = ((i & 1) == 1);
++	QPixmap *pix = pixmap[P_MAX * NumStates + i];
++	QColor color = is_act ? activeColor : inactiveColor;
++	drawB2Rect(pix, color, is_down);
++    }
+ 
+     // shade
+     QPixmap thinBox(buttonSize - 2, 6);
+@@ -998,15 +996,9 @@
+ 		0, 0, thinBox.width(), thinBox.height());
+     }
+ 
+-    // maximize
+-    for (int i = 0; i < NumStates; i++) {
+-	*pixmap[P_MAX * NumStates + i] = *pixmap[P_CLOSE * NumStates + i];
+-	pixmap[P_MAX * NumStates + i]->detach();
+-    }
+-
+     // normalize + iconify
+-    QPixmap smallBox( 10, 10 );
+-    QPixmap largeBox( 12, 12 );
++    QPixmap smallBox(10, 10);
++    QPixmap largeBox(12, 12);
+ 
+     for (int i = 0; i < NumStates; i++) {
+ 	bool is_act = (i < 3);
+@@ -1028,42 +1020,54 @@
+     for (int i = 0; i < NumStates; i++) {
+ 	bool is_act = (i < 3);
+ 	bool is_down = (i == Down || i == IDown);
+-	*pixmap[P_RESIZE * NumStates + i] = *pixmap[P_CLOSE * NumStates + i];
++	*pixmap[P_RESIZE * NumStates + i] = *pixmap[P_MAX * NumStates + i];
+ 	pixmap[P_RESIZE * NumStates + i]->detach();
+ 	drawB2Rect(&smallBox, is_act ? activeColor : inactiveColor, is_down);
+ 	bitBlt(pixmap[P_RESIZE * NumStates + i],
+ 		0, 0, &smallBox, 0, 0, 10, 10);
+     }
+ 
+-
+     QPainter p;
+-    // x for close + menu + help
+-    for (int j = 0; j < 3; j++) {
+-        int pix;
+-        unsigned const char *light, *dark;
+-        switch (j) {
+-        case 0:
+-            pix = P_CLOSE; light = close_white_bits; dark = close_dgray_bits;
+-            break;
+-        case 1:
+-            pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits;
+-            break;
+-        default:
+-            pix = P_HELP; light = help_light_bits; dark = help_dark_bits;
+-            break;
+-        }
+-	int off = (pixmap[pix * NumStates]->width() - 16) / 2;
++    // close: copy the maximize image, then add the X
++    for (int i = 0; i < NumStates; i++) {
++	*pixmap[P_CLOSE * NumStates + i] = *pixmap[P_MAX * NumStates + i];
++	pixmap[P_CLOSE * NumStates + i]->detach();
++    }
++
++    for (int i = 0; i < NumStates; i++) {
++	bool isAct = (i < 3);
++	QPixmap *pixm = pixmap[P_CLOSE * NumStates + i];
++	p.begin(pixm);
++	QColor color = isAct ? activeColor : inactiveColor;
++	QRect r = QRect(3, 3, pixm->width() - 6, pixm->height() - 6);
++	for (int j = 0; j < 2; j++) {
++	    r.moveTo(j + 3, 3);
++	    p.setPen(j == 0 ? color.light(150) : color.dark(150));
++	    p.drawLine(r.left(), r.top(), r.right() - 1, r.bottom() - 1);
++	    p.drawLine(r.left(), r.top() + 1, r.right() - 1, r.bottom());
++	    p.drawLine(r.right() - 1, r.top(), r.left(), r.bottom() - 1);
++	    p.drawLine(r.right() - 1, r.top() + 1, r.left(), r.bottom());
++	}
++	p.end();
++    }
++    for (int i = 0; i < 2; i++) {
++	
++    }
++
++    // menu 
++    {
++	int off = (pixmap[P_MENU * NumStates]->width() - 16) / 2;
+ 	QSize bSize(16, 16);
+ 	QBitmap lightBitmap = QBitmap::fromData(bSize, 
+-		    light, QImage::Format_MonoLSB);
++		    menu_white_bits, QImage::Format_MonoLSB);
+ 	//lightBitmap.setMask(lightBitmap);
+ 	QBitmap darkBitmap = QBitmap::fromData(bSize, 
+-		    dark, QImage::Format_MonoLSB);
++		    menu_dgray_bits, QImage::Format_MonoLSB);
+ 	//darkBitmap.setMask(darkBitmap);
+ 
+         for (int i = 0; i < NumStates; i++) {
+ 	    bool isAct = (i < 3);
+-	    QPixmap *pixm = pixmap[pix* NumStates + i];
++	    QPixmap *pixm = pixmap[P_MENU * NumStates + i];
+ 	    p.begin(pixm);
+ 	    QColor color = isAct ? activeColor : inactiveColor;
+ 	    p.setPen(color.light(150));
+@@ -1074,6 +1078,33 @@
+         }
+     }
+ 
++    // Help button: a question mark.
++    {
++	QFont font = options()->font(true);
++	font.setWeight(QFont::Black);
++	font.setStretch(110);
++	font.setPointSizeF(font.pointSizeF() * 1.1);
++	for (int i = 0; i < NumStates; i++) {
++	    bool isAct = (i < 3);
++	    QPixmap *pixm = pixmap[P_HELP * NumStates + i];
++	    pixm->fill(QColor(qRgba(0, 0, 0, 0)));
++	    pixm->setAlphaChannel(*pixm);
++	    p.begin(pixm);
++	    QColor color = isAct ? activeColor : inactiveColor;
++	    QRect r = QRect(0, 0, pixm->width(), pixm->height());
++	    p.setFont(font);
++	    QString label = i18nc("Help button label, one character", "?");
++	    r.moveTo(1, 2);
++	    p.setPen(color.light(150));
++	    p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, label);
++	    r.moveTo(0, 1);
++	    p.setPen(color.dark(150));
++	    p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter, label);
++	    p.end();
++	}
++    }
++
++    // Help button: a question mark.
+     // pin
+     for (int i = 0; i < NumStates; i++) {
+ 	const bool isDown = (i == Down || i == IDown);
+@@ -1116,7 +1147,6 @@
+ 	*pixmap[offset + IHover] = hilighted;
+     }
+ 
+-
+     // Create the titlebar gradients
+     if (QPixmap::defaultDepth() > 8) {
+ 	QColor titleColor[4] = {
+@@ -1171,10 +1201,10 @@
+ }
+ 
+ // Transparent bound stuff.
+-
+ static QRect *visible_bound;
+ static QPolygon bound_shape;
+ 
++
+ bool B2Client::drawbound(const QRect& geom, bool clear)
+ {
+     if (clear) {
+@@ -1210,17 +1240,23 @@
+     } else {
+ 	*visible_bound = geom;
+     }
+-/**
+- * TODO: Replace by QRubberBand
+- *   QPainter p(workspaceWidget());
+- *   p.setPen(QPen(Qt::white, 5));
+- *   p.setRasterOp(Qt::XorROP);
+- *   p.drawPolygon(bound_shape);
+- */
+-    if (clear) {
+-	delete visible_bound;
+-	visible_bound = 0;
++    if (!workspaceWidget()) {
++	kDebug() << "workspaceWidget is null";
++    } else {
++	kDebug() << "workspaceWidget is " << workspaceWidget();
++	QPainter p;
++	if (p.begin(workspaceWidget())) {
++	    p.setPen(QPen(Qt::white, 5));
++	    p.setCompositionMode(QPainter::CompositionMode_Xor);
++	    p.drawPolygon(bound_shape);
++	    if (clear) {
++		delete visible_bound;
++		visible_bound = 0;
++	    }
++	    p.end();
++	}
+     }
++
+     return true;
+ }
+ 
+@@ -1367,7 +1403,7 @@
+       set_x11mask(false), isfullyobscured(false), shift_move(false)
+ {
+     setAttribute(Qt::WA_NoSystemBackground);
+-    captionSpacer = new QSpacerItem(buttonSize, buttonSize + 4,
++    captionSpacer = new QSpacerItem(buttonSize, buttonSize + 3,
+ 	    QSizePolicy::Expanding, QSizePolicy::Fixed);
+ }
+ 
+@@ -1423,7 +1459,7 @@
+     p.setPen(options()->color(KDecoration::ColorFont, state));
+     p.setFont(options()->font(state));
+     t = captionSpacer->geometry();
+-    p.drawText(t, Qt::AlignCenter | Qt::AlignVCenter, client->caption());
++    p.drawText(t.translated(0, 1), Qt::AlignCenter | Qt::AlignVCenter, client->caption());
+ }
+ 
+ void B2Titlebar::recalcBuffer()
+--- a/kwin/clients/b2/bitmaps.h
++++ b/kwin/clients/b2/bitmaps.h
+@@ -8,16 +8,6 @@
+  * These are all the bitmaps.
+  */
+ 
+-static const unsigned char close_white_bits[] = {
+-  0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02,
+-  0x20, 0x01, 0x40, 0x00, 0x40, 0x00, 0x20, 0x01, 0x10, 0x02, 0x08, 0x04,
+-  0x04, 0x08, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00};
+-
+-static const unsigned char close_dgray_bits[] = {
+-  0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x18, 0x30, 0x30, 0x18, 0x60, 0x0c,
+-  0xc0, 0x06, 0x80, 0x03, 0x80, 0x03, 0xc0, 0x06, 0x60, 0x0c, 0x30, 0x18,
+-  0x18, 0x30, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+-
+ static const unsigned char menu_white_bits[] = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xfc, 0x3f, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+@@ -73,26 +63,5 @@
+   0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 
+-static const unsigned char help_mask_bits[] = {
+- 0x00,0x00,0x00,0x00,0xe0,0x03,0xf0,0x07,0x70,0x0e,0x60,0x0e,0x00,0x0f,0x80,
+- 0x07,0xc0,0x03,0xc0,0x01,0x80,0x01,0xc0,0x00,0xc0,0x01,0x80,0x01,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
+- 0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
+- 0x65,0x44,0x78,0x63 };
+-
+-static const unsigned char help_dark_bits[] = {
+- 0x00,0x00,0x00,0x00,0xe0,0x03,0x30,0x06,0x30,0x06,0x00,0x06,0x00,0x03,0x80,
+- 0x01,0xc0,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x65,0x64,0x28,0x29,0x00,0x00,0x00,0x00,0x90,0x00,0x00,
+- 0x00,0x21,0x00,0x00,0x00,0x34,0xfe,0x12,0x2b,0x00,0x00,0xff,0xff,0x58,0xc0,
+- 0x01,0x2b,0x45,0xfe };
+-
+-static const unsigned char help_light_bits[] = {
+- 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x40,0x08,0x60,0x08,0x00,0x0c,0x00,
+- 0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x00,0x00,0x00,0x01,0x80,0x01,0x00,0x00,
+- 0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
+- 0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
+- 0x65,0x44,0x78,0x63 };
+-
+ #endif
+ 
+--- a/kwin/clients/oxygen/oxygenclient.desktop
++++ b/kwin/clients/oxygen/oxygenclient.desktop
+@@ -4,7 +4,7 @@
+ Name=Oxygen
+ Name[csb]=Krziseń
+ Name[kk]=Оттегі
+-Name[km]=អុកស៊ីសែន
++Name[km]=អុកស៊ីហ្សែន
+ Name[ne]=अक्सिजन
+ Name[nn]=Oksygen
+ Name[pa]=ਆਕਸੀਜਨ
+--- a/kwin/clients/oxygen/oxygenbutton.cpp
++++ b/kwin/clients/oxygen/oxygenbutton.cpp
+@@ -31,18 +31,15 @@
+ 
+ #include <kdecoration.h>
+ #include <kglobal.h>
++#include <KColorUtils>
+ 
+ #include "oxygenclient.h"
+ #include "oxygenbutton.h"
+ #include "oxygen.h"
+ #include "definitions.cpp"
+-#include "lib/helper.h"
+ 
+ namespace Oxygen
+ {
+-#ifndef KDE_USE_FINAL
+-K_GLOBAL_STATIC_WITH_ARGS(OxygenHelper, globalHelper, ("OxygenDeco"))
+-#endif
+ // class OxygenClient;
+ /*
+ extern int BUTTONSIZE;
+@@ -58,12 +55,14 @@
+ // ---------------
+ // Constructor
+ 
+-OxygenButton::OxygenButton(OxygenClient *parent,
++OxygenButton::OxygenButton(OxygenClient &parent,
+                              const QString& tip, ButtonType type)
+-    : KCommonDecorationButton((::ButtonType)type,(KCommonDecoration*) parent)
++    : KCommonDecorationButton((::ButtonType)type, &parent)
+     , client_(parent)
++    , helper_(parent.helper_)
+     , type_(type)
+     , lastmouse_(0)
++    , colorCacheInvalid_(true)
+ {
+     setAutoFillBackground(false);
+     setAttribute(Qt::WA_OpaquePaintEvent, false);
+@@ -76,6 +75,28 @@
+ {
+ }
+ 
++//declare function from oxygenclient.cpp
++QColor reduceContrast(const QColor &c0, const QColor &c1, double t);
++
++
++QColor OxygenButton::buttonDetailColor(const QPalette &palette)
++{
++    if (client_.isActive())
++        return palette.color(QPalette::Active, QPalette::ButtonText);
++    else {
++        if (colorCacheInvalid_) {
++            QColor ab = palette.color(QPalette::Active, QPalette::Button);
++            QColor af = palette.color(QPalette::Active, QPalette::ButtonText);
++            QColor nb = palette.color(QPalette::Inactive, QPalette::Button);
++            QColor nf = palette.color(QPalette::Inactive, QPalette::ButtonText);
++
++            colorCacheInvalid_ = false;
++            cachedButtonDetailColor_ = reduceContrast(nb, nf, qMax(2.5, KColorUtils::contrastRatio(ab, KColorUtils::mix(ab, af, 0.4))));
++        }
++        return cachedButtonDetailColor_;
++    }
++}
++
+ //////////////////////////////////////////////////////////////////////////////
+ // sizeHint()
+ // ----------
+@@ -130,53 +151,69 @@
+ void OxygenButton::paintEvent(QPaintEvent *)
+ {
+     QPainter painter(this);
++    QPalette pal = palette(); // de-const-ify
+ 
+     if (type_ == ButtonMenu) {
+         // we paint the mini icon (which is 16 pixels high)
+         int dx = (width() - 16) / 2;
+         int dy = (height() - 16) / 2;
+-        painter.drawPixmap(dx, dy, client_->icon().pixmap(16));
++        painter.drawPixmap(dx, dy, client_.icon().pixmap(16));
+         return;
+     }
+ 
+-    QColor bg = globalHelper->backgroundTopColor(palette().window());
+-    painter.drawPixmap(0, 0, globalHelper->windecoButton(palette().button()));
++    // Set palette to the right group. Lubos disagrees with this being a kwin
++    // bug, but anyway, we need the palette group to match the current window.
++    // Since kwin doesn't set it correctly, we have to do it ourselves.
++    if (client_.isActive())
++        pal.setCurrentColorGroup(QPalette::Active);
++    else
++        pal.setCurrentColorGroup(QPalette::Inactive);
++
++    QColor bg = helper_.backgroundTopColor(pal.window());
++    painter.drawPixmap(0, 0, helper_.windecoButton(pal.button()));
+ 
+-    painter.translate(1.5,1.5);
+     painter.setRenderHints(QPainter::Antialiasing);
+     painter.setBrush(Qt::NoBrush);
+-    QLinearGradient lg(0, 6, 0, 12);
+-    lg.setColorAt(0.45, QColor(0,0,0,150));
+-    lg.setColorAt(0.80, QColor(0,0,0,80));
+-    painter.setPen(QPen(lg,2));
++    QLinearGradient lg = helper_.decoGradient(QRect(4,4,13,13), buttonDetailColor(pal));
++    painter.setPen(QPen(lg, 2.2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+     switch(type_)
+     {
+         case ButtonSticky:
+-                    painter.drawPoint(9,9);
++            painter.drawPoint(QPointF(10.5,10.5));
+             break;
+         case ButtonHelp:
++            painter.translate(1.5, 1.5);
++            painter.drawArc(7,5,4,4,135*16, -180*16);
++            painter.drawArc(9,8,4,4,135*16,45*16);
++            painter.drawPoint(9,12);
+             break;
+         case ButtonMin:
+-            painter.drawLine(6,8,9,11);
+-            painter.drawLine(9,11,12,8);
++            painter.drawLine(QPointF( 7.5, 9.5), QPointF(10.5,12.5));
++            painter.drawLine(QPointF(10.5,12.5), QPointF(13.5, 9.5));
+             break;
+         case ButtonMax:
+-            switch(client_->maximizeMode())
++            switch(client_.maximizeMode())
+             {
+                 case OxygenClient::MaximizeRestore:
+                 case OxygenClient::MaximizeVertical:
+                 case OxygenClient::MaximizeHorizontal:
+-                    painter.drawLine(9,8,12,11);
+-                    painter.drawLine(6,11,9,8);
++                    painter.drawLine(QPointF( 7.5,11.5), QPointF(10.5, 8.5));
++                    painter.drawLine(QPointF(10.5, 8.5), QPointF(13.5,11.5));
+                     break;
+                 case OxygenClient::MaximizeFull:
+-                    painter.drawLine(6,9,12,9);
++                {
++                    painter.translate(1.5, 1.5);
++                    //painter.setBrush(lg);
++                    QPoint points[4] = {QPoint(9, 6), QPoint(12, 9), QPoint(9, 12), QPoint(6, 9)};
++                    //QPoint points[4] = {QPoint(9, 5), QPoint(13, 9), QPoint(9, 13), QPoint(5, 9)};
++                    painter.drawPolygon(points, 4);
+                     break;
++                }
+             }
+             break;
+         case ButtonClose:
+-            painter.drawLine(6,6,12,12);
+-            painter.drawLine(12,6,6,12);
++            painter.drawLine(QPointF( 7.5,7.5), QPointF(13.5,13.5));
++            painter.drawLine(QPointF(13.5,7.5), QPointF( 7.5,13.5));
+             break;
+         default:
+             break;
+--- a/kwin/clients/oxygen/oxygenclient.cpp
++++ b/kwin/clients/oxygen/oxygenclient.cpp
+@@ -12,10 +12,11 @@
+ // #ifndef OXYGENCLIENT_H
+ // #define OXYGENCLIENT_H
+ 
+-#include <kconfig.h>
+-#include <kglobal.h>
+-#include <klocale.h>
+-#include <kdebug.h>
++#include <KConfig>
++#include <KGlobal>
++#include <KLocale>
++#include <KDebug>
++#include <KColorUtils>
+ 
+ #include <qbitmap.h>
+ #include <qlabel.h>
+@@ -34,7 +35,7 @@
+ #include <QTimer>
+ #include <QCache>
+ 
+-#include "lib/helper.h"
++#include "math.h"
+ 
+ #include "oxygenclient.h"
+ #include "oxygenclient.moc"
+@@ -66,7 +67,11 @@
+ 
+ 
+ OxygenClient::OxygenClient(KDecorationBridge *b, KDecorationFactory *f)
+-    : KCommonDecoration(b, f) { ; }
++    : KCommonDecoration(b, f)
++    , helper_(*globalHelper)
++    , colorCacheInvalid_(true)
++{
++}
+ 
+ OxygenClient::~OxygenClient()
+ {
+@@ -92,7 +97,7 @@
+ 
+     widget()->setAutoFillBackground(false);
+     widget()->setAttribute(Qt::WA_OpaquePaintEvent);
+-    widget()->setAttribute( Qt::WA_PaintOnScreen, false);
++    widget()->setAttribute(Qt::WA_PaintOnScreen, false);
+ }
+ 
+ bool OxygenClient::decorationBehaviour(DecorationBehaviour behaviour) const
+@@ -183,19 +188,19 @@
+ {
+     switch (type) {
+         case MenuButton:
+-            return new OxygenButton(this, i18n("Menu"), ButtonMenu);
++            return new OxygenButton(*this, i18n("Menu"), ButtonMenu);
+ 
+         case HelpButton:
+-            return new OxygenButton(this, i18n("Help"), ButtonHelp);
++            return new OxygenButton(*this, i18n("Help"), ButtonHelp);
+ 
+         case MinButton:
+-            return new OxygenButton(this, i18n("Minimize"), ButtonMin);
++            return new OxygenButton(*this, i18n("Minimize"), ButtonMin);
+ 
+         case MaxButton:
+-            return new OxygenButton(this, i18n("Minimize"), ButtonMax);
++            return new OxygenButton(*this, i18n("Minimize"), ButtonMax);
+ 
+         case CloseButton:
+-            return new OxygenButton(this, i18n("Minimize"), ButtonClose);
++            return new OxygenButton(*this, i18n("Minimize"), ButtonClose);
+ 
+         default:
+             return 0;
+@@ -203,6 +208,52 @@
+ }
+ 
+ 
++// c0 - background
++// c1 - foreground
++// t - target contrast ratio
++QColor reduceContrast(const QColor &c0, const QColor &c1, double t)
++{
++    double s = KColorUtils::contrastRatio(c0, c1);
++    if (s < t)
++        return c1;
++
++    double l = 0.0, h = 1.0;
++    double x = s, a;
++    QColor r = c1;
++    for (int maxiter = 16; maxiter; --maxiter) {
++        a = 0.5 * (l + h);
++        r = KColorUtils::mix(c0, c1, a);
++        x = KColorUtils::contrastRatio(c0, r);
++        if (fabs(x - t) < 0.01)
++            break;
++        if (x > t)
++            h = a;
++        else
++            l = a;
++    }
++    return r;
++}
++
++
++QColor OxygenClient::titlebarTextColor(const QPalette &palette)
++{
++    if (isActive())
++        return palette.color(QPalette::Active, QPalette::WindowText);
++    else {
++        if(colorCacheInvalid_) {
++            QColor ab = palette.color(QPalette::Active, QPalette::Window);
++            QColor af = palette.color(QPalette::Active, QPalette::WindowText);
++            QColor nb = palette.color(QPalette::Inactive, QPalette::Window);
++            QColor nf = palette.color(QPalette::Inactive, QPalette::WindowText);
++
++            colorCacheInvalid_ = false;
++            cachedTitlebarTextColor_ = reduceContrast(nb, nf, qMax(2.5, KColorUtils::contrastRatio(ab, KColorUtils::mix(ab, af, 0.4))));
++        }
++        return cachedTitlebarTextColor_;
++    }
++}
++
++
+ void OxygenClient::paintEvent(QPaintEvent *e)
+ {
+     Q_UNUSED(e)
+@@ -213,10 +264,9 @@
+     QPalette palette = widget()->palette();
+     QPainter painter(widget());
+ 
+-    // ### - This feels like a kwin bug; the palette we get back always seems
+-    // to be (incorrectly) using the Inactive group, which is wrong; active
+-    // windows should have currentColorGroup() == Active. So, hack around it...
+-    // I don't think a window can be disabled?
++    // Set palette to the right group. Lubos disagrees with this being a kwin
++    // bug, but anyway, we need the palette group to match the current window.
++    // Since kwin doesn't set it correctly, we have to do it ourselves.
+     if (isActive())
+         palette.setCurrentColorGroup(QPalette::Active);
+     else
+@@ -241,21 +291,21 @@
+ 
+     int splitY = qMin(300, 3*frame.height()/4);
+ 
+-    QPixmap tile = globalHelper->verticalGradient(color, splitY);
++    QPixmap tile = helper_.verticalGradient(color, splitY);
+     painter.drawTiledPixmap(QRect(0, 0, frame.width(), titleHeight + TFRAMESIZE), tile);
+ 
+     painter.drawTiledPixmap(QRect(0, 0, LFRAMESIZE, splitY), tile);
+-    painter.fillRect(0, splitY, LFRAMESIZE, frame.height() - splitY, globalHelper->backgroundBottomColor(color));
++    painter.fillRect(0, splitY, LFRAMESIZE, frame.height() - splitY, helper_.backgroundBottomColor(color));
+ 
+     painter.drawTiledPixmap(QRect(frame.width()-RFRAMESIZE, 0,
+                                                         RFRAMESIZE, splitY), tile,
+                                                         QPoint(frame.width()-RFRAMESIZE, 0));
+-    painter.fillRect(frame.width()-RFRAMESIZE, splitY, RFRAMESIZE, frame.height() - splitY, globalHelper->backgroundBottomColor(color));
++    painter.fillRect(frame.width()-RFRAMESIZE, splitY, RFRAMESIZE, frame.height() - splitY, helper_.backgroundBottomColor(color));
+ 
+-    painter.fillRect(0, frame.height() - BFRAMESIZE, frame.width(), BFRAMESIZE, globalHelper->backgroundBottomColor(color));
++    painter.fillRect(0, frame.height() - BFRAMESIZE, frame.width(), BFRAMESIZE, helper_.backgroundBottomColor(color));
+ 
+     int radialW = qMin(600, frame.width());
+-    tile = globalHelper->radialGradient(color, radialW);
++    tile = helper_.radialGradient(color, radialW);
+     QRect radialRect = QRect((frame.width() - radialW) / 2, 0, radialW, 64);
+     painter.drawPixmap(radialRect, tile);
+ 
+@@ -263,41 +313,36 @@
+ 
+     // draw title text
+     painter.setFont(options()->font(isActive(), false));
+-    painter.setPen(palette.windowText());
++    painter.setPen(titlebarTextColor(palette));
+     painter.drawText(titleLeft, titleTop, titleWidth, titleHeight,
+               OxygenFactory::titleAlign() | Qt::AlignVCenter, caption());
+ 
+     painter.setRenderHint(QPainter::Antialiasing);
+ 
+-    // shadows of the frame
++    // Draw shadows of the frame
+     frame = widget()->rect();
+     frame.getRect(&x, &y, &w, &h);
+ 
+     painter.setBrush(Qt::NoBrush);
+-    QLinearGradient lg(0, 0, 0, 10);
+-    QGradientStops stops;
+-    stops << QGradientStop( 0, QColor(255,255,255, 110) )
+-           << QGradientStop( 1, QColor(128,128,128, 60) );
+-    lg.setStops(stops);
+-    painter.setPen(QPen(QBrush(lg),1));
+-    painter.drawLine(QPointF(6.3, 0.5), QPointF(w-6.3, 0.5));
+-    painter.drawArc(QRectF(0.5, 0.5, 9.5, 9.5),90*16, 90*16);
+-    painter.drawArc(QRectF(w-9.5-0.5, 0.5, 9.5, 9.5), 0, 90*16);
+-
++    painter.setPen(QColor(255,255,255, 120));
++    painter.drawLine(QPointF(0, 0.5), QPointF(w, 0.5));
+     painter.setPen(QColor(128,128,128, 60));
+-    painter.drawLine(QPointF(0.5, 6.3), QPointF(0.5, h-6.3));
+-    painter.drawLine(QPointF(w-0.5, 6.3), QPointF(w-0.5, h-6.3));
+-
+-    lg = QLinearGradient(0, h-10, 0, h);
+-    stops.clear();
+-    stops << QGradientStop( 0, QColor(128,128,128, 60) )
+-           << QGradientStop( 1, QColor(0,0,0, 50) );
+-    lg.setStops(stops);
+-    painter.setPen(QPen(QBrush(lg),1));
+-    painter.drawArc(QRectF(0.5, h-9.5-0.5, 9.5, 9.5),180*16, 90*16);
+-    painter.drawArc(QRectF(w-9.5-0.5, h-9.5-0.5, 9.5, 9.5), 270*16, 90*16);
+-    painter.drawLine(QPointF(6.3, h-0.5), QPointF(w-6.3, h-0.5));
++    painter.drawLine(QPointF(0.5, 0), QPointF(0.5, h));
++    painter.drawLine(QPointF(w-0.5, 0), QPointF(w-0.5, h));
++    painter.setPen(QColor(0,0,0, 60));
++    painter.drawLine(QPointF(0, h-0.5), QPointF(w, h-0.5));
++
++    painter.setPen(QColor(0,0,0, 40));
++    painter.drawPoint(QPointF(1.5, 1.5)); // top middle point
++    painter.drawPoint(QPointF(w-1.5, 1.5));
++    painter.drawPoint(QPointF(3.5, 0.5)); // top away points
++    painter.drawPoint(QPointF(w-3.5, 0.5));
++    painter.drawPoint(QPointF(0.5, 3.5));
++    painter.drawPoint(QPointF(w-0.5, 3.5));
++    painter.drawPoint(QPointF(1.5, h-1.5)); // bottom middle point
++    painter.drawPoint(QPointF(w-1.5, h-1.5));
+ 
++    // Draw the 3-dots resize handles
+     qreal cenY = frame.height() / 2 + 0.5;
+     qreal posX = frame.width() - 2.5;
+     painter.setPen(Qt::NoPen);
+@@ -314,27 +359,34 @@
+ 
+ void OxygenClient::doShape()
+ {
++    bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();
+   int r=widget()->width();
+   int b=widget()->height();
+ QRegion mask(0,0,r,b);
++
++    if(maximized) {
++        setMask(mask);
++        return;
++    }
++
+     // Remove top-left corner.
+     mask -= QRegion(0, 0, 3, 1);
+-    mask -= QRegion(0, 1, 2, 1);
++    mask -= QRegion(0, 1, 1, 1);
+     mask -= QRegion(0, 2, 1, 1);
+ 
+     // Remove top-right corner.
+     mask -= QRegion(r - 3, 0, 3, 1);
+-    mask -= QRegion(r - 2, 1, 2, 1);
++    mask -= QRegion(r - 1, 1, 1, 1);
+     mask -= QRegion(r - 1, 2, 1, 1);
+ 
+     // Remove bottom-left corner.
+     mask -= QRegion(0, b-1-0, 3, b-1-1);
+-    mask -= QRegion(0, b-1-1, 2, b-1-1);
++    mask -= QRegion(0, b-1-1, 1, b-1-1);
+     mask -= QRegion(0, b-1-2, 1, b-1-1);
+ 
+     // Remove bottom-right corner.
+     mask -= QRegion(r - 3, b-1-0, 3, b-1-1);
+-    mask -= QRegion(r - 2, b-1-1, 2, b-1-1);
++    mask -= QRegion(r - 1, b-1-1, 1, b-1-1);
+     mask -= QRegion(r - 1, b-1-2, 1, b-1-1);
+ 
+     setMask(mask);
+--- a/kwin/clients/oxygen/oxygenbutton.h
++++ b/kwin/clients/oxygen/oxygenbutton.h
+@@ -30,6 +30,7 @@
+ #include <kcommondecoration.h>
+ 
+ #include "oxygen.h"
++#include "oxygenclient.h"
+ 
+ namespace Oxygen
+ {
+@@ -45,7 +46,7 @@
+ class OxygenButton : public KCommonDecorationButton
+ {
+ public:
+-    explicit OxygenButton(OxygenClient *parent=0,
++    explicit OxygenButton(OxygenClient &parent,
+                   const QString &tip=NULL,
+                   ButtonType type=ButtonHelp);
+     ~OxygenButton();
+@@ -58,15 +59,19 @@
+     void enterEvent(QEvent *e);
+     void leaveEvent(QEvent *e);
+     void paintEvent(QPaintEvent *e);
++    QColor buttonDetailColor(const QPalette &palette);
+ 
+ private Q_SLOTS:
+     void pressSlot();
+ 
+ private:
+-    OxygenClient *client_;
++    OxygenClient &client_;
++    OxygenHelper &helper_;
+     ButtonType type_;
+     ButtonState status_;
+     int lastmouse_;
++    bool colorCacheInvalid_;
++    QColor cachedButtonDetailColor_;
+ };
+ 
+ } //namespace Oxygen
+--- a/kwin/clients/oxygen/oxygenclient.h
++++ b/kwin/clients/oxygen/oxygenclient.h
+@@ -31,7 +31,7 @@
+ 
+ #include <kcommondecoration.h>
+ 
+-#include "oxygenbutton.h"
++#include "lib/helper.h"
+ 
+ class QPoint;
+ 
+@@ -56,6 +56,13 @@
+ private:
+     void paintEvent(QPaintEvent *e);
+     void doShape();
++    QColor titlebarTextColor(const QPalette &palette);
++    bool colorCacheInvalid_;
++    QColor cachedTitlebarTextColor_;
++
++protected:
++    friend class OxygenButton;
++    OxygenHelper &helper_;
+ };
+ 
+ 
+--- a/kwin/clients/CMakeLists.txt
++++ b/kwin/clients/CMakeLists.txt
+@@ -3,12 +3,9 @@
+ add_subdirectory( b2 ) 
+ add_subdirectory( kde2 ) 
+ add_subdirectory( keramik ) 
+-message(STATUS "TODO - remove kdefx usage in laptop")
+-#add_subdirectory( laptop ) 
+-message(STATUS "TODO - remove kdefx usage in modernsystem")
+-#add_subdirectory( modernsystem ) 
++add_subdirectory( laptop ) 
++add_subdirectory( modernsystem ) 
+ add_subdirectory( oxygen ) 
+ add_subdirectory( quartz ) 
+-message(STATUS "TODO - remove kdefx usage in redmond")
+-#add_subdirectory( redmond ) 
++add_subdirectory( redmond ) 
+ add_subdirectory( web ) 
+--- a/kwin/kcmkwin/kwindecoration/kwindecoration.desktop
++++ b/kwin/kcmkwin/kwindecoration/kwindecoration.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kwindecoration
++Exec=kcmshell4 kwindecoration
+ Icon=preferences-system-windows-decoration
+ Type=Service
+ ServiceTypes=KCModule
+@@ -164,7 +164,7 @@
+ Keywords[is]=kwin,gluggi,gluggastjóri,gluggar,kantar,rammi,skreyting,þema,stíll,útlit,takki,kwm,skraut
+ Keywords[it]=kwin,finestra,window manager,bordo,stile,tema,aspetto,pulsante,maniglia,bordo,kwm,decorazione
+ Keywords[ja]=kwin,ウィンドウ,マネージャ,枠,スタイル,テーマ,ルック,外観,レイアウト,ボタン,ハンドル,エッジ,kwm,装飾
+-Keywords[km]=kwin,បង្អួច,កម្មវិធី​គ្រប់គ្រង,ស៊ុម,រចនាប័ទ្ម,ស្បែក,មើល,ស្គាល់,ប្លង់,ប៊ូតុង,ការ​គ្រប់គ្រង,គែម,kwm ,ការ​តុបតែង
++Keywords[km]=kwin បង្អួច កម្មវិធី​គ្រប់គ្រង ស៊ុម រចនាប័ទ្ម ស្បែក មើល ស្គាល់ ប្លង់ ប៊ូតុង ការ​គ្រប់គ្រង គែម kwm ការ​តុបតែង
+ Keywords[ko]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration ,창,윈도,관리자,매니저,테두리,꼴,스타일,테마,모양새,보이기,쓰임새,느끼기 ,배치,단추
+ Keywords[lt]=kwin,window,manager,border,style,theme,look,feel,layout,buttons,handle,edge,kwm,decoration,langas,tvarkyklė,rėmelis,stilius,tema,žiūrėti,jausti,išdėstymas,mygtukai,kraštas,dekoracija
+ Keywords[lv]=kwin, logs, menedžeris, rāmis, stils, tēma, skats, gars, izkārtojums, poga, rokturis, stūris, kwm, dekorācija
+--- a/kwin/kcmkwin/kwinrules/kwinrules.desktop
++++ b/kwin/kcmkwin/kwinrules/kwinrules.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kwinrules
++Exec=kcmshell4 kwinrules
+ Icon=preferences-system-windows-specific
+ Type=Service
+ ServiceTypes=KCModule
+@@ -157,7 +157,7 @@
+ Keywords[hu]=méret,pozíció,állapot,ablakműködés,ablakok,specifikus,megjegyzés,szabályok
+ Keywords[it]=dimensione,posizione,stato,comportamento finestra,finestre,specifico,ricorda,regole
+ Keywords[ja]=サイズ,位置,状態,ウィンドウの挙動,windows,特定,ワークアラウンド,記憶,ルール
+-Keywords[km]=ទំហំ,ទីតាំង,សភាព,ឥរិយាបថ​បង្អួច,បង្អួច,ជាក់លាក់,workarounds,ចងចាំ,ច្បាប់
++Keywords[km]=ទំហំ ទីតាំង សភាព ឥរិយាបថ​បង្អួច បង្អួច ជាក់លាក់ workarounds ចងចាំ ច្បាប់
+ Keywords[lt]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,dydis,pozicija,būsena,lango eelgesys,langai,atsiminti,taisyklės
+ Keywords[lv]=izmērs,novietojums,statuss,loga izturēšanās,logi,specifisks,apjājiens,atcerēties,noteikumi
+ Keywords[mk]=size,position,state,window behavior,windows,specific,workarounds,remember,rules,големина,позиција,состојба,однесување на прозорец,специфично,заобиколни
+--- a/kwin/kcmkwin/kwinrules/main.cpp
++++ b/kwin/kcmkwin/kwinrules/main.cpp
+@@ -41,7 +41,7 @@
+          i <= count;
+          ++i )
+         {
+-        cfg.changeGroup( QString::number( i ));
++        cfg = KConfigGroup(&_cfg,QString::number( i ));
+         Rules* rule = new Rules( cfg );
+         rules.append( rule );
+         }
+--- a/kwin/kcmkwin/kwinrules/ruleswidgetbase.ui
++++ b/kwin/kcmkwin/kwinrules/ruleswidgetbase.ui
+@@ -329,7 +329,7 @@
+                             <cstring>types</cstring>
+                         </property>
+                     </widget>
+-                    <widget class="KListWidget" row="1" column="0" rowspan="1" colspan="4">
++                    <widget class="QListWidget" row="1" column="0" rowspan="1" colspan="4">
+                         <item>
+                             <property name="text">
+                                 <string>Normal Window</string>
+--- a/kwin/kcmkwin/kwinrules/ruleslist.cpp
++++ b/kwin/kcmkwin/kwinrules/ruleslist.cpp
+@@ -161,7 +161,7 @@
+          i <= count;
+          ++i )
+         {
+-        cfg.changeGroup( QString::number( i ));
++        cfg = KConfigGroup(&_cfg,QString::number( i ));
+         Rules* rule = new Rules( cfg );
+         rules.append( rule );
+         rules_listbox->addItem( rule->description );
+--- a/kwin/kcmkwin/kwinrules/CMakeLists.txt
++++ b/kwin/kcmkwin/kwinrules/CMakeLists.txt
+@@ -11,7 +11,8 @@
+ 
+ kde4_add_kdeinit_executable( kwin_rules_dialog ${kwin_rules_dialog_KDEINIT_SRCS})
+ 
+-target_link_libraries(kdeinit_kwin_rules_dialog   ${KDE4_KDE3SUPPORT_LIBS} )
++target_link_libraries(kdeinit_kwin_rules_dialog   ${QT_QT3SUPPORT_LIBRARY}
++${KDE4_KDEUI_LIBS} )
+ 
+ install(TARGETS kdeinit_kwin_rules_dialog  DESTINATION ${LIB_INSTALL_DIR} )
+ 
+@@ -25,7 +26,8 @@
+ 
+ kde4_add_plugin(kcm_kwinrules ${kcm_kwinrules_PART_SRCS})
+ 
+-target_link_libraries(kcm_kwinrules   ${KDE4_KDE3SUPPORT_LIBS} )
++target_link_libraries(kcm_kwinrules   ${KDE4_KDEUI_LIBS}
++${QT_QT3SUPPORT_LIBRARY} )
+ 
+ install(TARGETS kcm_kwinrules  DESTINATION ${PLUGIN_INSTALL_DIR} )
+ 
+--- a/kwin/kcmkwin/kwincompositing/main.ui
++++ b/kwin/kcmkwin/kwincompositing/main.ui
+@@ -97,7 +97,7 @@
+             <item>
+              <widget class="QPushButton" name="advancedOptions" >
+               <property name="text" >
+-               <string>Advanced options...</string>
++               <string>Advanced Options...</string>
+               </property>
+              </widget>
+             </item>
+@@ -126,7 +126,7 @@
+      </widget>
+      <widget class="QWidget" name="tab_2" >
+       <attribute name="title" >
+-       <string>All effects</string>
++       <string>All Effects</string>
+       </attribute>
+       <layout class="QVBoxLayout" >
+        <item>
+--- a/kwin/kcmkwin/kwincompositing/advanced.ui
++++ b/kwin/kcmkwin/kwincompositing/advanced.ui
+@@ -38,7 +38,7 @@
+    <item>
+     <widget class="QGroupBox" name="glGroup" >
+      <property name="title" >
+-      <string>OpenGL options</string>
++      <string>OpenGL Options</string>
+      </property>
+      <layout class="QVBoxLayout" >
+       <item>
+@@ -121,7 +121,7 @@
+    <item>
+     <widget class="QGroupBox" name="xrenderGroup" >
+      <property name="title" >
+-      <string>XRender options</string>
++      <string>XRender Options</string>
+      </property>
+      <layout class="QVBoxLayout" >
+       <item>
+--- a/kwin/kcmkwin/kwincompositing/advanced.cpp
++++ b/kwin/kcmkwin/kwincompositing/advanced.cpp
+@@ -26,7 +26,7 @@
+     mKWinConfig = config;
+     mDefaultPrefs = defaults;
+ 
+-    setCaption(i18n("Advanced compositing options"));
++    setCaption(i18n("Advanced Compositing Options"));
+     setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Apply);
+     setModal(true);
+ 
+--- a/kwin/kcmkwin/kwincompositing/kwincompositing.desktop
++++ b/kwin/kcmkwin/kwincompositing/kwincompositing.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kwincompositing
++Exec=kcmshell4 kwincompositing
+ Icon=preferences-system-windows-effects
+ Type=Service
+ ServiceTypes=KCModule
+@@ -16,6 +16,7 @@
+ Name[de]=Arbeitsflächen-Effekte
+ Name[el]=Εφέ επιφάνειας εργασίας
+ Name[es]=Efectos del escritorio
++Name[et]=Töölauaefektid
+ Name[fa]=جلوه‌های رومیزی
+ Name[ga]=Maisíochtaí Deisce
+ Name[he]=אפקטי שולחן עבודה
+@@ -43,6 +44,7 @@
+ Comment[bg]=Настройване активирането на прозорците
+ Comment[de]=Arbeitsflächen-Effekte einrichten
+ Comment[el]=Ρύθμιση εφέ επιφάνειας εργασίας
++Comment[et]=Töölauaefektide seadistamine
+ Comment[fa]=پیکربندی جلوه‌های رومیزی
+ Comment[ga]=Cumraigh maisíochtaí deisce
+ Comment[he]=שינוי הגדרות אפקטי שולחן העבודה
+@@ -68,12 +70,13 @@
+ Keywords[bg]=kwin,window,manager,compositing,effect,прозорец,мениджър,ефект
+ Keywords[de]=kwin,fenster,manager,effekt,verwaltung,composit
+ Keywords[el]=παράθυρο,διαχειριστής,εφέ,kwin,παράθυρο,διαχειριστής,εφέ
++Keywords[et]=kwin,aken,haldur,komposiit,efekt
+ Keywords[fa]=kwin، پنجره، مدیر، ترکیب، جلوه
+ Keywords[ga]=kwin,fuinneog,bainisteoir,comhshuíomh,maisíocht
+ Keywords[he]=kwin,window,manager,compositing,effect,מנהל,חלונות,שזירה,אפקט
+ Keywords[it]=kwin,window,manager,compositing,effect,finestra,composizione,effetto,gestione
+ Keywords[ja]=kwin,ウィンドウ,マネージャ,コンポジティング,効果,エフェクト
+-Keywords[km]=kwin,បង្អួច,កម្មវិធី​គ្រប់គ្រង,សមាសភាគ,បែបផែន
++Keywords[km]=kwin បង្អួច កម្មវិធី​គ្រប់គ្រង សមាសភាគ បែបផែន
+ Keywords[nb]=kwin,vindu,vindusstyring,sammensetting,effekt
+ Keywords[nds]=kwin,Finster,Pleger,Effekt,Tosamensetten
+ Keywords[nl]=kwin,window,venster,window manager,effect,3D,compositing
+--- a/kwin/kcmkwin/kwinoptions/kwinfocus.desktop
++++ b/kwin/kcmkwin/kwinoptions/kwinfocus.desktop
+@@ -3,7 +3,7 @@
+ Icon=kcmkwm
+ Type=Service
+ ServiceTypes=KCModule
+-Exec=kcmshell kwinfocus
++Exec=kcmshell4 kwinfocus
+ DocPath=kcontrol/windowmanagement/index.html#action-focus
+ 
+ X-KDE-Library=kcm_kwinoptions
+@@ -153,7 +153,7 @@
+ Keywords[is]=fókus,staðsetning,fleyta upp sjálfkrafa, fleyta upp,smellur fleytir upp,lyklaborð,CDE,alt-tab,öll skjáborð
+ Keywords[it]=focus,piazzamento,alza automaticamente,alza,clic per alzare,tastiera, CDE,alt-tab,tutti i desktop
+ Keywords[ja]=フォーカス,配置,自動的に前面に,前面に,クリックして前面に,キーボード,CDE,alt-tab,すべてのデスクトップ
+-Keywords[km]=ផ្តោត​អារម្មណ៍,ការ​ដាក់,លើក​ឡើង​ស្វ័យប្រវត្តិ,លើក​ឡើង,ចុច,លើក​ឡើង,ក្ដារ​ចុច,CDE,ជំនួស (alt) - ថេប (tab),ផ្ទៃតុ​ទាំងអស់
++Keywords[km]=ផ្តោត​អារម្មណ៍ ការ​ដាក់ លើក​ឡើង​ស្វ័យប្រវត្តិ លើក​ឡើង ចុច លើក​ឡើង ក្ដារ​ចុច CDE ជំនួស(alt)-ថេប (tab) ផ្ទៃតុ​ទាំងអស់
+ Keywords[lt]=focus,placement,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop, fokusas,perkėlimas į pirmą planą, pirmas planas, klaviatūra, CDE,visi darbastaliai
+ Keywords[lv]=fokuss,novietojums,automātiska pacelšanās,pacelšanās,klikšķaraise,tastatūra,CDE,alt-tab,visas darbavirsmas
+ Keywords[mk]=focus,placement,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,фокус,позиција,авто подигање,подигање,клик подигање,сите десктопи
+--- a/kwin/kcmkwin/kwinoptions/kwinoptions.desktop
++++ b/kwin/kcmkwin/kwinoptions/kwinoptions.desktop
+@@ -1,6 +1,6 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+-Exec=kcmshell kwinoptions
++Exec=kcmshell4 kwinoptions
+ Icon=preferences-system-windows-behaviour
+ Type=Service
+ ServiceTypes=KCModule
+@@ -167,7 +167,7 @@
+ Keywords[is]=virkni glugga,staðsetning,hegðun,högun glugga,hækka,hækka sjálfkrafa,gluggar,titilslá,titilrönd,tvísmella
+ Keywords[it]=focus,piazzamento,comportamento finestre,animazione,alza,alza automaticamente,finestre,cornice,barra del titolo,doppio clic
+ Keywords[ja]=フォーカス,配置,ウィンドウの挙動,アニメーション,前面へ,自動的に前面へ,ウィンドウ,フレーム,タイトルバー,ダブルクリック
+-Keywords[km]=ផ្ដោត​អារម្មណ៍,ការ​ដាក់,ឥរិយាបថ​បង្អួច,ចលនា,លើកឡើង​លើ,លើក​ឡើង​ស្វ័យប្រវត្ត,បង្អួច,ស៊ុម,របារ​ចំណងជើង,ចុច​ទ្វេ​ដង
++Keywords[km]=ផ្ដោត​អារម្មណ៍ ការ​ដាក់ ឥរិយាបថ​បង្អួច ចលនា លើកឡើង​លើ លើក​ឡើង​ស្វ័យប្រវត្ត បង្អួច ស៊ុម របារ​ចំណងជើង ចុច​ទ្វេ​ដង
+ Keywords[lt]=focus,placement,window behaviour,animation,raise,auto raise,windows,frame,titlebar,doubleclick,lango išdėstymas,elgesys,langai,rėmelis,lango antraštė
+ Keywords[lv]=fokuss,novietojums,loga izturēšanās,animācija,celt,auto celt,logi,kadrs,virsraksta josla,dubultklikšķis
+ Keywords[mk]=focus,placement,window behavior,animation,raise,auto raise,windows,frame,titlebar,doubleclick,фокус,позиционирање,однесување на прозорците, анимација,подигање,авто подигање,прозорци,рамка,насловна лента,двоен клик
+--- a/kwin/kcmkwin/kwinoptions/kwinmoving.desktop
++++ b/kwin/kcmkwin/kwinoptions/kwinmoving.desktop
+@@ -3,7 +3,7 @@
+ Icon=kcmkwm
+ Type=Service
+ ServiceTypes=KCModule
+-Exec=kcmshell kwinmoving
++Exec=kcmshell4 kwinmoving
+ DocPath=kcontrol/windowmanagement/index.html#action-moving
+ 
+ X-KDE-Library=kcm_kwinoptions
+@@ -159,7 +159,7 @@
+ Keywords[is]=færi,snjallt,stafla,hámarka,gripsvæði,grip,rammi,jaðar
+ Keywords[it]=spostamento,intelligente,cascata,massimizza,zona magnetica,bordi,bordi magnetici
+ Keywords[ja]=移動,スマート,カスケード,最大化,スナップゾーン,スナップ境界
+-Keywords[km]=ការ​ផ្លាស់ទី,ឆ្លាត,ល្បាក់,ពង្រីក​អប្បបរមា,តំបន់​ខ្ទាស់,ខ្ទាស់,ស៊ុម
++Keywords[km]=ការ​ផ្លាស់ទី ឆ្លាត ល្បាក់ ពង្រីក​អប្បបរមា តំបន់​ខ្ទាស់ ខ្ទាស់ ស៊ុម
+ Keywords[lt]=moving,smart,cascade,maximize,maximise,snap zone,snap,border, perkėlimas,išmoningas,kaskada,išdidinti,rėmelis,riba
+ Keywords[lv]=pārvietošana,gudra,kaskāde,maksimizē,maksimizēšana,pielipsanas zona,pielipt,mala
+ Keywords[mk]=moving,smart,cascade,maximize,maximise,snap zone,snap,border, движење,паметно,каскадно,рашири,спушти,граница
+--- a/kwin/kcmkwin/kwinoptions/kwinactions.desktop
++++ b/kwin/kcmkwin/kwinoptions/kwinactions.desktop
+@@ -3,7 +3,7 @@
+ Icon=kcmkwm
+ Type=Service
+ ServiceTypes=KCModule
+-Exec=kcmshell kwinactions
++Exec=kcmshell4 kwinactions
+ DocPath=kcontrol/windowmanagement/index.html#action-actions
+ 
+ X-KDE-Library=kcm_kwinoptions
+--- a/kwin/kcmkwin/kwinoptions/kwinadvanced.desktop
++++ b/kwin/kcmkwin/kwinoptions/kwinadvanced.desktop
+@@ -3,7 +3,7 @@
+ Icon=kcmkwm
+ Type=Service
+ ServiceTypes=KCModule
+-Exec=kcmshell kwinadvanced
++Exec=kcmshell4 kwinadvanced
+ DocPath=kcontrol/windowmanagement/index.html#action-advanced
+ 
+ X-KDE-Library=kcm_kwinoptions
+@@ -163,7 +163,7 @@
+ Keywords[is]=rúlla upp,skyggja,rammi,svif,hover,virkir rammar
+ Keywords[it]=arrotola,bordi,passaggio del mouse,bordi attivi
+ Keywords[ja]=畳む,境界,復元,アクティブ境界
+-Keywords[km]=ស្រមោល,ស៊ុម,សំកាំង,ស៊ុម​សកម្ម
++Keywords[km]=ស្រមោល ស៊ុម សំកាំង ស៊ុម​សកម្ម
+ Keywords[lt]=shading,border,hover,active borders, tik antraštės juosta, rėmelis, aktyvūs rėmeliai
+ Keywords[lv]=ēnošana,mala,hover,aktīvās malas
+ Keywords[mk]=shading,border,hover,active borders,засенчување,граница,лебди,активни граници
+--- a/kwin/options.cpp
++++ b/kwin/options.cpp
+@@ -161,7 +161,7 @@
+     showDesktopIsMinimizeAll = config.readEntry( "ShowDesktopIsMinimizeAll", false );
+ 
+     // Mouse bindings
+-    config.changeGroup("MouseBindings");
++    config = KConfigGroup(_config,"MouseBindings");
+     CmdActiveTitlebar1 = mouseCommand(config.readEntry("CommandActiveTitlebar1","Raise"), true );
+     CmdActiveTitlebar2 = mouseCommand(config.readEntry("CommandActiveTitlebar2","Lower"), true );
+     CmdActiveTitlebar3 = mouseCommand(config.readEntry("CommandActiveTitlebar3","Operations menu"), true );
+@@ -178,11 +178,10 @@
+     CmdAll3 = mouseCommand(config.readEntry("CommandAll3","Resize"), false );
+     CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel","Nothing"));
+ 
+-    config.changeGroup("Translucency");
++    config=KConfigGroup(_config,"Compositing");
+     refreshRate = config.readEntry( "RefreshRate", 0 );
+-    glStrictBinding = config.readEntry( "GLStrictBinding", false );
+     const HiddenPreviews hps[] = { HiddenPreviewsNever, HiddenPreviewsKeep, HiddenPreviewUpdate, HiddenPreviewsActive };
+-    hiddenPreviews = hps[ qBound( 0, config.readEntry( "HiddenPreviews", 3 ), 3 ) ];
++    hiddenPreviews = hps[ qBound( 0, config.readEntry( "HiddenPreviews", 0 ), 3 ) ];
+ 
+     // Read button tooltip animation effect from kdeglobals
+     // Since we want to allow users to enable window decoration tooltips
+@@ -231,6 +230,7 @@
+     glDirect = config.readEntry("GLDirect", prefs.enableDirectRendering() );
+     glVSync = config.readEntry("GLVSync", prefs.enableVSync() );
+     smoothScale = qBound( -1, config.readEntry( "GLTextureFilter", -1 ), 2 );
++    glStrictBinding = config.readEntry( "GLStrictBinding", prefs.strictBinding());
+ 
+     xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false );
+     }
+--- a/kwin/compositingprefs.h
++++ b/kwin/compositingprefs.h
+@@ -44,17 +44,20 @@
+     bool enableCompositing() const  { return mEnableCompositing; }
+     bool enableVSync() const  { return mEnableVSync; }
+     bool enableDirectRendering() const  { return mEnableDirectRendering; }
++    bool strictBinding() const { return mStrictBinding; }
+ 
+     void detect();
+ 
+     QString driver() const  { return mDriver; }
+     Version version() const  { return mVersion; }
++    bool xgl() const { return mXgl; }
+ 
+ 
+ protected:
+ 
+     void detectDriverAndVersion();
+     void applyDriverSpecificOptions();
++    static bool detectXgl();
+ 
+     bool createGLXContext();
+     void deleteGLXContext();
+@@ -66,10 +69,12 @@
+     QString mGLVersion;
+     QString mDriver;
+     Version mVersion;
++    bool mXgl;
+ 
+     bool mEnableCompositing;
+     bool mEnableVSync;
+     bool mEnableDirectRendering;
++    bool mStrictBinding;
+ 
+ #ifdef HAVE_OPENGL
+     GLXContext mGLContext;
+--- a/kwin/scene_opengl.cpp
++++ b/kwin/scene_opengl.cpp
+@@ -870,7 +870,9 @@
+             createTexture();
+         // when the pixmap is bound to the texture, they share the same data, so the texture
+         // updates automatically - no need to do anything in such case
+-        if( bound_glxpixmap == None )
++        if( bound_glxpixmap != None )
++            glBindTexture( mTarget, mTexture );
++        else
+             {
+             int attrs[] =
+                 {
+@@ -911,11 +913,12 @@
+             }
+         findTarget();
+ #ifdef CHECK_GL_ERROR
+-            checkGLError( "TextureLoadSHM1" );
++        checkGLError( "TextureLoadSHM1" );
+ #endif
+         if( mTexture == None )
+             {
+             createTexture();
++            glBindTexture( mTarget, mTexture );
+             y_inverted = false;
+             glTexImage2D( mTarget, 0, depth == 32 ? GL_RGBA : GL_RGB,
+                 mSize.width(), mSize.height(), 0,
+@@ -970,6 +973,7 @@
+         if( mTexture == None )
+             {
+             createTexture();
++            glBindTexture( mTarget, mTexture );
+             y_inverted = false;
+             glCopyTexImage2D( mTarget, 0,
+                 depth == 32 ? GL_RGBA : GL_RGB,
+--- a/kwin/COMPOSITE_TODO
++++ b/kwin/COMPOSITE_TODO
+@@ -87,12 +87,13 @@
+ 
+ / handling of window pixmaps for unmapped windows [Seli]
+   - config option?
+-- strict binding
+ 
+ - shm mode needs support for more data formats than GL_BGRA
+ 
+ ? __GL_YIELD=NOTHING
+ 
++? libIndirectGL.so
++
+ - check what works with XRender
+ 
+ - more notification functions for effects
+@@ -211,6 +212,9 @@
+ % __GL_YIELD=NOTHING for NVidia reportedly improves perceived performance
+     - it needs to be set somehow (http://lists.kde.org/?l=kwin&m=117794153720348&w=2)
+ 
++% LD_PRELOAD=/usr/lib/libIndirectGL.so.1 seems to noticeably improve smoothness
++    - (http://lists.kde.org/?t=119186684900004&r=1&w=2)
++
+ 
+ XRender TODO
+ ==============================
+--- a/kwin/sm.cpp
++++ b/kwin/sm.cpp
+@@ -205,45 +205,54 @@
+     // First search ``session''
+     if (! sessionId.isEmpty() ) 
+         {
+-			// look for a real session managed client (algorithm suggested by ICCCM)
+-			foreach( SessionInfo* info, session ) {
+-				if ( realInfo )
+-					break;
+-				if ( info->sessionId == sessionId && sessionInfoWindowTypeMatch( c, info )) 
+-				{
+-				if ( ! windowRole.isEmpty() ) 
+-					{
+-					if ( info->windowRole == windowRole )
+-						realInfo = info;
+-						session.removeAll(info);
+-					}
+-				else 
+-					{
+-					if ( info->windowRole.isEmpty() &&
+-						 info->resourceName == resourceName &&
+-						 info->resourceClass == resourceClass )
+-						realInfo = info;
+-						session.removeAll(info);
+-					}
+-				}
+-			}
++        // look for a real session managed client (algorithm suggested by ICCCM)
++        foreach( SessionInfo* info, session )
++            {
++            if( realInfo )
++                break;
++            if( info->sessionId == sessionId && sessionInfoWindowTypeMatch( c, info )) 
++                {
++                if( ! windowRole.isEmpty() ) 
++                    {
++                    if( info->windowRole == windowRole )
++                        {
++                        realInfo = info;
++                        session.removeAll(info);
++                        }
++                    }
++                else 
++                    {
++                    if( info->windowRole.isEmpty()
++                        && info->resourceName == resourceName
++                        && info->resourceClass == resourceClass )
++                        {
++                        realInfo = info;
++                        session.removeAll(info);
++                        }
++                    }
++                }
++            }
+         }
+     else 
+         {
+-			// look for a sessioninfo with matching features.
+-			foreach( SessionInfo* info, session ) {
+-				if ( realInfo ) break;
+-				if ( info->resourceName == resourceName &&
+-						info->resourceClass == resourceClass &&
+-						info->wmClientMachine == wmClientMachine &&
+-						sessionInfoWindowTypeMatch( c, info ))
+-					if ( wmCommand.isEmpty() || info->wmCommand == wmCommand ) {
+-						realInfo = info;
+-						session.removeAll( info );
+-					}
+-			}
++        // look for a sessioninfo with matching features.
++        foreach( SessionInfo* info, session )
++            {
++            if( realInfo )
++                break;
++            if( info->resourceName == resourceName
++                && info->resourceClass == resourceClass
++                && info->wmClientMachine == wmClientMachine
++                && sessionInfoWindowTypeMatch( c, info ))
++                {
++                if ( wmCommand.isEmpty() || info->wmCommand == wmCommand )
++                    {
++                    realInfo = info;
++                    session.removeAll( info );
++                    }
++                }
++            }
+         }
+-
+     return realInfo;
+     }
+ 
+@@ -386,8 +395,8 @@
+     props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
+     props[ 2 ].num_vals = 1;
+     props[ 2 ].vals = &propvalue[ 2 ];
+-    propvalue[ 3 ].length = 0;
+-    propvalue[ 3 ].value = qApp->argv()[ 0 ];
++    propvalue[ 3 ].length = strlen( "kwinsmhelper" );
++    propvalue[ 3 ].value = (SmPointer)"kwinsmhelper";
+     props[ 3 ].name = const_cast< char* >( SmProgram );
+     props[ 3 ].type = const_cast< char* >( SmARRAY8 );
+     props[ 3 ].num_vals = 1;
+--- a/kwin/kwin.notifyrc
++++ b/kwin/kwin.notifyrc
+@@ -537,6 +537,7 @@
+ Comment=Virtual desktop six is selected
+ Comment[br]=Burev galloudel C'hwec'h a zo diuzet
+ Comment[el]=Επιλέχθηκε η έκτη εικονική επιφάνεια εργασίας
++Comment[et]=Kuues virtuaalne töölaud on valitud
+ Comment[ga]=Roghnaíodh deasc fhíorúil a sé
+ Comment[it]=Il desktop virtuale sei è selezionato
+ Comment[ja]=仮想デスクトップ 6 が選択されました
+@@ -1530,7 +1531,7 @@
+ Comment[da]=Virtuel desktop atten er valgt
+ Comment[el]=Επιλέχθηκε η 18η εικονική επιφάνεια εργασίας
+ Comment[eo]=Tabulo dek oka estas elektita
+-Comment[et]=Kaheksateiskümnes virtuaalne töölaud on valitud
++Comment[et]=Kaheksateistkümnes virtuaalne töölaud on valitud
+ Comment[eu]=Hamazortzigarren mahaigain birtuala hautatua dago
+ Comment[fi]=Virtuaalityöpöytä kahdeksantoista on valittu
+ Comment[fr]=Le bureau virtuel 18 est sélectionné
+@@ -1736,6 +1737,7 @@
+ Name=Activate Window
+ Name[be]=Актывізаваць акно
+ Name[el]=Ενεργοποίηση παραθύρου
++Name[et]=Akna aktiveerimine
+ Name[fy]=Finster aktivearje
+ Name[ga]=Gníomhachtaigh Fuinneog
+ Name[it]=Attiva finestra
+@@ -1863,6 +1865,7 @@
+ Comment=New window
+ Comment[be]=Новае акно
+ Comment[el]=Νέο παράθυρο
++Comment[et]=Uus aken
+ Comment[fy]=Nij finster
+ Comment[ga]=Fuinneog nua
+ Comment[it]=Nuova finestra
+@@ -1887,6 +1890,7 @@
+ Name=Delete Window
+ Name[be]=Выдаліць акно
+ Name[el]=Διαγραφή παραθύρου
++Name[et]=Akna kustutamine
+ Name[ga]=Scrios Fuinneog
+ Name[ja]=ウィンドウを削除
+ Name[km]=លុប​បង្អួច
+@@ -1948,11 +1952,12 @@
+ Name[be]=Закрыць акно
+ Name[br]=Serriñ ar Prenestr
+ Name[el]=Κλείσιμο παραθύρου
++Name[et]=Aken sulgub
+ Name[fy]=Finster slute
+ Name[ga]=Dún fuinneog
+ Name[it]=Chiusura finestra
+ Name[ja]=ウィンドウを閉じる
+-Name[km]=ការ​បិទ​បង្អួច
++Name[km]=បិទ​បង្អួច
+ Name[lt]=Uždaryti langą
+ Name[nb]=Vindu lukkes
+ Name[nds]=Finster tomaken
+@@ -2192,7 +2197,7 @@
+ Name[is]=Glugga lágmarkað
+ Name[ja]=ウィンドウ最小化
+ Name[ka]=ფანჯრის მინიმიზება
+-Name[km]=បង្អួច​បង្រួម​អប្បបរមា
++Name[km]=​បង្រួម​បង្អួច​អប្បបរមា
+ Name[lt]=Sumažinti langą
+ Name[lv]=Minimizet logu
+ Name[mk]=Спушти прозорец
+@@ -2233,7 +2238,7 @@
+ Comment[is]=Gluggi er lágmarkaður
+ Comment[ja]=ウィンドウが最小化されました
+ Comment[ka]=ფანჯარა მინიმიზირებულია
+-Comment[km]=បង្រួម​បង្អួច​អប្បបរមា
++Comment[km]=បង្អួច​ត្រូវ​បាន​បង្រួម​អប្បបរមា
+ Comment[lt]=Langas sumažintas
+ Comment[lv]=Logs ir Minimizēts
+ Comment[mk]=Прозорецот се спушта
+@@ -2403,7 +2408,7 @@
+ Comment[is]=Gluggi er hámarkaður
+ Comment[ja]=ウィンドウが最大化されました
+ Comment[ka]=ფანჯარა მაქსიმიზირებულია
+-Comment[km]=ពង្រីក​អតិបរមា​បង្អួច
++Comment[km]=ពង្រីក​បង្អួច​អតិបរមា​
+ Comment[lt]=Langas išdidintas
+ Comment[lv]=Logs ir Maksimizēts
+ Comment[mk]=Прозорецот се раширува
+@@ -2517,6 +2522,7 @@
+ Name=Window on All Desktops
+ Name[be]=Акно на ўсіх працоўных сталах
+ Name[el]=Παράθυρο σε όλες τις επιφάνειες
++Name[et]=Aken kõigil töölaudadel
+ Name[ga]=Fuinneog ar Gach Deasc
+ Name[it]=Finestra su tutti i desktop
+ Name[ja]=ウィンドウがすべてのデスクトップに
+@@ -2576,9 +2582,10 @@
+ [Event/not_on_all_desktops]
+ Name=Window Not on All Desktops
+ Name[el]=Παράθυρο εκτός όλων των επιφανειών
++Name[et]=Aken ei ole kõigil töölaudadel
+ Name[it]=Finestra non su tutti i desktop
+ Name[ja]=ウィンドウが一部のデスクトップのみに
+-Name[km]=បង្អួច​មិន​នៅ​លើ​ផ្ទៃតុ​ទាំងអស់
++Name[km]=បង្អួច​មិន​នៅ​លើ​ផ្ទៃតុ​ទាំងអស់​ទេ
+ Name[nb]=Vindu ikke på alle skrivebord
+ Name[nds]=Finster nich op all Schriefdischen
+ Name[nl]=Venster niet op alle bureaubladen
+@@ -2606,7 +2613,7 @@
+ Comment[it]=Una finestra non è più visibile su tutti i desktop
+ Comment[ja]=ウィンドウが一部のデスクトップで不可視になりました
+ Comment[ka]=ფანჯარა არ ჩანს ყველა სამუშაო დაფაზე
+-Comment[km]=បង្អួច​មិន​អាច​មើល​ឃើញ​នៅ​លើ​ផ្ទៃតុ​ទាំងអស់​ទេ
++Comment[km]=បង្អួច​មិន​អាច​មើល​ឃើញ​នៅ​លើ​ផ្ទៃតុ​ទាំងអស់​ទៀតទេ
+ Comment[lt]=Langas nebematomas visuose darbastaliuose
+ Comment[lv]=Logs vairs nav redzams uz visām darba virsmām
+ Comment[mk]=Прозорецот не е повеќе видлив на сите површини
+@@ -2677,9 +2684,10 @@
+ Name[zh_TW]=新對話框
+ Comment=Transient window (a dialog) appears
+ Comment[el]=Ένα προσωρινό παράθυρο (διάλογος) εμφανίζεται
++Comment[et]=Avaneb ajutine aken (dialoog)
+ Comment[it]=Appare una finestra di dialogo
+ Comment[ja]=ダイアログウィンドウが表示されました
+-Comment[km]=បង្អួច​បណ្ដោះ​អាសន្ន​បាន​លេចឡើង
++Comment[km]=បង្អួច​បណ្ដោះ​អាសន្ន​បាន​លេច​ឡើង
+ Comment[lt]=Atsiranda laikinas langas (dialogas)
+ Comment[nb]=Et midlertidig vindu (en dialog) vises
+ Comment[nds]=En temporeer Finster (en Dialoog) dukt op
+@@ -2964,7 +2972,7 @@
+ Name[is]=Stærðarbreyting glugga hefst
+ Name[ja]=ウィンドウリサイズ開始
+ Name[ka]=ფანჯრის ზომა იზვლბა
+-Name[km]=ការ​ចាប់ផ្ដើម​ប្ដូរ​ទំហំ​បង្អួច
++Name[km]=ចាប់ផ្ដើម​ផ្លាស់ប្ដូរ​ទំហំ​បង្អួច
+ Name[lt]=Lango dydžio keitimo pradžia
+ Name[lv]=Sākas Loga Izmēra Maiņa
+ Name[mk]=Почеток на промена на големината на прозорец
+@@ -3002,7 +3010,7 @@
+ Comment[is]=Stærð glugga er byrjuð að breytast
+ Comment[ja]=ウィンドウのリサイズを開始しました
+ Comment[ka]=ფანჯარამ დაიწყო ზომის შეცვლა
+-Comment[km]=បង្អួច​បាន​ចាប់ផ្ដើម​ប្ដូរ​ទំហំ
++Comment[km]=បង្អួច​បាន​ចាប់ផ្ដើម​ផ្លាស់ប្ដូរ​ទំហំ
+ Comment[lt]=Lango dydis pradėtas keisti
+ Comment[lv]=Loga Izmēra Maiņa Sākusies
+ Comment[mk]=Прозорецот започна да ја менува големината
+@@ -3044,7 +3052,7 @@
+ Name[is]=Stærðarbreyting glugga lýkur
+ Name[ja]=ウィンドウリサイズ終了
+ Name[ka]=ფანჯრის ზომა შეიცვალა
+-Name[km]=ចុង​បញ្ចប់​ការ​ប្ដូរ​ទំហំ​បង្អួច
++Name[km]=ចុង​បញ្ចប់​ការ​ផ្លាស់ប្ដូរ​​ទំហំ​បង្អួច
+ Name[lt]=Lango dydžio keitimo pabaiga
+ Name[lv]=Loga Izmēra Maiņa Beidzas
+ Name[mk]=Крај на промена на големината на прозорец
+@@ -3082,7 +3090,7 @@
+ Comment[is]=Stærð glugga hefur breyst
+ Comment[ja]=ウィンドウのリサイズが終了しました
+ Comment[ka]=ფანჯრის ზომის ცვლილება დასრულდა
+-Comment[km]=បង្អួច​បាន​បញ្ចប់​ការ​ប្ដូរ​ទំហំ
++Comment[km]=បង្អួច​បាន​បញ្ចប់​ការ​ផ្លាស់ប្ដូរ​ទំហំ
+ Comment[lt]=Lango dydžio keitimas baigtas
+ Comment[lv]=Loga Izmēra Maiņa Beigusies
+ Comment[mk]=Прозорецот заврши со менувањето на големината
+@@ -3108,6 +3116,7 @@
+ [Event/demandsattentioncurrent]
+ Name=Window on Current Desktop Demands Attention
+ Name[el]=Παράθυρο της τρέχουσας επιφάνειας απαιτεί προσοχή
++Name[et]=Aken aktiivsel töölaual nõuab tähelepanu
+ Name[ja]=現在のデスクトップのウィンドウが注意を要求
+ Name[km]=បង្អួច​នៅ​លើ​ផ្ទៃតុ​បច្ចុប្បន្ន​ទាមទារ​ការ​ចាប់អារម្មណ៍
+ Name[nb]=VIndu på gjeldende skrivebord vil ha oppmerksomhet
+@@ -3136,7 +3145,7 @@
+ Comment[is]=Gluggi á núverandi sýndarskjáborði krefst athygli
+ Comment[ja]=現在の仮想ウィンドウ上のウィンドウが注意を促しています
+ Comment[ka]=მიმდინარე ვირტუალური სამუშაო დაფის ფანჯარა ყურადღებას მოითხოვს
+-Comment[km]=បង្អួច​លើ​ផ្ទៃតុ​និម្មិត​បច្ចុប្បន្ន​ទាមទារ​ការ​ចាប់អារម្មណ៍
++Comment[km]=បង្អួច​លើ​ផ្ទៃតុ​និម្មិត​បច្ចុប្បន្ន​ទាមទារ​ការ​ចាប់​អារម្មណ៍
+ Comment[lt]=Langas dabartiniame menamame darbastalyje reikalauja dėmesio
+ Comment[mk]=Некој од прозорците на тековната површина бара внимание
+ Comment[nb]=Et vIndu på gjeldende skrivebord vil ha oppmerksomhet
+@@ -3158,6 +3167,7 @@
+ [Event/demandsattentionother]
+ Name=Window on Other Desktop Demands Attention
+ Name[el]=Παράθυρο σε άλλη επιφάνεια εργασίας απαιτεί προσοχή
++Name[et]=Aken teisel töölaual nõuab tähelepanu
+ Name[ja]=他のデスクトップのウィンドウが注意を要求
+ Name[km]=បង្អួច​នៅ​លើ​ផ្ទៃតុ​និម្មិត​ផ្សេង​ទៀត​ទាមទារ​ការ​ចាប់​អារម្មណ៍
+ Name[nb]=VIndu på annet skrivebord vil ha oppmerksomhet
+--- a/kwin/compositingprefs.cpp
++++ b/kwin/compositingprefs.cpp
+@@ -20,11 +20,14 @@
+ {
+ 
+ CompositingPrefs::CompositingPrefs()
++    : mXgl( false )
++    , mEnableCompositing( false )
++    , mEnableVSync( true )
++    , mEnableDirectRendering( true )
++    , mStrictBinding( true )
+     {
+-    mEnableCompositing = false;
+-    mEnableVSync = true;
+-    mEnableDirectRendering = true;
+     }
++
+ CompositingPrefs::~CompositingPrefs()
+     {
+     }
+@@ -163,26 +166,28 @@
+     mGLVendor = QString((const char*)glGetString( GL_VENDOR ));
+     mGLRenderer = QString((const char*)glGetString( GL_RENDERER ));
+     mGLVersion = QString((const char*)glGetString( GL_VERSION ));
++    mXgl = detectXgl();
+     kDebug() << "GL vendor is" << mGLVendor;
+     kDebug() << "GL renderer is" << mGLRenderer;
+     kDebug() << "GL version is" << mGLVersion;
++    kDebug() << "XGL:" << ( mXgl ? "yes" : "no" );
+ 
+     if( mGLRenderer.contains( "Intel" ))
+-    {
++        {
+         mDriver = "intel";
+         QStringList words = mGLRenderer.split(" ");
+         mVersion = Version( words[ words.count() - 2 ] );
+-    }
++        }
+     else if( mGLVendor.contains( "NVIDIA" ))
+-    {
++        {
+         mDriver = "nvidia";
+         QStringList words = mGLVersion.split(" ");
+         mVersion = Version( words[ words.count() - 1 ] );
+-    }
++        }
+     else
+-    {
++        {
+         mDriver = "unknown";
+-    }
++        }
+ 
+     kDebug() << "Detected driver" << mDriver << ", version" << mVersion.join(".");
+ #endif
+@@ -190,7 +195,13 @@
+ 
+ void CompositingPrefs::applyDriverSpecificOptions()
+     {
+-    if( mDriver == "intel")
++    if( mXgl )
++        {
++        kDebug() << "xgl, enabling";
++        mEnableCompositing = true;
++        mStrictBinding = false;
++        }
++    else if( mDriver == "intel")
+         {
+         kDebug() << "intel driver, disabling vsync, enabling direct";
+         mEnableVSync = false;
+@@ -205,6 +216,7 @@
+         {
+         kDebug() << "nvidia driver, disabling vsync";
+         mEnableVSync = false;
++        mStrictBinding = false;
+         if( mVersion >= Version( "96.39" ))
+             {
+             kDebug() << "nvidia >= 96.39, enabling compositing";
+@@ -214,6 +226,11 @@
+     }
+ 
+ 
++bool CompositingPrefs::detectXgl()
++    { // Xgl apparently uses only this specific X version
++    return VendorRelease(display()) == 70000001;
++    }
++
+ CompositingPrefs::Version::Version( const QString& str ) :
+         QStringList()
+     {
+--- a/kwin/data/fsp_workarounds_1.kwinrules
++++ b/kwin/data/fsp_workarounds_1.kwinrules
+@@ -3,6 +3,7 @@
+ Description[bg]=(По подразбиране) Изключване открадването на фокуса за XV
+ Description[de]=(Standard) Aktivierungsübernahme verhindern für XV
+ Description[el]=(Προκαθορισμένο) Αποτροπή κλεψίματος εστίασης για το XV
++Description[et]=(Vaikimisi) Fookuse röövimise vältimise keelamine XV puhul
+ Description[fy]=(standert) Foarkomme fan ôfpakke fan toetseboerdfokus foar XV
+ Description[he]=(ברירת מחדל) אל תאפשר מניעת גניבת התמקדות עבור XV
+ Description[it]=(Predefinita) Disabilita la prevenzione della cattura del fuoco per XV
+--- a/kwin/workspace.cpp
++++ b/kwin/workspace.cpp
+@@ -128,6 +128,7 @@
+     cm_selection( NULL ),
+     compositeRate( 0 ),
+     overlay( None ),
++    overlay_visible( true ),
+     transSlider( NULL ),
+     transButton( NULL )
+     {
+@@ -1140,7 +1141,7 @@
+ 
+ void Workspace::configureWM()
+     {
+-	KToolInvocation::kdeinitExec( "kcmshell", configModules(false) );
++	KToolInvocation::kdeinitExec( "kcmshell4", configModules(false) );
+     }
+ 
+ /*!
+--- a/kdm/kfrontend/sessions/xfce4.desktop
++++ b/kdm/kfrontend/sessions/xfce4.desktop
+@@ -35,7 +35,7 @@
+ Comment[ja]=Cholesterol Free Desktop Environment, version 4, CDE を思わせる、むだのないデスクトップ環境
+ Comment[ka]=CDE-ს მაგვარი უქოლესტერინო სამუშაო დაფა xfce 4
+ Comment[kk]=Cholesterol Free Desktop Environment, 4-нұсқа. CDE-ге ұқсас графикалық орта
+-Comment[km]=បរិស្ថាន​ផ្ទៃ​តុ​ Cholesterol ឥតគិត​ថ្លៃ​កំណែ ៤។ បរិស្ថាន​ផ្ទៃតុ​ដែល​សំអាង​លើ CDE
++Comment[km]=បរិស្ថាន​ផ្ទៃ​តុ​ Cholesterol ឥតគិត​ថ្លៃ​កំណែ ៤ ។ បរិស្ថាន​ផ្ទៃតុ​ដែល​សំអាង​លើ CDE
+ Comment[lt]=Darbatalio aplinka „Be cholesterolio“ , 4 versija. CDE primenanti darbastalio aplinka
+ Comment[lv]=Darbvirsmas vide bez holesterīna, versija 4. Darbavirsmas vide, kas atgādina CDE
+ Comment[mk]=Cholesterol Free Desktop Environment, верзија 4. Работна околина која потсетува на CDE
+--- a/kdm/kfrontend/sessions/ctwm.desktop
++++ b/kdm/kfrontend/sessions/ctwm.desktop
+@@ -34,7 +34,7 @@
+ Comment[ja]=TWM に仮想デスクトップなどを強化した Claude のウィンドウマネージャ
+ Comment[ka]=Claude's Tab Window Manager - TWM-ის გაუმჯობესებული ვერსია
+ Comment[kk]=Claude's Tab Window Manager, TWM-ның жетілдірген нұсқасы.
+-Comment[km]=កម្មវិធី​គ្រប់គ្រង​ផ្ទាំង​បង្អួច​របស់ Claude TWM ដែលបាន​​ធ្វើ​ឲ្យ​ប្រសើរ​ដោយ​អេក្រង់​និមិត្ត​ជាដើម ។ល។
++Comment[km]=កម្មវិធី​គ្រប់គ្រង​ផ្ទាំង​បង្អួច​របស់ Claude TWM ដែល​បាន​​ធ្វើ​ឲ្យ​ប្រសើរ​ដោយ​អេក្រង់​និមិត្ត​ជា​ដើម ។ល។
+ Comment[lt]=Claude kortelių langų tvarkyklė, TWM praplėsta virtualių ekranų palaikymu ir t.t.
+ Comment[mk]=Claude's Tab Window Manager, TWM подобрен менаџер со виртуелни екрани итн.
+ Comment[nb]=Claude's Tab Window Manager, TWM forbedret med virtuelle skrivebord,osv.
+--- a/kdm/kfrontend/sessions/ude.desktop
++++ b/kdm/kfrontend/sessions/ude.desktop
+@@ -19,7 +19,7 @@
+ Comment[el]=Το περιβάλλον επιφάνειας εργασίας του UNIX
+ Comment[eo]=La Uniksa Labortablo Ĉirkauaĵo
+ Comment[es]=El UNIX Desktop Environment
+-Comment[et]=UNIXi töölaua keskkond
++Comment[et]=UNIX-i töölaua keskkond
+ Comment[eu]=UNIX mahaigain ingurunea
+ Comment[fa]=محیط رومیزی یونیکس
+ Comment[fi]=UNIX-työpöytäympäristö
+--- a/kdm/kfrontend/sessions/qvwm.desktop
++++ b/kdm/kfrontend/sessions/qvwm.desktop
+@@ -36,7 +36,7 @@
+ Comment[ja]=Windows95 風のウィンドウマネージャ
+ Comment[ka]=ფანჯრის მენეჯერი Windows 95-ს სტილში
+ Comment[kk]=Windows 95 секілді терезе менеджері
+-Comment[km]=កម្មវិធី​គ្រប់គ្រង​បង្អួច​ស្រដៀង Windows 95
++Comment[km]=កម្មវិធី​គ្រប់គ្រង​បង្អួច​ស្រដៀងនឹង Windows 95
+ Comment[lt]=Langų tvarkyklė, primenanti Windows 95
+ Comment[lv]=Windows 95 līdzīgs logu menedžeris
+ Comment[mk]=Менаџер на прозорци со изглед на Windows 95
+--- a/kdm/kfrontend/sessions/asclassic.desktop
++++ b/kdm/kfrontend/sessions/asclassic.desktop
+@@ -39,7 +39,7 @@
+ Comment[ja]=AfterStep クラシック, AfterStep v1.1 ベースのウィンドウマネージャ
+ Comment[ka]=AfterStep Classic, ფანჯრის მენეჯერი AfterStep v1.1 -ის ბაზაზე
+ Comment[kk]=AfterStep v1.1 негіздеген AfterStep Classic терезе менеджері
+-Comment[km]=AfterStep បុរាណ, កម្មវិធី​គ្រប់គ្រង​បង្អួច​ដែល​ផ្អែក​លើ AfterStep v1.1
++Comment[km]=AfterStep បុរាណ កម្មវិធី​គ្រប់គ្រង​បង្អួច​ដែល​ផ្អែក​លើ AfterStep v1.1
+ Comment[ko]=AfterStrp 1.1 기반 창 관리자
+ Comment[lt]=AfterStep Classic, langų tvarkyklė, paremta AfterStep v1.1
+ Comment[lv]=Klasiskais Afterstep, logu menedžeris bāzēts uz AfterStem v1.1
+--- a/kdm/kfrontend/sessions/amiwm.desktop
++++ b/kdm/kfrontend/sessions/amiwm.desktop
+@@ -35,7 +35,7 @@
+ Comment[ja]=Amiga に似たウィンドウマネージャ
+ Comment[ka]=ფანჯრის მენეჯერი Amiga-ს სტილში
+ Comment[kk]=Amiga секілді терезе менеджері
+-Comment[km]=កម្មវិធី​គ្រប់គ្រប់​បង្អួច​ស្រដៀង Amiga
++Comment[km]=កម្មវិធី​គ្រប់គ្រប់​បង្អួច​ស្រដៀង​នឹង Amiga
+ Comment[ko]=Amiga를 닮은 창 관리자
+ Comment[lt]=Langų tvarkyklė, panaši į Amiga
+ Comment[lv]=Amiga izskata logu menedžeris
+--- a/kdm/kfrontend/sessions/cde.desktop
++++ b/kdm/kfrontend/sessions/cde.desktop
+@@ -33,7 +33,7 @@
+ Comment[ja]=Common Desktop Environment,プロプライエタリな業界標準のデスクトップ環境
+ Comment[ka]=Common Desktop Environment, UNIX -ის სამუშაო სფეროს სამრეწვლო სტანდარტი
+ Comment[kk]=Common Desktop Environment - UNIX жұмыс ортаның өнеркәсіп стандарты
+-Comment[km]=បរិស្ថាន​ផ្ទៃតុ​ធម្មតា,បរិស្ថាន​ផ្ទៃតុ​ស្តង់ដារ​ឧស្សាហ៍កម្ម​កម្មវិធី​មានកម្មសិទ្ធិ
++Comment[km]=បរិស្ថាន​ផ្ទៃតុ​ធម្មតា បរិស្ថាន​ផ្ទៃតុ​ស្តង់ដារ​ឧស្សាហ៍កម្ម​កម្មវិធី​មាន​កម្មសិទ្ធិ
+ Comment[lt]=Common Desktop Environment, nuosavybinių sistemų standartinė darbastalio tvarkyklė
+ Comment[mk]=Common Desktop Environment, сопственичка индустриски стандардна работна околина
+ Comment[ms]=Persekitaran Desktop Biasa, persekitaran desktop standard industri proprietari
+--- a/kdm/kfrontend/sessions/evilwm.desktop
++++ b/kdm/kfrontend/sessions/evilwm.desktop
+@@ -35,7 +35,7 @@
+ Comment[ja]=AEWM ベースの小さなウィンドウマネージャ
+ Comment[ka]=მინიმალისტური ფანჯრის მენეჯერი AEWM-ის ბაზაზე
+ Comment[kk]=AEWM-негіздеген шағын терезе менеджері
+-Comment[km]=កម្មវិធី​គ្រប់គ្រង​បង្អួច​លក្ខណៈ​ពិសេស​តិចតួច ដែល​​មាន​មូលដ្ឋាន​លើ AEWM
++Comment[km]=កម្មវិធី​គ្រប់គ្រង​បង្អួច​លក្ខណៈ​ពិសេស​តិច ដែល​​មាន​មូលដ្ឋាន​លើ AEWM
+ Comment[lt]=Minimalistinė langų tvarkyklė, paremta AEWM
+ Comment[lv]=Minimālistisks logu menedžeris bāzēts uz AEWM
+ Comment[mk]=Минималистички менаџер на прозорци базиран на AEWM
+--- a/ksysguard/ksysguardd/NetBSD/loadavg.c
++++ b/ksysguard/ksysguardd/NetBSD/loadavg.c
+@@ -37,17 +37,24 @@
+ 	if (updateLoadAvg() < 0)
+ 		return;
+ 
+-	registerMonitor("cpu/loadavg1", "float", printLoadAvg1,
+-					printLoadAvg1Info, sm);
+-	registerMonitor("cpu/loadavg5", "float", printLoadAvg5,
+-					printLoadAvg5Info, sm);
+-	registerMonitor("cpu/loadavg15", "float", printLoadAvg15,
+-					printLoadAvg15Info, sm);
++	registerMonitor("cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm);
++	registerMonitor("cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm);
++	registerMonitor("cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm);
++	
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm);
++	registerLegacyMonitor("cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm);
++	registerLegacyMonitor("cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm);
+ }
+ 
+ void
+ exitLoadAvg(void)
+ {
++	removeMonitor("cpu/system/loadavg1");
++	removeMonitor("cpu/system/loadavg5");
++	removeMonitor("cpu/system/loadavg15");
++	
++	/* These were registered as legacy monitors */
+ 	removeMonitor("cpu/loadavg1");
+ 	removeMonitor("cpu/loadavg5");
+ 	removeMonitor("cpu/loadavg15");
+--- a/ksysguard/ksysguardd/NetBSD/CPU.c
++++ b/ksysguard/ksysguardd/NetBSD/CPU.c
+@@ -53,14 +53,17 @@
+ initCpuInfo(struct SensorModul* sm)
+ {
+ 	/* Total CPU load */
+-	registerMonitor("cpu/system/user", "integer", printCPUUser,
+-			printCPUUserInfo, sm);
+-	registerMonitor("cpu/system/nice", "integer", printCPUNice,
+-			printCPUNiceInfo, sm);
+-	registerMonitor("cpu/system/sys", "integer", printCPUSys,
+-			printCPUSysInfo, sm);
+-	registerMonitor("cpu/system/idle", "integer", printCPUIdle,
+-			printCPUIdleInfo, sm);
++	registerMonitor("cpu/system/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerMonitor("cpu/system/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerMonitor("cpu/system/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerMonitor("cpu/system/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
++	
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerLegacyMonitor("cpu/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerLegacyMonitor("cpu/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerLegacyMonitor("cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
++	
+ 	kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open");
+ 	kvm_nlist(kd, my_nlist);
+ 	cp_time_offset = my_nlist[0].n_value;
+@@ -71,6 +74,18 @@
+ void
+ exitCpuInfo(void)
+ {
++	removeMonitor("cpu/system/user");
++	removeMonitor("cpu/system/nice");
++	removeMonitor("cpu/system/sys");
++	removeMonitor("cpu/system/idle");
++
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/user");
++	removeMonitor("cpu/nice");
++	removeMonitor("cpu/sys");
++	removeMonitor("cpu/idle");
++
++
+ 	kvm_close(kd);
+ }
+ 
+--- a/ksysguard/ksysguardd/Tru64/LoadAvg.c
++++ b/ksysguard/ksysguardd/Tru64/LoadAvg.c
+@@ -42,16 +42,28 @@
+ 
+ void initLoadAvg( struct SensorModul* sm ) {
+ #ifdef HAVE_KSTAT
+-	registerMonitor( "cpu/loadavg1", "float",
+-					printLoadAvg1, printLoadAvg1Info, sm );
+-	registerMonitor( "cpu/loadavg5", "float",
+-					printLoadAvg5, printLoadAvg5Info, sm );
+-	registerMonitor( "cpu/loadavg15", "float",
+-					printLoadAvg15, printLoadAvg15Info, sm );
++	registerMonitor( "cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerMonitor( "cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerMonitor( "cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
++	
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
+ #endif
+ }
+ 
+ void exitLoadAvg( void ) {
++#ifdef HAVE_KSTAT
++	removeMonitor("cpu/system/loadavg1");
++	removeMonitor("cpu/system/loadavg5");
++	removeMonitor("cpu/system/loadavg15");
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/loadavg1");
++	removeMonitor("cpu/loadavg5");
++	removeMonitor("cpu/loadavg15");
++#endif
+ }
+ 
+ int updateLoadAvg( void ) {
+--- a/ksysguard/ksysguardd/OpenBSD/cpu.c
++++ b/ksysguard/ksysguardd/OpenBSD/cpu.c
+@@ -44,16 +44,17 @@
+ initCpuInfo(struct SensorModul* sm)
+ {
+ 	/* Total CPU load */
+-	registerMonitor("cpu/system/user", "integer", printCPUUser,
+-			printCPUUserInfo, sm);
+-	registerMonitor("cpu/system/nice", "integer", printCPUNice,
+-			printCPUNiceInfo, sm);
+-	registerMonitor("cpu/system/sys", "integer", printCPUSys,
+-			printCPUSysInfo, sm);
+-	registerMonitor("cpu/system/idle", "integer", printCPUIdle,
+-			printCPUIdleInfo, sm);
+-	registerMonitor("cpu/interrupt", "integer", printCPUInterrupt,
+-			printCPUInterruptInfo, sm);
++	registerMonitor("cpu/system/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerMonitor("cpu/system/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerMonitor("cpu/system/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerMonitor("cpu/system/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
++	registerMonitor("cpu/interrupt", "integer", printCPUInterrupt, printCPUInterruptInfo, sm);
++
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerLegacyMonitor("cpu/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerLegacyMonitor("cpu/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerLegacyMonitor("cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
+ 
+ 	updateCpuInfo();
+ }
+@@ -61,6 +62,17 @@
+ void
+ exitCpuInfo(void)
+ {
++	removeMonitor("cpu/system/user");
++	removeMonitor("cpu/system/nice");
++	removeMonitor("cpu/system/sys");
++	removeMonitor("cpu/system/idle");
++	removeMonitor("cpu/interrupt");
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/user");
++	removeMonitor("cpu/nice");
++	removeMonitor("cpu/sys");
++	removeMonitor("cpu/idle");
+ }
+ 
+ int
+--- a/ksysguard/ksysguardd/Linux/stat.c
++++ b/ksysguard/ksysguardd/Linux/stat.c
+@@ -297,15 +297,15 @@
+ 			
+ 			/* Disk device has disappeared. We have to remove it from
+ 			* the list and unregister the monitors. */
+-			sprintf( sensorName, "disk/%s_(%d:%d)26/total", ptr->devname, ptr->major, ptr->minor );
++			sprintf( sensorName, "disk/%s_(%d:%d)24/total", ptr->devname, ptr->major, ptr->minor );
+ 			removeMonitor( sensorName );
+-			sprintf( sensorName, "disk/%s_(%d:%d)26/rio", ptr->devname, ptr->major, ptr->minor );
++			sprintf( sensorName, "disk/%s_(%d:%d)24/rio", ptr->devname, ptr->major, ptr->minor );
+ 			removeMonitor( sensorName );
+-			sprintf( sensorName, "disk/%s_(%d:%d)26/wio", ptr->devname, ptr->major, ptr->minor );
++			sprintf( sensorName, "disk/%s_(%d:%d)24/wio", ptr->devname, ptr->major, ptr->minor );
+ 			removeMonitor( sensorName );
+-			sprintf( sensorName, "disk/%s_(%d:%d)26/rblk", ptr->devname, ptr->major, ptr->minor );
++			sprintf( sensorName, "disk/%s_(%d:%d)24/rblk", ptr->devname, ptr->major, ptr->minor );
+ 			removeMonitor( sensorName );
+-			sprintf( sensorName, "disk/%s_(%d:%d)26/wblk", ptr->devname, ptr->major, ptr->minor );
++			sprintf( sensorName, "disk/%s_(%d:%d)24/wblk", ptr->devname, ptr->major, ptr->minor );
+ 			removeMonitor( sensorName );
+ 			if ( last ) {
+ 				last->next = ptr->next;
+@@ -492,6 +492,14 @@
+ 			registerMonitor( "cpu/system/TotalLoad", "float", printCPUTotalLoad, printCPUTotalLoadInfo, StatSM );
+ 			registerMonitor( "cpu/system/idle", "float", printCPUIdle, printCPUIdleInfo, StatSM );
+ 			registerMonitor( "cpu/system/wait", "float", printCPUWait, printCPUWaitInfo, StatSM );
++
++			/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++			registerLegacyMonitor( "cpu/user", "float", printCPUUser, printCPUUserInfo, StatSM );
++			registerLegacyMonitor( "cpu/nice", "float", printCPUNice, printCPUNiceInfo, StatSM );
++			registerLegacyMonitor( "cpu/sys", "float", printCPUSys, printCPUSysInfo, StatSM );
++			registerLegacyMonitor( "cpu/TotalLoad", "float", printCPUTotalLoad, printCPUTotalLoadInfo, StatSM );
++			registerLegacyMonitor( "cpu/idle", "float", printCPUIdle, printCPUIdleInfo, StatSM );
++			registerLegacyMonitor( "cpu/wait", "float", printCPUWait, printCPUWaitInfo, StatSM );
+ 		}
+ 		else if ( strncmp( "cpu", tag, 3 ) == 0 ) {
+ 			char cmdName[ 24 ];
+@@ -608,6 +616,19 @@
+ 	
+ 	free( Intr );
+ 	Intr = 0;
++	
++	removeMonitor("cpu/system/user");
++	removeMonitor("cpu/system/nice");
++	removeMonitor("cpu/system/sys");
++	removeMonitor("cpu/system/idle");
++	
++	/* Todo: Dynamically registered monitors (per cpu, per disk) are not removed yet) */
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/user");
++	removeMonitor("cpu/nice");
++	removeMonitor("cpu/sys");
++	removeMonitor("cpu/idle");
+ }
+ 	
+ int updateStat( void ) {
+@@ -1006,7 +1027,7 @@
+ 	char name[ 17 ];
+ 	DiskIOInfo* ptr;
+ 	
+-	sscanf( cmd, "disk/%[^_]_(%d:%d)26/%16s", devname, &major, &minor, name );
++	sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s", devname, &major, &minor, name );
+ 	
+ 	if ( Dirty )
+ 		process24Stat();
+@@ -1045,7 +1066,7 @@
+ 	char name[ 17 ];
+ 	DiskIOInfo* ptr = DiskIO;
+ 	
+-	sscanf( cmd, "disk/%[^_]_(%d:%d)26/%16s", devname, &major, &minor, name );
++	sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s", devname, &major, &minor, name );
+ 	
+ 	while ( ptr && ( ptr->major != major || ptr->minor != minor ) )
+ 		ptr = ptr->next;
+--- a/ksysguard/ksysguardd/Linux/acpi.c
++++ b/ksysguard/ksysguardd/Linux/acpi.c
+@@ -336,6 +336,8 @@
+ 
+ void printThermalZoneTemperatureInfo(const char *cmd)
+ {
++	(void)cmd;
++
+ 	fprintf(CurrentClient, "Current temperature\t0\t0\tC\n");
+ }
+ 
+@@ -434,7 +436,7 @@
+ 
+ void printFanStateInfo(const char *cmd)
+ {
++	(void)cmd;
++
+ 	fprintf(CurrentClient, "Fan status\t0\t1\tboolean\n");
+ }
+-
+-
+--- a/ksysguard/ksysguardd/Linux/loadavg.c
++++ b/ksysguard/ksysguardd/Linux/loadavg.c
+@@ -57,6 +57,11 @@
+   registerMonitor( "cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
+   registerMonitor( "cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
+   registerMonitor( "cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
++
++  /* Register some legacy monitors. These will be hidden from the module list. */
++  registerLegacyMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++  registerLegacyMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++  registerLegacyMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
+ }
+ 
+ void exitLoadAvg( void )
+--- a/ksysguard/ksysguardd/Linux/diskstats.c
++++ b/ksysguard/ksysguardd/Linux/diskstats.c
+@@ -80,12 +80,7 @@
+ static struct SensorModul* StatSM;
+ 
+ static DiskLoadInfo* DiskLoad = 0;
+-static unsigned DiskCount = 0;
+ static DiskIOInfo* DiskIO = 0;
+-static unsigned long PageIn = 0;
+-static unsigned long OldPageIn = 0;
+-static unsigned long PageOut = 0;
+-static unsigned long OldPageOut = 0;
+ 
+ static char IOStatBuf[ DISKSTATSBUFSIZE ];	/* Buffer for /proc/diskstats */
+ static int Dirty = 0;
+--- a/ksysguard/ksysguardd/Linux/ProcessList.c
++++ b/ksysguard/ksysguardd/Linux/ProcessList.c
+@@ -29,6 +29,10 @@
+ #include <sys/resource.h>
+ #include <time.h>
+ #include <unistd.h>
++#include <sys/ptrace.h>
++#include <asm/unistd.h>
++
++
+ 
+ #include "../../gui/SignalIDs.h"
+ #include "Command.h"
+@@ -42,6 +46,58 @@
+ #define TAGSIZE 32
+ #define KDEINITLEN sizeof( "kdeinit: " )
+ 
++/* For ionice */
++extern int sys_ioprio_set(int, int, int);
++extern int sys_ioprio_get(int, int);
++
++#define HAVE_IONICE
++
++/* Check if this system has ionice */
++#if !defined(SYS_ioprio_get) || !defined(SYS_ioprio_set)
++/* All new kernels have SYS_ioprio_get and _set defined, but for the few that do not, here are the definitions */
++#if defined(__i386__)
++#define __NR_ioprio_set         289
++#define __NR_ioprio_get         290
++#elif defined(__ppc__) || defined(__powerpc__)
++#define __NR_ioprio_set         273
++#define __NR_ioprio_get         274
++#elif defined(__x86_64__)
++#define __NR_ioprio_set         251
++#define __NR_ioprio_get         252
++#elif defined(__ia64__)
++#define __NR_ioprio_set         1274
++#define __NR_ioprio_get         1275
++#else
++#ifdef __GNUC__
++#warning "This architecture does not support IONICE.  Disabling ionice feature."
++#endif
++#undef HAVE_IONICE
++#endif
++/* Map these to SYS_ioprio_get */
++#define SYS_ioprio_get                __NR_ioprio_get
++#define SYS_ioprio_set                __NR_ioprio_set
++
++#endif /* !SYS_ioprio_get */
++
++/* Set up ionice functions */
++#ifdef HAVE_IONICE
++#define IOPRIO_WHO_PROCESS 1
++#define IOPRIO_CLASS_SHIFT 13
++
++/* Expose the kernel calls to usespace via syscall
++ * See man ioprio_set  and man ioprio_get   for information on these functions */
++static int ioprio_set(int which, int who, int ioprio)
++{
++  return syscall(SYS_ioprio_set, which, who, ioprio);
++}
++ 
++static int ioprio_get(int which, int who)
++{
++  return syscall(SYS_ioprio_get, which, who);
++}
++#endif
++
++
+ #ifndef bool
+ #define bool char
+ #define true 1
+@@ -57,22 +113,22 @@
+ 
+ typedef struct {
+ 
+-  /* The parent process ID */
++  /** The parent process ID */
+   pid_t ppid;
+ 
+-  /* The real user ID */
++  /** The real user ID */
+   uid_t uid;
+ 
+-  /* The real group ID */
++  /** The real group ID */
+   gid_t gid;
+ 
+-  /* The process ID of any application that is debugging this one. 0 if none */
++  /** The process ID of any application that is debugging this one. 0 if none */
+   pid_t tracerpid;
+ 
+-  /* A character description of the process status */
++  /** A character description of the process status */
+   char status[ 16 ];
+ 
+-  /* The tty the process owns */
++  /** The tty the process owns */
+   char tty[10];
+ 
+   /**
+@@ -81,9 +137,13 @@
+    */
+   int niceLevel;
+ 
+-  /* The scheduling priority. */
++  /** The scheduling priority. */
+   int priority;
+ 
++  /** The i/o scheduling class and priority. */
++  int ioPriorityClass;  /** 0 for none, 1 for realtime, 2 for best-effort, 3 for idle.  -1 for error. */
++  int ioPriority;       /** Between 0 and 7.  0 is highest priority, 7 is lowest.  -1 for error. */
++
+   /**
+     The total amount of virtual memory space that this process uses. This includes shared and
+     swapped memory, plus graphics memory and mmap'ed files and so on.
+@@ -102,8 +162,8 @@
+   
+   unsigned long vmRss;
+ 
+-  /* The amount of physical memory that is used by this process, not including any memory used by any shared libraries.
+-   * This is in KiB */
++  /** The amount of physical memory that is used by this process, not including any memory used by any shared libraries.
++   *  This is in KiB */
+   unsigned long vmURss;
+ 
+   /**
+@@ -124,17 +184,20 @@
+ 
+   /* NOTE:  To get the user/system percentage, record the userTime and sysTime from between calls, then use the difference divided by the difference in time measure in 100th's of a second */
+ 
+-  /* The name of the process */
++  /** The name of the process */
+   char name[ 64 ];
+ 
+-  /* The command used to start the process */
++  /** The command used to start the process */
+   char cmdline[ 256 ];
+ 
+-  /* The login name of the user that owns this process */
++  /** The login name of the user that owns this process */
+   char userName[ 32 ];
+ 
+ } ProcessInfo;
+ 
++void getIOnice( int pid, ProcessInfo *ps );
++void ioniceProcess( const char* cmd );
++
+ static unsigned ProcessCount;
+ static DIR* procDir;
+ static void validateStr( char* str )
+@@ -311,6 +374,9 @@
+   strncpy( ps->userName, uName, sizeof( ps->userName ) - 1 );
+   ps->userName[ sizeof( ps->userName ) - 1 ] = '\0';
+   validateStr( ps->userName );
++
++  getIOnice(pid, ps);
++
+   return true;
+ }
+ 
+@@ -327,11 +393,11 @@
+       long pid;
+       pid = atol( entry->d_name );
+       if(getProcess( pid, &ps ))
+-        fprintf( CurrentClient, "%s\t%ld\t%ld\t%lu\t%lu\t%s\t%lu\t%lu\t%d\t%lu\t%lu\t%lu\t%s\t%ld\t%s\t%s\n",
++        fprintf( CurrentClient, "%s\t%ld\t%ld\t%lu\t%lu\t%s\t%lu\t%lu\t%d\t%lu\t%lu\t%lu\t%s\t%ld\t%s\t%s\t%d\t%d\n",
+ 	     ps.name, pid, (long)ps.ppid,
+              (long)ps.uid, (long)ps.gid, ps.status, ps.userTime,
+              ps.sysTime, ps.niceLevel, ps.vmSize, ps.vmRss, ps.vmURss,
+-             ps.userName, (long)ps.tracerpid, ps.tty, ps.cmdline
++             ps.userName, (long)ps.tracerpid, ps.tty, ps.cmdline, ps.ioPriorityClass, ps.ioPriority
+ 	     );
+     }
+   }
+@@ -339,6 +405,71 @@
+   return;
+ }
+ 
++void getIOnice( int pid, ProcessInfo *ps ) {
++#ifdef HAVE_IONICE
++  int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);  /* Returns from 0 to 7 for the iopriority, and -1 if there's an error */
++  if(ioprio == -1) {
++	  ps->ioPriority = -1;
++	  ps->ioPriorityClass = -1;
++	  return; /* Error. Just give up. */
++  }
++  ps->ioPriority = ioprio & 0xff;  /* Bottom few bits are the priority */
++  ps->ioPriorityClass = ioprio >> IOPRIO_CLASS_SHIFT; /* Top few bits are the class */
++#else
++  return;  /* Do nothing, if we do not support this architecture */
++#endif
++}
++
++void ioniceProcess( const char* cmd )
++{
++  /* Re-ionice's a process. cmd is a string containing "ionice <pid> <class> <priority>" 
++   * where c = 1 for real time, 2 for best-effort, 3 for idle
++   * and priority is between 0 and 7, 0 being the highest priority, and ignored if c=3
++   *
++   * For more information, see:  man ionice
++   */
++  int pid = 0;
++  int class = 2;
++  int priority = 0;
++  if(sscanf( cmd, "%*s %d %d %d", &pid, &class, &priority ) < 2) {
++    fprintf( CurrentClient, "4\t%d\n", pid ); /* 4 means error in values */
++    return; /* Error with input. */
++  }
++
++#ifdef HAVE_IONICE
++  if(pid < 1 || class < 0 || class > 3) {
++    fprintf( CurrentClient, "4\t%d\n", pid ); /* 4 means error in values */
++    return; /* Error with input. Just ignore. */
++  }
++
++  if (ioprio_set(IOPRIO_WHO_PROCESS, pid, priority | class << IOPRIO_CLASS_SHIFT) == -1) {
++    switch ( errno ) {
++      case EINVAL:
++        fprintf( CurrentClient, "4\t%d\n", pid );
++        break;
++      case ESRCH:
++        fprintf( CurrentClient, "3\t%d\n", pid );
++        break;
++      case EPERM:
++        fprintf( CurrentClient, "2\t%d\n", pid );
++        break;
++      default: /* unknown error */
++        fprintf( CurrentClient, "1\t%d\n", pid );
++        break;
++    }
++  } else {
++    /* Successful */
++    fprintf( CurrentClient, "0\t%d\n", pid );
++  }
++  return;
++#else
++  /** should never reach here */
++  fprintf( CurrentClient, "1\t%d\n", pid );
++  return;
++#endif
++}
++ 
++
+ /*
+ ================================ public part =================================
+ */
+@@ -353,6 +484,9 @@
+   if ( !RunAsDaemon ) {
+     registerCommand( "kill", killProcess );
+     registerCommand( "setpriority", setPriority );
++#ifdef HAVE_IONICE
++    registerCommand( "ionice", ioniceProcess );
++#endif
+   }
+ 
+ #ifdef HAVE_XRES
+@@ -361,6 +495,7 @@
+     registerMonitor( "xres", "table", printXresList, printXresListInfo, sm);
+   }
+ #endif
++
+   /*open /proc now in advance*/
+   /* read in current process list via the /proc file system entry */
+   if ( ( procDir = opendir( "/proc" ) ) == NULL ) {
+@@ -407,8 +542,8 @@
+ {
+   (void)cmd;
+   fprintf( CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser Time\tSystem Time\tNice\tVmSize"
+-                          "\tVmRss\tVmURss\tLogin\tTracerPID\tTTY\tCommand\n" );
+-  fprintf( CurrentClient, "s\td\td\td\td\tS\td\td\td\tD\tD\tD\ts\td\ts\ts\n" );
++                          "\tVmRss\tVmURss\tLogin\tTracerPID\tTTY\tCommand\tIO Priority Class\tIO Priority\n" );
++  fprintf( CurrentClient, "s\td\td\td\td\tS\td\td\td\tD\tD\tD\ts\td\ts\ts\td\td\n" );
+ }
+ 
+ void printProcessCount( const char* cmd )
+@@ -433,6 +568,7 @@
+ 
+ void killProcess( const char* cmd )
+ {
++  /* Sends a signal (not neccessarily kill!) to the process.  cmd is a string containing "kill <pid> <signal>" */
+   int sig, pid;
+ 
+   sscanf( cmd, "%*s %d %d", &pid, &sig );
+--- a/ksysguard/ksysguardd/Linux/softraid.c
++++ b/ksysguard/ksysguardd/Linux/softraid.c
+@@ -214,7 +214,11 @@
+ 	char* mdadmStatBufP;
+ 
+ 	/* Create a pipe */
+-	pipe(fd);
++	if(pipe(fd) == -1)
++	{
++		perror("Could not create a pipe to launch mdadm.");
++		exit(1);
++	}
+ 
+ 	/* Fork */
+ 	if((ChildPID = fork()) == -1)
+--- a/ksysguard/ksysguardd/Linux/netstat.c
++++ b/ksysguard/ksysguardd/Linux/netstat.c
+@@ -271,7 +271,7 @@
+ 	char buffer[1024];
+ 	uint local_addr, local_port;
+ 	uint remote_addr, remote_port;
+-	int uid, i;
++	int uid;
+ 	uint state;
+ 	SocketInfo *socket_info;
+ 
+@@ -367,7 +367,7 @@
+ 	FILE *file;
+ 	char buffer[1024];
+ 	char path[256];
+-	int ref_count, type, state, inode, i;
++	int ref_count, type, state, inode;
+ 	UnixInfo *unix_info;
+ 
+ 	if ((file = fopen("/proc/net/unix", "r")) == NULL) {
+--- a/ksysguard/ksysguardd/Command.c
++++ b/ksysguard/ksysguardd/Command.c
+@@ -36,6 +36,7 @@
+   cmdExecutor ex;
+   char* type;
+   int isMonitor;
++  int isLegacy;
+   struct SensorModul* sm;
+ } Command;
+ 
+@@ -139,8 +140,8 @@
+   ReconfigureFlag = 1;
+ }
+ 
+-void registerMonitor( const char* command, const char* type, cmdExecutor ex,
+-                      cmdExecutor iq, struct SensorModul* sm )
++void registerAnyMonitor( const char* command, const char* type, cmdExecutor ex,
++                      cmdExecutor iq, struct SensorModul* sm, int isLegacy )
+ {
+   /* Monitors are similar to regular commands except that every monitor
+    * registers two commands. The first is the value request command and
+@@ -156,6 +157,7 @@
+   cmd->type = (char*)malloc( strlen( type ) + 1 );
+   strcpy( cmd->type, type );
+   cmd->isMonitor = 1;
++  cmd->isLegacy = isLegacy;
+   cmd->sm = sm;
+   push_ctnr( CommandList, cmd );
+ 
+@@ -171,6 +173,22 @@
+   push_ctnr( CommandList, cmd );
+ }
+ 
++void registerMonitor( const char* command, const char* type, cmdExecutor ex,
++                      cmdExecutor iq, struct SensorModul* sm )
++{
++  int legacyFlag = 0;
++
++  registerAnyMonitor( command, type, ex, iq, sm, legacyFlag );
++}
++
++void registerLegacyMonitor( const char* command, const char* type, cmdExecutor ex,
++                      cmdExecutor iq, struct SensorModul* sm )
++{
++  int legacyFlag = 1;
++
++  registerAnyMonitor( command, type, ex, iq, sm, legacyFlag );
++}
++
+ void removeMonitor( const char* command )
+ {
+   char* buf;
+@@ -229,7 +247,7 @@
+   (void)c;
+ 
+   for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) {
+-    if ( cmd->isMonitor )
++    if ( cmd->isMonitor && !cmd->isLegacy )
+       fprintf(CurrentClient, "%s\t%s\n", cmd->command, cmd->type);
+   }
+ 
+--- a/ksysguard/ksysguardd/ksysguardd.c
++++ b/ksysguard/ksysguardd/ksysguardd.c
+@@ -154,7 +154,11 @@
+     fseek( file, 0, SEEK_SET );
+     fprintf( file, "%d\n", getpid() );
+     fflush( file );
+-    ftruncate( fileno( file ), ftell( file ) );
++    if (ftruncate( fileno( file ), ftell( file ) ) == -1) {
++      log_error( "Cannot set size of lockfile '%s'", LockFile );
++      fprintf( stderr, "Cannot set size of lockfile '%s'\n", LockFile );
++      return -2;
++    }
+   } else {
+     log_error( "Cannot create lockfile '%s'", LockFile );
+     fprintf( stderr, "Cannot create lockfile '%s'\n", LockFile );
+--- a/ksysguard/ksysguardd/Command.h
++++ b/ksysguard/ksysguardd/Command.h
+@@ -78,10 +78,37 @@
+   @ref sm is a parameter to the sensor module object that is passed by
+   the initXXX method.
+  */
++void registerAnyMonitor( const char* monitor, const char* type, cmdExecutor ex,
++                      cmdExecutor iq, struct SensorModul* sm, int isLegacy );
++
++/**
++  Use this function to add a new monitior with the name @ref monitor
++  from the type @ref type.
++  It will be marked as non-legacy.
++  @ref ex is a pointer to the function that is called to get a value
++  and @ref iq is a pointer to the function that returns information
++  about this monitor.
++  @ref sm is a parameter to the sensor module object that is passed by
++  the initXXX method.
++ */
+ void registerMonitor( const char* monitor, const char* type, cmdExecutor ex,
+                       cmdExecutor iq, struct SensorModul* sm );
+ 
+ /**
++  Use this function to add a new monitior with the name @ref monitor
++  from the type @ref type. This monitor will be flagged as legacy,
++  which will forbid it from being listed by the 'modules' command.
++  The command will continue to function normally otherwise.
++  @ref ex is a pointer to the function that is called to get a value
++  and @ref iq is a pointer to the function that returns information
++  about this monitor.
++  @ref sm is a parameter to the sensor module object that is passed by
++  the initXXX method.
++ */
++void registerLegacyMonitor( const char* monitor, const char* type, cmdExecutor ex,
++                      cmdExecutor iq, struct SensorModul* sm );
++
++/**
+   Use this function to remove the monitior with the name @ref monitor.
+  */
+ void removeMonitor( const char* monitor );
+--- a/ksysguard/ksysguardd/FreeBSD/loadavg.c
++++ b/ksysguard/ksysguardd/FreeBSD/loadavg.c
+@@ -37,17 +37,24 @@
+ 	if (updateLoadAvg() < 0)
+ 		return;
+ 
+-	registerMonitor("cpu/loadavg1", "float", printLoadAvg1,
+-					printLoadAvg1Info, sm);
+-	registerMonitor("cpu/loadavg5", "float", printLoadAvg5,
+-					printLoadAvg5Info, sm);
+-	registerMonitor("cpu/loadavg15", "float", printLoadAvg15,
+-					printLoadAvg15Info, sm);
++	registerMonitor("cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm);
++	registerMonitor("cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm);
++	registerMonitor("cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm);
++
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm);
++	registerLegacyMonitor("cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm);
++	registerLegacyMonitor("cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm);
+ }
+ 
+ void
+ exitLoadAvg(void)
+ {
++	removeMonitor("cpu/system/loadavg1");
++	removeMonitor("cpu/system/loadavg5");
++	removeMonitor("cpu/system/loadavg15");
++
++	/* These were registered as legacy monitors */
+ 	removeMonitor("cpu/loadavg1");
+ 	removeMonitor("cpu/loadavg5");
+ 	removeMonitor("cpu/loadavg15");
+--- a/ksysguard/ksysguardd/FreeBSD/CPU.c
++++ b/ksysguard/ksysguardd/FreeBSD/CPU.c
+@@ -71,14 +71,16 @@
+ initCpuInfo(struct SensorModul* sm)
+ {
+ 	/* Total CPU load */
+-	registerMonitor("cpu/system/user", "integer", printCPUUser,
+-			printCPUUserInfo, sm);
+-	registerMonitor("cpu/system/nice", "integer", printCPUNice,
+-			printCPUNiceInfo, sm);
+-	registerMonitor("cpu/system/sys", "integer", printCPUSys,
+-			printCPUSysInfo, sm);
+-	registerMonitor("cpu/system/idle", "integer", printCPUIdle,
+-			printCPUIdleInfo, sm);
++	registerMonitor("cpu/system/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerMonitor("cpu/system/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerMonitor("cpu/system/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerMonitor("cpu/system/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
++
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerLegacyMonitor("cpu/nice", "integer", printCPUNice, printCPUNiceInfo, sm);
++	registerLegacyMonitor("cpu/sys", "integer", printCPUSys, printCPUSysInfo, sm);
++	registerLegacyMonitor("cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
+ 
+ 	updateCpuInfo();
+ }
+@@ -86,6 +88,16 @@
+ void
+ exitCpuInfo(void)
+ {
++	removeMonitor("cpu/system/user");
++	removeMonitor("cpu/system/nice");
++	removeMonitor("cpu/system/sys");
++	removeMonitor("cpu/system/idle");
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/user");
++	removeMonitor("cpu/nice");
++	removeMonitor("cpu/sys");
++	removeMonitor("cpu/idle");
+ }
+ 
+ int
+--- a/ksysguard/ksysguardd/Irix/cpu.c
++++ b/ksysguard/ksysguardd/Irix/cpu.c
+@@ -70,12 +70,14 @@
+ 	g_ci = malloc(sizeof(struct cpu_info) * nCPUs);
+ 	memset(g_ci,0,sizeof(struct cpu_info) * nCPUs);
+ 
+-	registerMonitor("cpu/system/user", "integer", printCPUUser,
+-		printCPUUserInfo, sm);
+-	registerMonitor("cpu/system/sys",  "integer", printCPUSys,
+-		printCPUSysInfo, sm);
+-	registerMonitor("cpu/system/idle", "integer", printCPUIdle,
+-		printCPUIdleInfo, sm);
++	registerMonitor("cpu/system/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerMonitor("cpu/system/sys",  "integer", printCPUSys, printCPUSysInfo, sm);
++	registerMonitor("cpu/system/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
++	
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor("cpu/user", "integer", printCPUUser, printCPUUserInfo, sm);
++	registerLegacyMonitor("cpu/sys",  "integer", printCPUSys, printCPUSysInfo, sm);
++	registerLegacyMonitor("cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, sm);
+ 
+ 	if (nCPUs > 1) for (i=0;i<nCPUs;i++){
+ 		/* indidividual CPU load */
+@@ -96,6 +98,20 @@
+ void
+ exitCpuInfo(void)
+ {
++	removeMonitor("cpu/system/user");
++	removeMonitor("cpu/system/nice");
++	removeMonitor("cpu/system/sys");
++	removeMonitor("cpu/system/idle");
++	
++	/* Todo: Dynamically registered monitors (per cpu, per disk) are not removed yet) */
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/user");
++	removeMonitor("cpu/nice");
++	removeMonitor("cpu/sys");
++	removeMonitor("cpu/idle");
++	
++
+ 	free(g_ci);
+ }
+ 
+--- a/ksysguard/ksysguardd/Irix/LoadAvg.c
++++ b/ksysguard/ksysguardd/Irix/LoadAvg.c
+@@ -37,15 +37,25 @@
+ double loadavg15 = 0.0;
+ 
+ void initLoadAvg(struct SensorModul* sm ) {
+-	registerMonitor( "cpu/loadavg1", "float",
+-					printLoadAvg1, printLoadAvg1Info, sm );
+-	registerMonitor( "cpu/loadavg5", "float",
+-					printLoadAvg5, printLoadAvg5Info, sm );
+-	registerMonitor( "cpu/loadavg15", "float",
+-					printLoadAvg15, printLoadAvg15Info, sm );
++	registerMonitor( "cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerMonitor( "cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerMonitor( "cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
++
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerLegacyMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerLegacyMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
+ }
+ 
+ void exitLoadAvg( void ) {
++	removeMonitor("cpu/system/loadavg1");
++	removeMonitor("cpu/system/loadavg5");
++	removeMonitor("cpu/system/loadavg15");
++
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/loadavg1");
++	removeMonitor("cpu/loadavg5");
++	removeMonitor("cpu/loadavg15");
+ }
+ 
+ int updateLoadAvg( void ) {
+--- a/ksysguard/ksysguardd/Solaris/LoadAvg.c
++++ b/ksysguard/ksysguardd/Solaris/LoadAvg.c
+@@ -39,16 +39,28 @@
+ 
+ void initLoadAvg( struct SensorModul* sm ) {
+ #ifdef HAVE_KSTAT
+-	registerMonitor( "cpu/loadavg1", "float",
+-					printLoadAvg1, printLoadAvg1Info, sm );
+-	registerMonitor( "cpu/loadavg5", "float",
+-					printLoadAvg5, printLoadAvg5Info, sm );
+-	registerMonitor( "cpu/loadavg15", "float",
+-					printLoadAvg15, printLoadAvg15Info, sm );
++	registerMonitor( "cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerMonitor( "cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerMonitor( "cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
++	
++	/* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
++	registerLegacyMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
++	registerLegacyMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
++	registerLegacyMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
+ #endif
+ }
+ 
+ void exitLoadAvg( void ) {
++#ifdef HAVE_KSTAT
++	removeMonitor("cpu/system/loadavg1");
++	removeMonitor("cpu/system/loadavg5");
++	removeMonitor("cpu/system/loadavg15");
++	
++	/* These were registered as legacy monitors */
++	removeMonitor("cpu/loadavg1");
++	removeMonitor("cpu/loadavg5");
++	removeMonitor("cpu/loadavg15");
++#endif
+ }
+ 
+ int updateLoadAvg( void ) {
+--- a/ksysguard/libksysguard/processcore/process.cpp
++++ b/ksysguard/libksysguard/processcore/process.cpp
+@@ -31,13 +31,36 @@
+ }
+ 
+ QString KSysGuard::Process::niceLevelAsString() const {
++	// Just some rough heuristic to map a number to how nice it is
+ 	if( niceLevel == 0) return i18nc("Process Niceness", "Normal");
+-	if( niceLevel > 15) return i18nc("Process Niceness", "Very low priority");
++	if( niceLevel >= 10) return i18nc("Process Niceness", "Very low priority");
+ 	if( niceLevel > 0) return i18nc("Process Niceness", "Low priority");
+-	if( niceLevel < -1) return i18nc("Process Niceness", "High priority");
+-	if( niceLevel < -15) return i18nc("Process Niceness", "Very high priority");
++	if( niceLevel <= -10) return i18nc("Process Niceness", "Very high priority");
++	if( niceLevel < 0) return i18nc("Process Niceness", "High priority");
+ 	return QString(); //impossible;
+ }
++
++QString KSysGuard::Process::ioniceLevelAsString() const {
++	// Just some rough heuristic to map a number to how nice it is
++	if( ioniceLevel == 4) return i18nc("Process Niceness", "Normal");
++	if( ioniceLevel >= 6) return i18nc("Process Niceness", "Very low priority");
++	if( ioniceLevel > 4) return i18nc("Process Niceness", "Low priority");
++	if( ioniceLevel <= 2) return i18nc("Process Niceness", "Very high priority");
++	if( ioniceLevel < 4) return i18nc("Process Niceness", "High priority");
++	return QString(); //impossible;
++
++}
++
++QString KSysGuard::Process::ioPriorityClassAsString() const {
++	switch( ioPriorityClass ) {
++		case None: return i18nc("Priority Class", "None");
++		case RealTime: return i18nc("Priority Class", "Real Time");
++		case BestEffort: return i18nc("Priority Class", "Best Effort");
++		case Idle: return i18nc("Priority Class", "Idle");
++		default: return i18nc("Priority Class", "Unknown");
++	}
++}
++
+ QString KSysGuard::Process::translatedStatus() const { 
+ 	switch( status ) { 
+ 		case Running: return i18nc("process status", "running");
+@@ -70,5 +93,7 @@
+ 	vmURSS = 0; 
+ 	status=OtherStatus;
+ 	parent = NULL;
++	ioPriorityClass = None;
++	ioniceLevel = -1;
+ }
+ 
+--- a/ksysguard/libksysguard/processcore/processes_freebsd_p.cpp
++++ b/ksysguard/libksysguard/processcore/processes_freebsd_p.cpp
+@@ -33,7 +33,8 @@
+ #include <err.h>
+ #endif
+ #include <signal.h>
+-#include <unistd.h>  
++#include <unistd.h>
++#include <stdlib.h>
+ 
+ 
+ 
+@@ -257,6 +258,14 @@
+     return true;
+ }
+ 
++bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
++    return false; //Not yet supported
++}
++
++bool ProcessesLocal::supportsIoNiceness() {
++    return false;
++}
++
+ long long ProcessesLocal::totalPhysicalMemory() {
+ 
+     size_t Total;
+--- a/ksysguard/libksysguard/processcore/processes_openbsd_p.cpp
++++ b/ksysguard/libksysguard/processcore/processes_openbsd_p.cpp
+@@ -249,6 +249,14 @@
+     return true;
+ }
+ 
++bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
++    return false; //Not yet supported
++}
++
++bool ProcessesLocal::supportsIoNiceness() {
++    return false;
++}
++
+ long long ProcessesLocal::totalPhysicalMemory() {
+ 
+     static int physmem_mib[] = { CTL_HW, HW_PHYSMEM };
+--- a/ksysguard/libksysguard/processcore/processes_remote_p.cpp
++++ b/ksysguard/libksysguard/processcore/processes_remote_p.cpp
+@@ -63,6 +63,14 @@
+     return false;
+ }
+ 
++bool ProcessesRemote::setIoNiceness(long pid, int priorityClass, int priority) {
++    return false; //Not yet supported
++}
++
++bool ProcessesRemote::supportsIoNiceness() {
++    return false;
++}
++
+ long long ProcessesRemote::totalPhysicalMemory() {
+     return 0;
+ }
+--- a/ksysguard/libksysguard/processcore/process.h
++++ b/ksysguard/libksysguard/processcore/process.h
+@@ -32,7 +32,8 @@
+ 
+   class KDE_EXPORT Process {
+     public:
+-	typedef enum { Running, Sleeping, DiskSleep, Zombie, Stopped, Paging, OtherStatus } ProcessStatus;
++	enum ProcessStatus { Running, Sleeping, DiskSleep, Zombie, Stopped, Paging, OtherStatus };
++	enum IoPriorityClass { None, RealTime, BestEffort, Idle };
+         Process();
+         Process(long long _pid, long long _ppid, Process *_parent);
+ 
+@@ -67,6 +68,8 @@
+         int totalSysUsage; ///Percentage (0 to 100) from the sum of itself and all its children recursively. If there's no children, it's equal to sysUsage. It might be more than 100% on multiple cpu core systems
+         unsigned long numChildren; ///Number of children recursively that this process has.  From 0+
+         int niceLevel;      ///Niceness (-20 to 20) of this process.  A lower number means a higher priority.
++        IoPriorityClass ioPriorityClass; /// The IO priority class.  See man ionice for detailed information.
++        int ioniceLevel;    ///IO Niceless (0 to 7) of this process.  A lower number means a higher io priority.  -1 if not known or not applicable because ioPriorityClass is Idle or None
+         long vmSize;   ///Virtual memory size in KiloBytes, including memory used, mmap'ed files, graphics memory etc,
+         long vmRSS;    ///Physical memory used by the process and its shared libraries.  If the process and libraries are swapped to disk, this could be as low as 0
+         long vmURSS;   ///Physical memory used only by the process, and not counting the code for shared libraries. Set to -1 if unknown
+@@ -78,9 +81,10 @@
+ 
+ 	QString translatedStatus() const;  /// Returns a translated string of the status. e.g. "Running" etc
+ 	QString niceLevelAsString() const; /// Returns a simple translated string of the nice priority.  e.g. "Normal", "High", etc
+-
+-
+-	int index;
++	QString ioniceLevelAsString() const; /// Returns a simple translated string of the io nice priority.  e.g. "Normal", "High", etc
++	QString ioPriorityClassAsString() const; /// Returns a translated string of the io nice class.  i.e. "None", "Real Time", "Best Effort", "Idle"
++        
++	int index;  /// Each process has a parent process.  Each sibling has a unique number to identify it under that parent.  This is that number.
+ 
+   private:
+         void clear();
+--- a/ksysguard/libksysguard/processcore/processes_base_p.h
++++ b/ksysguard/libksysguard/processcore/processes_base_p.h
+@@ -85,6 +85,20 @@
+ 	 *  Returns 0 on error
+ 	 */
+ 	virtual long long totalPhysicalMemory() = 0;
++
++	/**
++	 *  Set the io priority for a process.  This is from 7 (very nice, lowest io priority) to
++	 *  0 (highest priority).  The default value is determined as: io_nice = (cpu_nice + 20) / 5.
++	 *
++	 *  @return false if you do not have permission to set the priority
++	 */
++	virtual bool setIoNiceness(long pid, int priorityClass, int priority) = 0;
++
++	/**
++	 *  Returns true if ionice is supported on this system
++	 */
++	virtual bool supportsIoNiceness() = 0;
++
+     };
+ }
+ 
+--- a/ksysguard/libksysguard/processcore/processes_linux_p.cpp
++++ b/ksysguard/libksysguard/processcore/processes_linux_p.cpp
+@@ -36,10 +36,64 @@
+ #include <sys/resource.h>
+ #include <dirent.h>
+ #include <stdlib.h>
+-
++//for ionice
++#include <sys/ptrace.h>
++#include <asm/unistd.h>
+ 
+ #define PROCESS_BUFFER_SIZE 1000
+ 
++/* For ionice */
++extern int sys_ioprio_set(int, int, int);
++extern int sys_ioprio_get(int, int);
++
++#define HAVE_IONICE
++/* Check if this system has ionice */
++#if !defined(SYS_ioprio_get) || !defined(SYS_ioprio_set)
++/* All new kernels have SYS_ioprio_get and _set defined, but for the few that do not, here are the definitions */
++#if defined(__i386__)
++#define __NR_ioprio_set         289
++#define __NR_ioprio_get         290
++#elif defined(__ppc__) || defined(__powerpc__)
++#define __NR_ioprio_set         273
++#define __NR_ioprio_get         274
++#elif defined(__x86_64__)
++#define __NR_ioprio_set         251
++#define __NR_ioprio_get         252
++#elif defined(__ia64__)
++#define __NR_ioprio_set         1274
++#define __NR_ioprio_get         1275
++#else
++#ifdef __GNUC__
++#warning "This architecture does not support IONICE.  Disabling ionice feature."
++#endif
++#undef HAVE_IONICE
++#endif
++/* Map these to SYS_ioprio_get */
++#define SYS_ioprio_get                __NR_ioprio_get
++#define SYS_ioprio_set                __NR_ioprio_set
++
++#endif /* !SYS_ioprio_get */
++
++/* Set up ionice functions */
++#ifdef HAVE_IONICE
++#define IOPRIO_WHO_PROCESS 1
++#define IOPRIO_CLASS_SHIFT 13
++
++/* Expose the kernel calls to usespace via syscall
++ * See man ioprio_set  and man ioprio_get   for information on these functions */
++static int ioprio_set(int which, int who, int ioprio)
++{
++  return syscall(SYS_ioprio_set, which, who, ioprio);
++}
++ 
++static int ioprio_get(int which, int who)
++{
++  return syscall(SYS_ioprio_get, which, who);
++}
++#endif
++
++
++
+ 
+ namespace KSysGuard
+ {
+@@ -53,6 +107,7 @@
+       inline bool readProcStat(long pid, Process *process);
+       inline bool readProcStatm(long pid, Process *process);
+       inline bool readProcCmdline(long pid, Process *process);
++      inline bool getIoNice(long pid, Process *process);
+       QFile mFile;
+       char mBuffer[PROCESS_BUFFER_SIZE+1]; //used as a buffer to read data into      
+       DIR* mProcDir;
+@@ -291,12 +346,30 @@
+     mFile.close();
+     return true;
+ }
++
++bool ProcessesLocal::Private::getIoNice(long pid, Process *process) {
++#ifdef HAVE_IONICE
++  int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);  /* Returns from 0 to 7 for the iopriority, and -1 if there's an error */
++  if(ioprio == -1) {
++	  process->ioniceLevel = -1;
++	  process->ioPriorityClass = KSysGuard::Process::None;
++	  return false; /* Error. Just give up. */
++  }
++  process->ioniceLevel = ioprio & 0xff;  /* Bottom few bits are the priority */
++  process->ioPriorityClass = (KSysGuard::Process::IoPriorityClass)(ioprio >> IOPRIO_CLASS_SHIFT); /* Top few bits are the class */
++#else
++  return false;  /* Do nothing, if we do not support this architecture */
++#endif
++  return true;
++}
++
+ bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
+ {
+     if(!d->readProcStat(pid, process)) return false;
+     if(!d->readProcStatus(pid, process)) return false;
+     if(!d->readProcStatm(pid, process)) return false;
+     if(!d->readProcCmdline(pid, process)) return false;
++    if(!d->getIoNice(pid, process)) return false;
+ 
+     return true;
+ }
+@@ -328,7 +401,25 @@
+     }
+     return true;
+ }
++bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
++#ifdef HAVE_IONICE
++    if (ioprio_set(IOPRIO_WHO_PROCESS, pid, priority | priorityClass << IOPRIO_CLASS_SHIFT) == -1) {
++	    //set io niceness failed
++	    return false;
++    }
++    return true;
++#else
++    return false;
++#endif
++}
+ 
++bool ProcessesLocal::supportsIoNiceness() {
++#ifdef HAVE_IONICE
++    return true;
++#else
++    return false;
++#endif
++}
+ 
+ long long ProcessesLocal::totalPhysicalMemory() {
+     d->mFile.setFileName("/proc/meminfo");
+--- a/ksysguard/libksysguard/processcore/processes_local_p.h
++++ b/ksysguard/libksysguard/processcore/processes_local_p.h
+@@ -40,6 +40,8 @@
+ 	virtual bool sendSignal(long pid, int sig);
+         virtual bool setNiceness(long pid, int priority);
+ 	virtual long long totalPhysicalMemory();
++	virtual bool setIoNiceness(long pid, int priorityClass, int priority);
++	virtual bool supportsIoNiceness();
+ 
+       private:
+ 	/**
+--- a/ksysguard/libksysguard/processcore/processes_remote_p.h
++++ b/ksysguard/libksysguard/processcore/processes_remote_p.h
+@@ -37,6 +37,8 @@
+ 	virtual bool sendSignal(long pid, int sig);
+         virtual bool setNiceness(long pid, int priority);
+ 	virtual long long totalPhysicalMemory();
++	virtual bool setIoNiceness(long pid, int priorityClass, int priority);
++	virtual bool supportsIoNiceness();
+ 
+       private:
+ 	/**
+--- a/ksysguard/libksysguard/processcore/processes.cpp
++++ b/ksysguard/libksysguard/processcore/processes.cpp
+@@ -92,7 +92,7 @@
+     }
+ }
+ 
+-void Processes::returnInstance(const QString &host) { //static
++void Processes::returnInstance(const QString &/*host*/) { //static
+ 	//Implement - we need reference counting etc
+ }
+ Processes::Processes(AbstractProcesses *abstractProcesses) : d(new Private())
+@@ -163,7 +163,11 @@
+        ps->name != old_process.name ||
+        ps->command != old_process.command ||
+        ps->status != old_process.status ||
+-       ps->uid != old_process.uid ) {
++       ps->uid != old_process.uid || 
++       ps->tracerpid != old_process.tracerpid ||
++       ps->niceLevel != old_process.niceLevel ||
++       ps->ioniceLevel != old_process.ioniceLevel ||
++       ps->ioPriorityClass != old_process.ioPriorityClass ) {
+ 
+        emit processChanged(ps, false);
+ 
+@@ -316,6 +320,14 @@
+     return d->mAbstractProcesses->setNiceness(pid, priority);
+ }
+ 
++bool Processes::setIoNiceness(long pid, KSysGuard::Process::IoPriorityClass priorityClass, int priority) {
++    return d->mAbstractProcesses->setIoNiceness(pid, priorityClass, priority);
++}
++
++bool Processes::supportsIoNiceness() { 
++    return d->mAbstractProcesses->supportsIoNiceness();
++}
++
+ long long Processes::totalPhysicalMemory() {
+     return d->mAbstractProcesses->totalPhysicalMemory();
+ }
+--- a/ksysguard/libksysguard/processcore/processes.h
++++ b/ksysguard/libksysguard/processcore/processes.h
+@@ -112,6 +112,19 @@
+ 	 */
+ 	bool setNiceness(long pid, int priority);
+ 
++	/**
++	 *  Set the io priority for a process.  This is from 7 (very nice, lowest io priority) to
++	 *  0 (highest priority).  The default value is determined as: io_nice = (cpu_nice + 20) / 5.
++	 *
++	 *  @return false if you do not have permission to set the priority
++	 */
++	bool setIoNiceness(long pid, KSysGuard::Process::IoPriorityClass priorityClass, int priority);
++
++	/**
++	 *  Returns true if ionice is supported on this system
++	 */
++	bool supportsIoNiceness();
++
+ 	/** 
+ 	 *  Return the internal pointer of all the processes.  The order of the processes 
+ 	 *  is guaranteed to never change.  Call updateAllProcesses first to actually
+--- a/ksysguard/libksysguard/processui/ProcessModel.cc
++++ b/ksysguard/libksysguard/processui/ProcessModel.cc
+@@ -359,7 +359,7 @@
+ 
+ 	//Deal with the case that we are showing it as a tree
+ 	int row = process->parent->children.count();
+-	QModelIndex parentModelIndex = getQModelIndex(process->parent, 0);
++	QModelIndex parentModelIndex = q->getQModelIndex(process->parent, 0);
+ 
+ 	//Only here can we actually change the model.  First notify the view/proxy models then modify
+ 	q->beginInsertRows(parentModelIndex, row, row);
+@@ -386,7 +386,7 @@
+ 			return;
+ 		}
+ 
+-		return q->beginRemoveRows(getQModelIndex(process->parent,0), row, row);
++		return q->beginRemoveRows(q->getQModelIndex(process->parent,0), row, row);
+ 	}
+ }
+ void ProcessModelPrivate::endRemoveRow() 
+@@ -421,19 +421,19 @@
+ }
+ 
+ 
+-QModelIndex ProcessModelPrivate::getQModelIndex( KSysGuard::Process *process, int column) const
++QModelIndex ProcessModel::getQModelIndex( KSysGuard::Process *process, int column) const
+ {
+ 	Q_ASSERT(process);
+ 	int pid = process->pid;
+ 	if(pid == 0) return QModelIndex(); //pid 0 is our fake process meaning the very root (never drawn).  To represent that, we return QModelIndex() which also means the top element
+ 	int row = 0;
+-        if(mSimple) {
++        if(d->mSimple) {
+ 		row = process->index;
+ 	} else {
+ 		row = process->parent->children.indexOf(process);
+ 	}
+ 	Q_ASSERT(row != -1);
+-	return q->createIndex(row, column, process);
++	return createIndex(row, column, process);
+ }
+ 
+ QModelIndex ProcessModel::parent ( const QModelIndex & index ) const
+@@ -445,12 +445,40 @@
+         if(d->mSimple)
+ 		return QModelIndex();
+ 	else 
+-		return d->getQModelIndex(process->parent,0);
++		return getQModelIndex(process->parent,0);
+ }
+ 
+ QVariant ProcessModel::headerData(int section, Qt::Orientation orientation,
+                                   int role) const
+ {
++	if (role == Qt::ToolTipRole) {
++
++		switch(section) {
++		    case HeadingName:
++			return i18n("The process name");
++		    case HeadingUser:
++			return i18n("The user that owns this process");
++		    case HeadingTty:
++			return i18n("The controlling terminal that this process is running on.");
++		    case HeadingNiceness:
++			return i18n("The priority that this process is being run with. Ranges from 19 (very nice, least priority) to -19 (top priority)");
++		    case HeadingCPUUsage:
++			// xgettext: no-c-format
++			return i18n("The CPU usage that this process is currently using. This can be greater than 100% if you have more than one processor.");
++		    case HeadingVmSize:
++			return i18n("<qt>This is the amount of virtual memory space that the process is using, included shared libraries, graphics memory, files on disk, and so on. This number is almost meaningless.</qt>");
++		    case HeadingMemory:
++			return i18n("<qt>This is the amount of real physical memory that this process is using by itself. It does not include any swapped out memory, nor the code size of its shared libraries. This is often the most useful figure to judge the memory use of a program.</qt>");
++		    case HeadingSharedMemory:
++			return i18n("<qt>This is the amount of real physical memory that this process's shared libraries are using. This memory is shared among all processes that use this library</qt>");
++		    case HeadingCommand:
++			return i18n("<qt>The command that this process was launched with</qt>");
++		    case HeadingXTitle:
++			return i18n("<qt>The title of any windows that this process is showing</qt>");
++		    default:
++			return QVariant();
++		}
++	}
+ 	if (role != Qt::DisplayRole)
+ 		return QVariant();
+ 	if(orientation != Qt::Horizontal)
+@@ -727,7 +755,7 @@
+ 
+ 		case HeadingCommand: {
+ 			QString tooltip =
+-				i18n("<qt>This process was run with the following command:<br />%1</qt>", process->command);
++				i18n("<qt>This process was run with the following command:<br />%1", process->command);
+ 			if(!process->tty.isEmpty())
+ 				tooltip += i18n( "<br /><br />Running on: %1", QString(process->tty));
+ 		        if(tracer.isEmpty()) return tooltip;
+@@ -738,8 +766,16 @@
+ 				return d->getTooltipForUser(process) + "<br />" + tracer;
+ 			return d->getTooltipForUser(process);
+ 		}
+-		case HeadingNiceness:
+-			return i18n("Nice level: %1 (%2)", process->niceLevel, process->niceLevelAsString() );
++		case HeadingNiceness: {
++		        QString tooltip = i18n("<qt>Nice level: %1 (%2)", process->niceLevel, process->niceLevelAsString() );
++			if(process->ioPriorityClass != KSysGuard::Process::None) {
++				if((process->ioPriorityClass == KSysGuard::Process::RealTime || process->ioPriorityClass == KSysGuard::Process::BestEffort) && process->ioniceLevel != -1)
++					tooltip += i18n("<br/>I/O Nice level: %1 (%2)", process->ioniceLevel, process->ioniceLevelAsString() );
++				tooltip += i18n("<br/>I/O Class: %1", process->ioPriorityClassAsString() );
++			}
++		        if(tracer.isEmpty()) return tooltip;
++			return tooltip + "<br />" + tracer;
++		}	
+ 		case HeadingCPUUsage: {
+ 			QString tooltip = ki18n("<qt>Process status: %1 %2<br />"
+ 						"User CPU usage: %3%<br />System CPU usage: %4%</qt>")
+@@ -768,22 +804,23 @@
+ 						.toString();
+ 			if(process->niceLevel != 0)
+ 				tooltip += i18n("<br />Nice level: %1 (%2)", process->niceLevel, process->niceLevelAsString() );
++			if(process->ioPriorityClass != KSysGuard::Process::None) {
++				if((process->ioPriorityClass == KSysGuard::Process::RealTime || process->ioPriorityClass == KSysGuard::Process::BestEffort) && process->ioniceLevel != -1)
++					tooltip += i18n("<br/>I/O Nice level: %1 (%2)", process->ioniceLevel, process->ioniceLevelAsString() );
++				tooltip += i18n("<br/>I/O Class: %1", process->ioPriorityClassAsString() );
++			}
+ 
+ 			if(!tracer.isEmpty())
+ 				return tooltip + "<br />" + tracer;
+ 			return tooltip;
+ 		}
+ 		case HeadingVmSize: {
+-			QString tooltip = i18n("<qt>This is the amount of virtual memory space that the process is using, included shared libraries, graphics memory, files on disk, and so on.  This number is almost meaningless.</qt>");
+-			return tooltip;
++			return QVariant();
+ 		}
+ 		case HeadingMemory: {
+-			QString tooltip;
+-			if(process->vmURSS == -1)
++			QString tooltip = "<qt>";
++			if(process->vmURSS != -1) {
+ 				//We don't have information about the URSS, so just fallback to RSS
+-				tooltip = i18n("<qt>This is the amount of real physical memory that this process is using.  It does not include any swapped out memory, but does include the code size for shared libraries etc.<br /><br /></qt>");
+-			else {
+-				tooltip = i18n("<qt>This is the amount of real physical memory that this process is using by itself.  It does not include any swapped out memory, nor the code size of its shared libraries.  This is often the most useful figure to judge the memory use of a program.<br /><br /></qt>");
+ 				if(d->mMemTotal > 0)
+ 					tooltip += i18n("Memory usage: %1 out of %2  (%3 %)<br />", KGlobal::locale()->formatByteSize(process->vmURSS * 1024), KGlobal::locale()->formatByteSize(d->mMemTotal*1024), process->vmURSS*100/d->mMemTotal);
+ 				else
+@@ -798,11 +835,11 @@
+ 		case HeadingSharedMemory: {
+ 			if(process->vmURSS == -1)
+ 				return i18n("<qt>Your system does not seem to have this information for us to read, sorry.</qt>");
+-			QString tooltip = i18n("<qt>This is the amount of real physical memory that this process's shared libraries are using.  This memory is shared among all processes that use this library</qt>");
++			QString tooltip = "<qt>";
+ 			if(d->mMemTotal >0)
+-				tooltip += i18n("<br /><br />Shared library memory usage: %1 out of %2  (%3 %)", KGlobal::locale()->formatByteSize((process->vmRSS - process->vmURSS) * 1024), KGlobal::locale()->formatByteSize(d->mMemTotal*1024), (process->vmRSS-process->vmURSS)*100/d->mMemTotal);
++				tooltip += i18n("Shared library memory usage: %1 out of %2  (%3 %)", KGlobal::locale()->formatByteSize((process->vmRSS - process->vmURSS) * 1024), KGlobal::locale()->formatByteSize(d->mMemTotal*1024), (process->vmRSS-process->vmURSS)*100/d->mMemTotal);
+ 			else
+-				tooltip += i18n("<br /><br />Shared library memory usage: %1", KGlobal::locale()->formatByteSize((process->vmRSS - process->vmURSS) * 1024));
++				tooltip += i18n("Shared library memory usage: %1", KGlobal::locale()->formatByteSize((process->vmRSS - process->vmURSS) * 1024));
+ 
+ 			return tooltip;
+ 		}
+--- a/ksysguard/libksysguard/processui/ProcessModel_p.h
++++ b/ksysguard/libksysguard/processui/ProcessModel_p.h
+@@ -89,11 +89,7 @@
+ 	void setupProcesses();
+         /** A mapping of running,stopped,etc  to a friendly description like 'Stopped, either by a job control signal or because it is being traced.'*/
+ 	QString getStatusDescription(KSysGuard::Process::ProcessStatus status) const;
+-	/** This returns a QModelIndex for the given process.  It has to look up the parent for this pid, find the offset this 
+-	 *  pid is from the parent, and return that.  It's not that slow, but does involve a couple of hash table lookups.
+-	 */
+-	QModelIndex getQModelIndex ( KSysGuard::Process *process, int column) const;
+-	
++		
+ 	/** Return a qt markup tooltip string for a local user.  It will have their full name etc.
+ 	 *  This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd
+ 	 *  But the second time will be as fast as hash lookup as we cache the result
+--- a/ksysguard/libksysguard/processui/ProcessModel.h
++++ b/ksysguard/libksysguard/processui/ProcessModel.h
+@@ -83,6 +83,11 @@
+ 	/** Returns the total amount of physical memory in the machine. */
+ 	long long totalMemory() const;
+ 
++        /** This returns a QModelIndex for the given process.  It has to look up the parent for this pid, find the offset this 
++	 *  pid is from the parent, and return that.  It's not that slow, but does involve a couple of hash table lookups.
++	 */
++	QModelIndex getQModelIndex ( KSysGuard::Process *process, int column) const;
++
+ 	/** Whether this is showing the processes for the current machine
+ 	 */
+ 	bool isLocalhost() const;
+--- a/ksysguard/libksysguard/processui/ksysguardprocesslist.cpp
++++ b/ksysguard/libksysguard/processui/ksysguardprocesslist.cpp
+@@ -51,7 +51,7 @@
+ #include "processcore/processes.h"
+ 
+ 
+-//Trolltech have a testing class for classes that inherit QAbstractItemModel.  If you want to run with this run-time testing enabled, put themodeltest.* files in this directory and uncomment the next line
++//Trolltech have a testing class for classes that inherit QAbstractItemModel.  If you want to run with this run-time testing enabled, put the modeltest.* files in this directory and uncomment the next line
+ //#define DO_MODELCHECK
+ #ifdef DO_MODELCHECK
+ #include "modeltest.h"
+@@ -135,7 +135,7 @@
+ struct KSysGuardProcessListPrivate {
+     
+ 	KSysGuardProcessListPrivate(KSysGuardProcessList* q) : mModel(q), mFilterModel(q), mUi(new Ui::ProcessWidget()) {}
+-    	/** The column context menu when you right click on a column.*/
++	/** The column context menu when you right click on a column.*/
+ 	QMenu *mColumnContextMenu;
+ 	
+ 	/** The context menu when you right click on a process */
+@@ -159,7 +159,7 @@
+ 	QTimer *mUpdateTimer;
+ 
+ 	/** A timer to rapidly pulse a process being killed */
+-	QTimer *mPulseTimer;
++	//QTimer *mPulseTimer;
+ };
+ 
+ KSysGuardProcessList::KSysGuardProcessList(QWidget* parent)
+@@ -195,7 +195,7 @@
+ 	connect(d->mUi->treeView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex & , const QModelIndex & )), this, SLOT(currentRowChanged(const QModelIndex &)));
+ 	setMinimumSize(sizeHint());
+ 
+-        enum State {AllProcesses=0,AllProcessesInTreeForm, SystemProcesses, UserProcesses, OwnProcesses};
++	enum State {AllProcesses=0,AllProcessesInTreeForm, SystemProcesses, UserProcesses, OwnProcesses};
+ 
+ 	d->mUi->cmbFilter->setItemIcon(ProcessFilter::AllProcesses, KIcon("view-process-all"));
+ 	d->mUi->cmbFilter->setItemIcon(ProcessFilter::AllProcessesInTreeForm, KIcon("view-process-all-tree"));
+@@ -241,7 +241,7 @@
+ 
+ KSysGuardProcessList::~KSysGuardProcessList()
+ {
+-    delete d;
++	delete d;
+ }
+ 
+ QTreeView *KSysGuardProcessList::treeView() const {
+@@ -272,23 +272,83 @@
+ void KSysGuardProcessList::showProcessContextMenu(const QPoint &point){
+ 	d->mProcessContextMenu->clear();
+ 
+-	QAction *renice = new QAction(d->mProcessContextMenu);
+-	renice->setText(i18n("Renice Process..."));
+-	d->mProcessContextMenu->addAction(renice);
+-
+-	QAction *kill = new QAction(d->mProcessContextMenu);
+-	kill->setText(i18n("Kill Process"));
+-	kill->setIcon(KIcon("stop"));
+-	d->mProcessContextMenu->addAction(kill);
++	QModelIndexList selectedIndexes = d->mUi->treeView->selectionModel()->selectedRows();
++	int numProcesses = selectedIndexes.size();
++        
++	if(numProcesses == 0) return;  //No processes selected, so no context menu
++
++	KSysGuard::Process *process = reinterpret_cast<KSysGuard::Process *> (d->mFilterModel.mapToSource(selectedIndexes.at(0)).internalPointer());
++
++
++	QAction *renice = 0;
++	QAction *kill = 0;
++	QAction *selectParent = 0;
++	QAction *selectTracer = 0;
++	QAction *resume = 0;
++	if(numProcesses != 1 || process->status != KSysGuard::Process::Zombie) {  //If the selected process is a zombie, don't bother offering renice and kill options
++
++		renice = new QAction(d->mProcessContextMenu);
++		renice->setText(i18np("Renice Process...", "Renice Processes...", numProcesses));
++		d->mProcessContextMenu->addAction(renice);
++
++		kill = new QAction(d->mProcessContextMenu);
++		kill->setText(i18np("Kill Process", "Kill Processes", numProcesses));
++		kill->setIcon(KIcon("stop"));
++		d->mProcessContextMenu->addAction(kill);
++	}
++
++	if(numProcesses == 1 && process->parent_pid > 1) {
++		//As a design decision, I do not show the 'Jump to parent process' option when the 
++		//parent is just 'init'.
++		selectParent = new QAction(d->mProcessContextMenu);
++		selectParent->setText(i18n("Jump to Parent Process"));
++		d->mProcessContextMenu->addAction(selectParent);
++	}
++
++	if(numProcesses == 1 && process->tracerpid > 0) {
++		//If the process is being debugged, offer to select it
++		selectTracer = new QAction(d->mProcessContextMenu);
++		selectTracer->setText(i18n("Jump to process debugging this one"));
++		d->mProcessContextMenu->addAction(selectTracer);
++	}
++        
++	if(numProcesses == 1 && process->status == KSysGuard::Process::Stopped) {
++		//If the process is being debugged, offer to select it
++		resume = new QAction(d->mProcessContextMenu);
++		resume->setText(i18n("Resume stopped process"));
++		d->mProcessContextMenu->addAction(resume);
++	}
+ 
+-	QAction *result = d->mProcessContextMenu->exec(d->mUi->treeView->mapToGlobal(point));	
+-	if(result == renice) {
++
++	QAction *result = d->mProcessContextMenu->exec(d->mUi->treeView->mapToGlobal(point));
++	if(result == 0) {
++		//Escape was pressed. Do nothing.
++	} else if(result == renice) {
+ 		reniceSelectedProcesses();
+ 	} else if(result == kill) {
+ 		killSelectedProcesses();
++	} else if(result == selectParent) {
++		selectAndJumpToProcess(process->parent_pid);
++	} else if(result == selectTracer) {
++		selectAndJumpToProcess(process->tracerpid);
++	} else if(result == resume) {
++		QList< long long > pidlist;
++		pidlist << process->pid;
++		killProcesses(pidlist, SIGCONT);  //Despite the function name, this sends a signal, rather than kill it.  Silly unix :)
++		updateList();
+ 	}
+ }
+ 
++void KSysGuardProcessList::selectAndJumpToProcess(int pid) {
++	KSysGuard::Process *process = d->mModel.getProcess(pid);
++	if(!process) return;
++	QModelIndex filterIndex = d->mFilterModel.mapFromSource( d->mModel.getQModelIndex(process, 0));
++	d->mUi->treeView->clearSelection();
++	d->mUi->treeView->setCurrentIndex(filterIndex);
++	d->mUi->treeView->scrollTo( filterIndex, QAbstractItemView::PositionAtCenter);
++	
++}
++
+ void KSysGuardProcessList::showColumnContextMenu(const QPoint &point){
+ 	d->mColumnContextMenu->clear();
+ 	
+@@ -339,8 +399,9 @@
+ 	//This is called when the user expands a node.  This then expands all of its 
+ 	//children.  This will trigger this function again recursively.
+ 	QModelIndex sourceParent = d->mFilterModel.mapToSource(parent);
+-	for(int i = 0; i < d->mModel.rowCount(sourceParent); i++) 
++	for(int i = 0; i < d->mModel.rowCount(sourceParent); i++) {
+ 		d->mUi->treeView->expand(d->mFilterModel.mapFromSource(d->mModel.index(i,0, sourceParent)));
++	}
+ }
+ 
+ void KSysGuardProcessList::expandInit()
+@@ -361,8 +422,10 @@
+ void KSysGuardProcessList::showEvent ( QShowEvent * event )  //virtual protected from QWidget
+ {
+ 	//Start updating the process list again if we are shown again
+-	if(!d->mUpdateTimer->isActive()) 
++	if(!d->mUpdateTimer->isActive()) {
+ 		d->mUpdateTimer->start(d->mUpdateIntervalMSecs);
++	}
++	
+ 	QWidget::showEvent(event);
+ }
+ 
+@@ -390,8 +453,9 @@
+ 	QList< long long> unreniced_pids;
+         for (int i = 0; i < pids.size(); ++i) {
+ 		bool success = d->mModel.processController()->setNiceness(pids.at(i), niceValue);
+-		if(!success)
++		if(!success) {
+ 			unreniced_pids << pids.at(i);
++		}
+ 	}
+ 	if(unreniced_pids.isEmpty()) return; //All processes were reniced successfully
+ 	if(!d->mModel.isLocalhost()) return; //We can't use kdesu to renice non-localhost processes
+@@ -399,8 +463,9 @@
+ 	QStringList arguments;
+ 	arguments << "--" << "renice" << QString::number(niceValue);
+ 
+-        for (int i = 0; i < unreniced_pids.size(); ++i)
++        for (int i = 0; i < unreniced_pids.size(); ++i) {
+ 		arguments << QString::number(unreniced_pids.at(i));
++	}
+ 
+ 	QProcess *reniceProcess = new QProcess(NULL);
+ 	connect(reniceProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(reniceFailed()));
+@@ -454,8 +519,9 @@
+ 	QList< long long> unkilled_pids;
+         for (int i = 0; i < pids.size(); ++i) {
+ 		bool success = d->mModel.processController()->sendSignal(pids.at(i), sig);
+-		if(!success)
++		if(!success) {
+ 			unkilled_pids << pids.at(i);
++		}
+ 	}
+ 	if(unkilled_pids.isEmpty()) return;
+ 	if(!d->mModel.isLocalhost()) return; //We can't use kdesu to kill non-localhost processes
+@@ -463,11 +529,13 @@
+ 	//We must use kdesu to kill the process
+ 	QStringList arguments;
+ 	arguments << "--" << "kill";
+-	if(sig != SIGTERM)
++	if(sig != SIGTERM) {
+ 		arguments << ('-' + QString::number(sig));
++	}
+ 
+-        for (int i = 0; i < unkilled_pids.size(); ++i)
++        for (int i = 0; i < unkilled_pids.size(); ++i) {
+ 		arguments << QString::number(unkilled_pids.at(i));
++	}
+ 	
+ 	QProcess *killProcess = new QProcess(NULL);
+ 	connect(killProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(killFailed()));
+@@ -499,7 +567,7 @@
+ 				selectedAsStrings.count());
+ 
+ 		int res = KMessageBox::warningContinueCancelList(this, msg, selectedAsStrings,
+-				                                 i18n("Kill Process"),
++								 i18n("Kill Process"),
+ 								 KGuiItem(i18n("Kill")),
+ 								 KStandardGuiItem::cancel(),
+ 								 "killconfirmation");
+@@ -520,12 +588,12 @@
+ void KSysGuardProcessList::reniceFailed()
+ {
+ 	KMessageBox::sorry(this, i18n("You do not have the permission to renice the process and there "
+-                                      "was a problem trying to run as root"));
++					"was a problem trying to run as root"));
+ }
+ void KSysGuardProcessList::killFailed()
+ {
+ 	KMessageBox::sorry(this, i18n("You do not have the permission to kill the process and there "
+-                                "was a problem trying to run as root"));
++					"was a problem trying to run as root"));
+ }
+ 
+ bool KSysGuardProcessList::showTotals() const {
+--- a/ksysguard/libksysguard/processui/ksysguardprocesslist.h
++++ b/ksysguard/libksysguard/processui/ksysguardprocesslist.h
+@@ -106,6 +106,9 @@
+ 	/** Set whether to show child totals for CPU and Memory etc usage */
+ 	void setShowTotals(bool showTotals);
+ 
++        /** Focus on a particular process, and select it */
++        void selectAndJumpToProcess(int pid);
++
+ private Q_SLOTS:
+ 
+ 	/** Expand all the children, recursively, of the node given.  Pass an empty QModelIndex to expand all the top level children */
+--- a/ksysguard/gui/ksysguard.desktop
++++ b/ksysguard/gui/ksysguard.desktop
+@@ -7,6 +7,7 @@
+ Name[csb]=Mònitor systemë
+ Name[de]=Systemmonitor
+ Name[el]=Επόπτης συστήματος
++Name[et]=Süsteemi jälgija
+ Name[fa]=نمایشگر سیستم
+ Name[ga]=Monatóir an Chórais
+ Name[he]=צג מערכת
+--- a/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui
++++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui
+@@ -283,5 +283,37 @@
+     </hint>
+    </hints>
+   </connection>
++  <connection>
++   <sender>m_lowerLimitActive</sender>
++   <signal>toggled(bool)</signal>
++   <receiver>m_lowerLimit</receiver>
++   <slot>setEnabled(bool)</slot>
++   <hints>
++    <hint type="sourcelabel" >
++     <x>33</x>
++     <y>362</y>
++    </hint>
++    <hint type="destinationlabel" >
++     <x>396</x>
++     <y>362</y>
++    </hint>
++   </hints>
++  </connection>
++  <connection>
++   <sender>m_lowerLimitActive</sender>
++   <signal>toggled(bool)</signal>
++   <receiver>m_lblLowerLimit</receiver>
++   <slot>setEnabled(bool)</slot>
++   <hints>
++    <hint type="sourcelabel" >
++     <x>33</x>
++     <y>362</y>
++    </hint>
++    <hint type="destinationlabel" >
++     <x>320</x>
++     <y>362</y>
++    </hint>
++   </hints>
++  </connection>
+  </connections>
+ </ui>
+--- a/ksysguard/gui/ksysguardapplet.desktop
++++ b/ksysguard/gui/ksysguardapplet.desktop
+@@ -7,6 +7,7 @@
+ Name[csb]=Mònitor systemë
+ Name[de]=Systemmonitor
+ Name[el]=Επόπτης συστήματος
++Name[et]=Süsteemi jälgija
+ Name[fa]=نمایشگر سیستم
+ Name[ga]=Monatóir an Chórais
+ Name[he]=צג מערכת
+@@ -37,6 +38,7 @@
+ Comment[csb]=Aplet jaczi mònitorëje systemòwą wedowiédzã
+ Comment[de]=Anwendung zur Systemüberwachung
+ Comment[el]=Ένα εφαρμογίδιο παρακολούθησης πληροφοριών του συστήματος
++Comment[et]=Süsteemi infot jälgiv aplett
+ Comment[fa]=برنامکی که اطلاعات سیستم را نمایش می‌دهد
+ Comment[he]=יישומון המציג מידע מערכת
+ Comment[ja]=システムの情報を監視するアプレット
+--- a/ksysguard/gui/SystemLoad.sgrd
++++ b/ksysguard/gui/SystemLoad.sgrd
+@@ -3,13 +3,13 @@
+ <WorkSheet title="Sensor Load" interval="2" locked="1" rows="2" columns="2" >
+  <host port="-1" command="ksysguardd" shell="" name="localhost" />
+  <display svgBackground="widgets/plot-background" bColor="4281413681" title="CPU Load" hScale="3" hCount="5" fontColor="4294967295" max="100" vLines="0" hColor="838860800" pause="0" labels="1" autoRange="0" min="0" vDistance="30" globalUpdate="1" fontSize="8" vScroll="0" column="0" topBar="1" unit="" vColor="838860800" hLines="1" showUnit="1" class="FancyPlotter" row="0" >
+-  <beam sensorName="cpu/system/nice" sensorType="float" hostName="localhost" color="872414995" />  
+-  <beam sensorName="cpu/system/user" sensorType="float" hostName="localhost" color="4279798271" />
+-  <beam sensorName="cpu/system/sys" sensorType="float" hostName="localhost" color="4294933768" />
+-  <beam sensorName="cpu/system/wait" sensorType="float" hostName="localhost" color="4294955007" />
++  <beam sensorName="cpu/nice" sensorType="float" hostName="localhost" color="872414995" />  
++  <beam sensorName="cpu/user" sensorType="float" hostName="localhost" color="4279798271" />
++  <beam sensorName="cpu/sys" sensorType="float" hostName="localhost" color="4294933768" />
++  <beam sensorName="cpu/wait" sensorType="float" hostName="localhost" color="4294955007" />
+  </display>
+  <display svgBackground="widgets/plot-background" bColor="4281413681" title="Load Average (1 min)" hScale="3" hCount="5" fontColor="4294967295" vLines="0" hColor="838860800" pause="0" labels="1" autoRange="1" vDistance="30" globalUpdate="1" fontSize="8" vScroll="0" column="1" topBar="1" unit="" vColor="838860800" hLines="1" showUnit="1" class="FancyPlotter" row="0" >
+-  <beam sensorName="cpu/system/loadavg1" sensorType="float" hostName="localhost" color="4279798271" />
++  <beam sensorName="cpu/loadavg1" sensorType="float" hostName="localhost" color="4279798271" />
+  </display>
+  <display svgBackground="widgets/plot-background" bColor="4281413681" title="Physical Memory" hScale="3" hCount="5" fontColor="4294967295" max="1000000" vLines="0" hColor="838860800" pause="0" labels="1" autoRange="0" min="0" vDistance="30" globalUpdate="1" fontSize="8" vScroll="0" column="0" topBar="1" unit="" vColor="838860800" hLines="1" showUnit="1" class="FancyPlotter" row="1" >
+   <beam sensorName="mem/physical/buf" sensorType="integer" hostName="localhost" color="4294933768" />
+--- a/ksysguard/example/ksysguard.notifyrc
++++ b/ksysguard/example/ksysguard.notifyrc
+@@ -48,6 +48,7 @@
+ [Event/pattern_match]
+ Name=Pattern Matched
+ Name[el]=Ταίριασμα μοτίβου
++Name[et]=Sobiv muster
+ Name[ja]=パターンにマッチ
+ Name[km]=លំនាំ​ដែល​ផ្គូផ្គង
+ Name[nb]=Mønsteret traff
+@@ -101,6 +102,7 @@
+ [Event/sensor_alarm]
+ Name=Sensor Alarm
+ Name[el]=Ειδοποίηση αισθητήρα
++Name[et]=Sensori häire
+ Name[ja]=センサーアラーム
+ Name[km]=សំឡេង​រោទិ៍​ឧបករណ៍​ចាប់​សញ្ញា
+ Name[nb]=Følervarsling
+--- a/ksysguard/version.h
++++ b/ksysguard/version.h
+@@ -1,3 +1,3 @@
+ #ifndef KSYSGUARD_VERSION
+ #define KSYSGUARD_VERSION "4"
+-#endif // KSYSGUARD_VERSION
++#endif
+--- a/plasma/containments/panel/plasma-containment-panel.desktop
++++ b/plasma/containments/panel/plasma-containment-panel.desktop
+@@ -52,8 +52,9 @@
+ Name[zh_TW]=面板
+ Comment=A containment for a panel
+ Comment[el]=Ένας υποδοχέας για έναν πίνακα
++Comment[et]=Paneeli konteiner
+ Comment[ja]=Plasmoid (Plasma パネル) の入れ物
+-Comment[km]=បន្ទុក​សម្រាប់​បន្ទះ
++Comment[km]=ការ​ផ្ទុក​សម្រាប់​បន្ទះ
+ Comment[nb]=En beholder for et panel
+ Comment[nds]=En Gelaats för en Paneel
+ Comment[nl]=Een insluiting voor een paneel
+--- a/plasma/containments/panel/panel.cpp
++++ b/plasma/containments/panel/panel.cpp
+@@ -30,6 +30,8 @@
+ Panel::Panel(QObject *parent, const QVariantList &args)
+     : Containment(parent, args)
+ {
++    //FIXME: we should do in the init, not here in the ctor as we'll end up resizing/positioning at
++    //       start up?
+     // Place us at the bottom by default, and make us 48px high:
+     Plasma::Location loc = Plasma::BottomEdge;
+     if (args.count() >= 3 && args[2].canConvert(QVariant::Int)) {
+@@ -37,6 +39,7 @@
+     }
+     setLocation(loc);
+ 
++    //FIXME: we need a proper background painting implementation here
+     m_background = new Plasma::Svg("widgets/panel-background", this);
+     setZValue(150);
+     QDesktopWidget desktop;
+@@ -48,6 +51,11 @@
+     delete m_background;
+ }
+ 
++Containment::Type Panel::type()
++{
++    return PanelContainment;
++}
++
+ void Panel::constraintsUpdated(Plasma::Constraints constraints)
+ {
+     if (constraints & Plasma::LocationConstraint) {
+--- a/plasma/containments/panel/panel.h
++++ b/plasma/containments/panel/panel.h
+@@ -33,6 +33,7 @@
+     Panel(QObject *parent, const QVariantList &args);
+     ~Panel();
+ 
++    Containment::Type type();
+     void constraintsUpdated(Plasma::Constraints constraints);
+     Qt::Orientations expandingDirections() const;
+ 
+--- a/plasma/containments/desktop/desktop.h
++++ b/plasma/containments/desktop/desktop.h
+@@ -19,16 +19,64 @@
+ #ifndef PLASMA_DESKTOP_H
+ #define PLASMA_DESKTOP_H
+ 
++#include <QGraphicsItem>
+ #include <QList>
++#include <QObject>
++
++#include <KIcon>
+ 
+ #include <plasma/containment.h>
++#include <plasma/phase.h>
++#include <plasma/widgets/widget.h>
+ 
+ class QAction;
++class QTimeLine;
++
+ namespace Plasma
+ {
+     class AppletBrowser;
+ }
+ 
++/*class Tool : public QObject, public QGraphicsItem
++{
++    Q_OBJECT
++
++public:
++    explicit Tool(QGraphicsItem *parent = 0);
++    QRectF boundingRect() const;
++    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
++
++};*/
++
++class ToolBox : public QObject, public QGraphicsItem
++{
++    Q_OBJECT
++
++public:
++    explicit ToolBox(QGraphicsItem *parent = 0);
++    QRectF boundingRect() const;
++    QPainterPath shape() const;
++
++    void addTool(Plasma::Widget* tool);
++
++protected:
++    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
++    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
++    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
++
++protected slots:
++    void animate(qreal progress);
++    void toolMoved(QGraphicsItem*);
++
++private:
++    KIcon m_icon;
++    int m_size;
++    bool m_hidden;
++    bool m_showing;
++    Plasma::Phase::AnimId m_animId;
++    int m_animFrame;
++};
++
+ class DefaultDesktop : public Plasma::Containment
+ {
+     Q_OBJECT
+@@ -36,6 +84,8 @@
+ public:
+     DefaultDesktop(QObject *parent, const QVariantList &args);
+     ~DefaultDesktop();
++    void init();
++    void constraintsUpdated(Plasma::Constraints constraints);
+ 
+     QList<QAction*> contextActions();
+ 
+@@ -52,6 +102,7 @@
+     QAction *m_runCommandAction;
+     QAction *m_lockAction;
+     QAction *m_logoutAction;
++    ToolBox *m_toolbox;
+     Plasma::AppletBrowser *m_appletBrowser;
+ };
+ 
+--- a/plasma/containments/desktop/desktop.cpp
++++ b/plasma/containments/desktop/desktop.cpp
+@@ -19,12 +19,17 @@
+ #include "desktop.h"
+ 
+ #include <QAction>
++#include <QPainter>
++#include <QTimeLine>
+ 
+ #include <KAuthorized>
+ #include <KDebug>
+ #include <KRun>
++#include <KWindowSystem>
+ 
+ #include "plasma/appletbrowser.h"
++#include "plasma/phase.h"
++#include "plasma/widgets/pushbutton.h"
+ #include "workspace/kworkspace.h"
+ 
+ #include "krunner_interface.h"
+@@ -32,6 +37,148 @@
+ #include "screensaver_interface.h"
+ 
+ using namespace Plasma;
++/*
++Tool::Tool(QGraphicsItem *parent)
++    : QGraphicsItem(parent)
++{
++}
++*/
++
++
++ToolBox::ToolBox(QGraphicsItem *parent)
++    : QGraphicsItem(parent),
++      m_icon("configure"),
++      m_size(50),
++      m_showing(false),
++      m_animId(0),
++      m_animFrame(0)
++{
++    setAcceptsHoverEvents(true);
++    setZValue(10000);
++    setFlag(ItemClipsToShape, true);
++    setFlag(ItemClipsChildrenToShape, false);
++
++    connect(Plasma::Phase::self(), SIGNAL(movementComplete(QGraphicsItem*)), this, SLOT(toolMoved(QGraphicsItem*)));
++}
++
++/*QRectF ToolBox::sizeHint() const
++{
++    return boundingRect();
++}*/
++
++QRectF ToolBox::boundingRect() const
++{
++    return QRectF(0, 0, m_size*2, m_size*2);
++}
++
++void ToolBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
++{
++    Q_UNUSED(option)
++    Q_UNUSED(widget)
++
++    QPainterPath p = shape();
++    QRadialGradient gradient(QPoint(m_size*2, 0), m_size*3);
++    gradient.setFocalPoint(QPointF(m_size*2, 0));
++    gradient.setColorAt(0, QColor(255, 255, 255, 128));
++    gradient.setColorAt(.9, QColor(128, 128, 128, 128));
++    painter->save();
++    painter->setPen(Qt::NoPen);
++    painter->setRenderHint(QPainter::Antialiasing, true);
++    painter->setBrush(gradient);
++    painter->drawPath(p);
++    painter->restore();
++    m_icon.paint(painter, QRect(m_size*2 - 34, 2, 32, 32));
++}
++
++QPainterPath ToolBox::shape() const
++{
++    QPainterPath path;
++    int size = m_size + m_animFrame;
++    path.moveTo(m_size*2, 0);
++    path.arcTo(QRectF(m_size*2 - size, -size, size*2, size*2), 180, 90);
++    return path;
++}
++
++void ToolBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
++{
++    Q_UNUSED(event)
++
++//    Plasma::Phase::self()->moveItem(this, Phase::SlideIn, QPoint(-25, -25));
++    int x = -25; // pos().x();
++    int y = 0; // pos().y();
++    Plasma::Phase* phase = Plasma::Phase::self();
++    foreach (QGraphicsItem* tool, QGraphicsItem::children()) {
++//        kDebug() << "let's show and move" << (QObject*)tool << tool->geometry().toRect();
++        tool->show();
++        phase->moveItem(tool, Plasma::Phase::SlideIn, QPoint(x, y));
++        //x += 0;
++        y += tool->boundingRect().height() + 5;
++    }
++
++    if (m_animId) {
++        phase->stopCustomAnimation(m_animId);
++    }
++
++    m_showing = true;
++    m_animId = phase->customAnimation(m_size, 150, Plasma::Phase::EaseInCurve, this, "animate");
++}
++
++void ToolBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
++{
++    Q_UNUSED(event)
++//    Plasma::Phase::self->moveItem(this, Phase::SlideOut, boundingRect()QPoint(-50, -50));
++    int x = 0; // pos().x() + geometry().width();
++    int y = 0;
++    Plasma::Phase* phase = Plasma::Phase::self();
++    foreach (QGraphicsItem* tool, QGraphicsItem::children()) {
++        phase->moveItem(tool, Plasma::Phase::SlideOut, QPoint(x, y));
++    }
++
++    if (m_animId) {
++        phase->stopCustomAnimation(m_animId);
++    }
++
++    m_showing = false;
++    m_animId = phase->customAnimation(m_size, 150, Plasma::Phase::EaseOutCurve, this, "animate");
++}
++
++void ToolBox::animate(qreal progress)
++{
++    if (m_showing) {
++        m_animFrame = m_size * progress;
++    } else {
++        m_animFrame = m_size * (1 - progress);
++    }
++
++    //kDebug() << "animating at" << progress << "for" << m_animFrame;
++
++    if (progress >= 1) {
++        m_animId = 0;
++    }
++
++    update();
++}
++
++void ToolBox::toolMoved(QGraphicsItem *item)
++{
++    //kDebug() << "geometry is now " << static_cast<Plasma::Widget*>(item)->geometry();
++    if (!m_showing &&
++        QGraphicsItem::children().indexOf(static_cast<Plasma::Widget*>(item)) != -1) {
++        item->hide();
++    }
++}
++
++void ToolBox::addTool(Plasma::Widget *tool)
++{
++    if (!tool) {
++        return;
++    }
++
++    tool->hide();
++    tool->setPos(pos());
++    tool->setZValue(zValue() + 1);
++    tool->setParentItem(this);
++}
+ 
+ DefaultDesktop::DefaultDesktop(QObject *parent, const QVariantList &args)
+     : Containment(parent, args),
+@@ -40,17 +187,54 @@
+       m_runCommandAction(0),
+       m_lockAction(0),
+       m_logoutAction(0),
++      m_toolbox(0),
+       m_appletBrowser(0)
+ {
++    kDebug() << "!!! loading desktop";
+ }
+ 
+ DefaultDesktop::~DefaultDesktop()
+ {
+ }
+ 
++void DefaultDesktop::init()
++{
++    Containment::init();
++    m_toolbox = new ToolBox(this);
++    //m_toolbox->updateGeometry();
++    m_toolbox->setPos(geometry().width() - m_toolbox->boundingRect().width(), 0);
++
++    Plasma::PushButton *tool = new Plasma::PushButton("Add Widgets", this);
++    tool->resize(tool->sizeHint());
++    m_toolbox->addTool(tool);
++    connect(tool, SIGNAL(clicked()), this, SLOT(launchAppletBrowser()));
++
++    tool = new Plasma::PushButton("Engine Explorer", this);
++    connect(tool, SIGNAL(clicked()), this, SLOT(launchExplorer()));
++    tool->resize(tool->sizeHint());
++    m_toolbox->addTool(tool);
++
++    tool = new Plasma::PushButton("Zoom In", this);
++    //connect(tool, SIGNAL(clicked()), this, SLOT(launchAppletBrowser()));
++    tool->resize(tool->sizeHint());
++    m_toolbox->addTool(tool);
++
++    tool = new Plasma::PushButton("Zoom Out", this);
++    //connect(tool, SIGNAL(clicked()), this, SLOT(launchAppletBrowser()));
++    tool->resize(tool->sizeHint());
++    m_toolbox->addTool(tool);
++}
++
++void DefaultDesktop::constraintsUpdated(Plasma::Constraints constraints)
++{
++    if (constraints & Plasma::ScreenConstraint && m_toolbox) {
++        m_toolbox->setPos(geometry().width() - m_toolbox->boundingRect().width(), 0);
++    }
++}
++
+ void DefaultDesktop::launchExplorer()
+ {
+-    KRun::run("plasmaAppletExplorer", KUrl::List(), 0);
++    KRun::run("plasmaengineexplorer", KUrl::List(), 0);
+ }
+ 
+ void DefaultDesktop::launchAppletBrowser()
+@@ -61,7 +245,9 @@
+         m_appletBrowser = new Plasma::AppletBrowser(this);
+     }
+ 
++    KWindowSystem::setOnDesktop(m_appletBrowser->winId(), KWindowSystem::currentDesktop());
+     m_appletBrowser->show();
++    KWindowSystem::activateWindow(m_appletBrowser->winId());
+ }
+ 
+ void DefaultDesktop::runCommand()
+@@ -102,7 +288,7 @@
+         m_engineExplorerAction = new QAction(i18n("Engine Explorer"), this);
+         connect(m_engineExplorerAction, SIGNAL(triggered(bool)), this, SLOT(launchExplorer()));
+ 
+-        m_appletBrowserAction = new QAction(i18n("Add applet"), this);
++        m_appletBrowserAction = new QAction(i18n("Add Applet..."), this);
+         connect(m_appletBrowserAction, SIGNAL(triggered(bool)), this, SLOT(launchAppletBrowser()));
+ 
+         m_runCommandAction = new QAction(i18n("Run Command..."), this);
+--- /dev/null
++++ b/plasma/dataengines/weather/AUTHORS
+@@ -0,0 +1,2 @@
++Author: Shawn Starr <shawn.starr at rogers.com>
++With Help from Aaron J. Seigo <aseigo at kde.org>
+--- /dev/null
++++ b/plasma/dataengines/weather/TODO
+@@ -0,0 +1 @@
++- For Applet, use Strigi to search though list of cities each Ion provides. This will make it easier choose locations.
+--- /dev/null
++++ b/plasma/dataengines/weather/plasma-engine-weather.desktop
+@@ -0,0 +1,42 @@
++[Desktop Entry]
++Name=Weather Data Engine
++Name[el]=Μηχανή δεδομένων καιρού
++Name[et]=Ilmaandmete mootor
++Name[ga]=Inneall Sonraí Aimsire
++Name[ja]=気象データエンジン
++Name[kk]=Ауа райы қызметі
++Name[km]=ម៉ាស៊ីន​ស្វែងរក​ទិន្នន័យ​អាកាសធាតុ
++Name[ko]=날씨 데이터 엔진
++Name[nb]=Værdata-motor
++Name[nds]=Weder-Hanteerkarn
++Name[nl]=Weer (gegevensengine)
++Name[nn]=Vêrdatamotor
++Name[pt]=Motor de Dados Meteorológicos
++Name[pt_BR]=Mecanismo de Dados Meteorológicos
++Name[sv]=Datagränssnitt för väder
++Name[x-test]=xxWeather Data Enginexx
++Name[zh_CN]=天气数据引擎
++Name[zh_TW]=天氣資料引擎
++Comment=Weather data for Plasmoids
++Comment[el]=Δεδομένα καιρού για πλασμοειδή
++Comment[et]=Ilmaandmed plasmoididele
++Comment[ga]=Sonraí aimsire le haghaidh Plasmoids
++Comment[ja]=Plasmoid のための気象データ
++Comment[kk]=Плазмоидтер үшін ауа райы деректері
++Comment[km]=ទិន្នន័យ​អាកាសធាតុ​សម្រាប់ Plasmoids
++Comment[ko]=Plasmoid를 위한 날씨 정보
++Comment[nb]=Værdata for Plasmoids
++Comment[nds]=Wederdaten för Plasmoiden
++Comment[nl]=Weergegevens voor Plasmoids
++Comment[nn]=Vêrdata for plasmoidar
++Comment[pt]=Dados meteorológicos para os Plasmóides
++Comment[pt_BR]=Dados meteorológicos para os Plasmóides
++Comment[sv]=Väderdata för Plasmoider
++Comment[x-test]=xxWeather data for Plasmoidsxx
++Comment[zh_CN]=Plasmoids 的天气数据
++Comment[zh_TW]=Plasmoid 的天氣資料
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=
++X-KDE-Library=plasma_engine_weather
++X-EngineName=weather
+--- /dev/null
++++ b/plasma/dataengines/weather/weatherengine.cpp
+@@ -0,0 +1,223 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++#include "weatherengine.h"
++#include <KServiceTypeTrader>
++#include <KDateTime>
++#include <KLocale>
++#include "ions/ion.h"
++
++class WeatherEngine::Private
++{
++public:
++    Private() {}
++    ~Private() {
++        qDeleteAll(m_ions);
++    }
++
++    IonInterface* ionForSource(const QString& name)
++    {
++        int offset = name.indexOf(':');
++
++        if (offset < 1) {
++            return 0;
++        }
++
++        QString ionName = name.left(offset);
++
++        if (!this->m_ions.contains(ionName)) {
++            return 0;
++        }
++
++        return this->m_ions[ionName];
++    }
++
++    IonInterface::IonDict m_ions;
++    KDateTime m_localTime;
++};
++
++// Returns an instance of an Ion plugin loaded.
++IonInterface* WeatherEngine::Ion(const QString& name) const
++{
++    IonInterface::IonDict::const_iterator it = d->m_ions.find(name);
++    if (it != d->m_ions.end()) {
++        return *it;
++    }
++
++    return NULL;
++}
++
++// Loads an Ion plugin given a plugin name found via KService.
++IonInterface* WeatherEngine::loadIon(const KService::Ptr& service)
++{
++    IonInterface *ion = 0;
++    QString plugName = service->property("X-IonName").toString();
++    IonInterface::IonDict::const_iterator it = d->m_ions.find(plugName);
++
++    if (it != d->m_ions.end()) {
++         ion = *it;
++         ion->ref();
++         return ion;
++    }
++
++    QString error;
++
++    // Load the Ion plugin, store it into a QMap to handle multiple ions.
++    ion = service->createInstance<IonInterface>(0, QVariantList(), &error);
++    if (!ion) {
++        kDebug() << "weatherengine: Couldn't load ion \"" << plugName << "\"!" << error;
++        return 0;
++    }
++
++    // Increment counter of ions.
++    ion->ref();
++
++    // Set the Ion's long name
++    //ion->setObjectName(offers.first()->name());
++    connect(ion, SIGNAL(newSource(QString)), this, SLOT(newIonSource(QString)));
++    connect(ion, SIGNAL(sourceRemoved(QString)), this, SLOT(removeIonSource(QString)));
++
++    /* Set properties for the ion
++     *
++     * TIMEFORMAT is displaying the time/date in UTC or user's local time
++     * UNITS is setting the weather units used, Celsius/Fahrenheit, Kilopascals/Inches of Mercury, etc
++     * WINDFORMAT enable winds to be displayed as meters per second (m/s) some countries display winds like this
++     */
++
++    ion->option(IonInterface::TIMEFORMAT, QVariant(d->m_localTime.isUtc()));
++    ion->option(IonInterface::UNITS, KGlobal::locale()->measureSystem());
++    ion->option(IonInterface::WINDFORMAT, QVariant(false)); // FIXME: Should be configurable by applet
++
++    // Assign the instantiated ion the key of the name of the ion.
++    d->m_ions[plugName] = ion;
++
++    return ion;
++}
++
++// Unload an Ion plugin given a Ion plugin name.
++void WeatherEngine::unloadIon(const QString &name)
++{
++    IonInterface *ion = Ion(name);
++    if (ion) {
++        ion->deref();
++
++        if (!ion->isUsed()) {
++            d->m_ions.remove(name);
++            delete ion;
++        }
++    }
++}
++
++// Return a list of Ion plugins found.
++KService::List WeatherEngine::knownIons()
++{
++    KService::List offers = KServiceTypeTrader::self()->query("WeatherEngine/Ion");
++
++    if (offers.isEmpty()) {
++        kDebug() << "weatherengine: No plugins to load!";
++        return KService::List();
++    }
++
++    foreach(KService::Ptr service, offers) {
++        setData("ions", service->property("X-IonName").toString(), service->property("Name").toString());
++    }
++
++    return offers;
++}
++
++void WeatherEngine::newIonSource(const QString& source)
++{
++    IonInterface *ion = qobject_cast<IonInterface*>(sender());
++
++    if (!ion) {
++        return;
++    }
++    ion->connectSource(source, this);
++}
++
++void WeatherEngine::removeIonSource(const QString& source)
++{
++    IonInterface *ion = qobject_cast<IonInterface*>(sender());
++    if (!ion) {
++        return;
++    }
++    ion->disconnectSource(source, this);
++}
++
++void WeatherEngine::updated(const QString& source, Plasma::DataEngine::Data data)
++{
++    setData(source, data);
++}
++
++// ctor
++WeatherEngine::WeatherEngine(QObject *parent, const QVariantList& args)
++        :  Plasma::DataEngine(parent), d(new Private())
++{
++    Q_UNUSED(args)
++
++    // Set any local properties for Ion to use
++    d->m_localTime = KDateTime::currentDateTime(KDateTime::LocalZone);
++
++    /* FIXME: For now we just load them all as we find them, we'll need to make this configurable
++              somehow. No point in loading all plugins if your not interested in certain cities.
++    */
++    foreach(KService::Ptr service, knownIons()) {
++        loadIon(service); 
++    }
++}
++
++// dtor
++WeatherEngine::~WeatherEngine()
++{
++    // Cleanup all private data.
++    delete d;
++}
++
++// Setup each Ion for the first time
++bool WeatherEngine::sourceRequested(const QString &source)
++{
++    IonInterface *ion = d->ionForSource(source);
++
++    if (!ion) {
++        return false;
++    }
++
++    ion->connectSource(source, this);
++    kDebug() << "sourceRequested()";
++    setData(source, this);
++    return true;
++}
++
++// SLOT: update the Applet with new data from all ions loaded.
++bool WeatherEngine::updateSource(const QString& source)
++{
++    IonInterface *ion = d->ionForSource(source);
++ 
++    if (!ion) {
++        return false;
++    }
++
++    if (ion->updateSource(source)) {
++        return true;
++    } else {
++        return false;
++    }
++}
++
++#include "weatherengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/weather/COPYING
+@@ -0,0 +1,340 @@
++		    GNU GENERAL PUBLIC LICENSE
++		       Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++			    Preamble
++
++  The licenses for most software are designed to take away your
++freedom to share and change it.  By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users.  This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it.  (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.)  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++  To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have.  You must make sure that they, too, receive or can get the
++source code.  And you must show them these terms so they know their
++rights.
++
++  We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++  Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software.  If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++  Finally, any free program is threatened constantly by software
++patents.  We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary.  To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++		    GNU GENERAL PUBLIC LICENSE
++   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++  0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License.  The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language.  (Hereinafter, translation is included without limitation in
++the term "modification".)  Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope.  The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++  1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++  2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++    a) You must cause the modified files to carry prominent notices
++    stating that you changed the files and the date of any change.
++
++    b) You must cause any work that you distribute or publish, that in
++    whole or in part contains or is derived from the Program or any
++    part thereof, to be licensed as a whole at no charge to all third
++    parties under the terms of this License.
++
++    c) If the modified program normally reads commands interactively
++    when run, you must cause it, when started running for such
++    interactive use in the most ordinary way, to print or display an
++    announcement including an appropriate copyright notice and a
++    notice that there is no warranty (or else, saying that you provide
++    a warranty) and that users may redistribute the program under
++    these conditions, and telling the user how to view a copy of this
++    License.  (Exception: if the Program itself is interactive but
++    does not normally print such an announcement, your work based on
++    the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole.  If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works.  But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++  3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++    a) Accompany it with the complete corresponding machine-readable
++    source code, which must be distributed under the terms of Sections
++    1 and 2 above on a medium customarily used for software interchange; or,
++
++    b) Accompany it with a written offer, valid for at least three
++    years, to give any third party, for a charge no more than your
++    cost of physically performing source distribution, a complete
++    machine-readable copy of the corresponding source code, to be
++    distributed under the terms of Sections 1 and 2 above on a medium
++    customarily used for software interchange; or,
++
++    c) Accompany it with the information you received as to the offer
++    to distribute corresponding source code.  (This alternative is
++    allowed only for noncommercial distribution and only if you
++    received the program in object code or executable form with such
++    an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it.  For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable.  However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++  4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License.  Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++  5. You are not required to accept this License, since you have not
++signed it.  However, nothing else grants you permission to modify or
++distribute the Program or its derivative works.  These actions are
++prohibited by law if you do not accept this License.  Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++  6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions.  You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++  7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all.  For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices.  Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++  8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded.  In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++  9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number.  If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation.  If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++  10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission.  For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this.  Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++			    NO WARRANTY
++
++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++		     END OF TERMS AND CONDITIONS
++
++	    How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) <year>  <name of author>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++    Gnomovision version 69, Copyright (C) year name of author
++    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary.  Here is a sample; alter the names:
++
++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++  `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++  <signature of Ty Coon>, 1 April 1989
++  Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs.  If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library.  If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_envcan.cpp
+@@ -0,0 +1,1463 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for Environment Canada XML data */
++
++#include "ion_envcan.h"
++
++class EnvCanadaIon::Private : public QObject
++{
++public:
++    Private() {}
++    ~Private() {}
++
++private:
++    struct XMLMapInfo {
++        QString cityName;
++        QString territoryName;
++        QString cityCode;
++    };
++
++public:
++    // Key dicts
++    QHash<QString, EnvCanadaIon::Private::XMLMapInfo> m_place;
++    QHash<QString, QString> m_locations;
++    QString m_code;
++    QString m_territory;
++    QString m_cityName;
++
++    // Weather information
++    QHash<QString, WeatherData> m_weatherData;
++
++    // Store KIO jobs
++    QMap<KJob *, QXmlStreamReader*> m_jobXml;
++    QMap<KJob *, QString> m_jobList;
++    QXmlStreamReader m_xmlSetup;
++    KUrl *m_url;
++    KIO::TransferJob *m_job;
++
++    bool m_useUTC;  // Ion option: Timezone may be local time or UTC time
++    bool m_useMetric; // Ion option: Units may be Metric or Imperial
++    bool m_windInMeters; // Ion option: Display wind format in meters per second only
++
++    WeatherFormula m_formula;
++};
++
++
++// ctor, dtor
++EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args)
++        : IonInterface(parent), d(new Private())
++{
++    Q_UNUSED(args)
++}
++
++EnvCanadaIon::~EnvCanadaIon()
++{
++    // Destroy each warning stored in a QVector
++    foreach(WeatherData item, d->m_weatherData) {
++        foreach(WeatherData::WarningInfo *warning, item.warnings) {
++            if (warning) {
++                delete warning;
++            }
++        }
++        foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
++            if (forecast) {
++                delete forecast;
++            }
++        }
++    }
++
++    // Destroy dptr
++    delete d;
++}
++
++// Get the master list of locations to be parsed
++void EnvCanadaIon::init()
++{
++    // Get the real city XML URL so we can parse this
++    getXMLSetup();
++}
++
++QString EnvCanadaIon::validate(const QString& source)
++{
++    QHash<QString, QString>::const_iterator it = d->m_locations.find(source);
++    if (it != d->m_locations.end()) {
++        return source;
++    }
++    return QString();
++}
++
++// Get a specific Ion's data
++bool EnvCanadaIon::updateIonSource(const QString& source)
++{
++
++    QString result = this->validate(source);
++
++    if (!result.isEmpty()) {
++        QStringList tokens = result.split(':');
++        setData(source, "Validate", tokens[1]);
++        getXMLData(source);
++        return true;
++    }
++    setData(source, "Validate", "Invalid");
++    return false;
++}
++
++// Parses city list and gets the correct city based on ID number
++void EnvCanadaIon::getXMLSetup()
++{
++
++    d->m_url = new KUrl("http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/siteList.xml");
++
++    KIO::TransferJob *job = KIO::get(d->m_url->url(), KIO::NoReload, KIO::HideProgressInfo);
++
++    if (job) {
++        connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
++        connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
++    }
++}
++
++// Gets specific city XML data
++void EnvCanadaIon::getXMLData(const QString& source)
++{
++    KUrl url;
++    url = "http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/" + d->m_place[source].territoryName + "/" + d->m_place[source].cityCode + "_e.xml";
++
++    kDebug() << "URL Location: " << url.url();
++
++    d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
++    d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
++    d->m_jobList.insert(d->m_job, source);
++
++    if (d->m_job) {
++        connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
++        connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
++    }
++}
++
++void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++    Q_UNUSED(job)
++
++    if (data.isEmpty()) {
++        return;
++    }
++
++    // Send to xml.
++    d->m_xmlSetup.addData(data.data());
++}
++
++void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++
++    if (data.isEmpty() || !d->m_jobXml.contains(job)) {
++        return;
++    }
++
++    // Send to xml.
++    d->m_jobXml[job]->addData(data.data());
++}
++
++void EnvCanadaIon::slotJobFinished(KJob *job)
++{
++    // Dual use method, if we're fetching location data to parse we need to do this first
++    readXMLData(d->m_jobList[job], *d->m_jobXml[job]);
++    d->m_jobList.remove(job);
++    delete d->m_jobXml[job];
++    d->m_jobXml.remove(job);
++}
++
++void EnvCanadaIon::setup_slotJobFinished(KJob *job)
++{
++    Q_UNUSED(job)
++    readXMLSetup();
++    this->setInitialized(true);
++}
++
++// Parse the city list and store into a QMap
++bool EnvCanadaIon::readXMLSetup()
++{
++    QString tmp;
++    while (!d->m_xmlSetup.atEnd()) {
++        d->m_xmlSetup.readNext();
++
++        if (d->m_xmlSetup.isStartElement()) {
++
++            // XML ID code to match filename
++            if (d->m_xmlSetup.name() == "site") {
++                d->m_code = d->m_xmlSetup.attributes().value("code").toString();
++            }
++
++            if (d->m_xmlSetup.name() == "nameEn") {
++                d->m_cityName = d->m_xmlSetup.readElementText(); // Name of cities
++            }
++
++            if (d->m_xmlSetup.name() == "provinceCode") {
++                d->m_territory = d->m_xmlSetup.readElementText(); // Provinces/Territory list
++                tmp = "envcan:" + d->m_cityName + ", " + d->m_territory; // Build the key name.
++
++                // Set the mappings
++                d->m_place[tmp].cityCode = d->m_code;
++                d->m_place[tmp].territoryName = d->m_territory;
++                d->m_place[tmp].cityName = d->m_cityName;
++
++                // Set the string list, we will use for the applet to display the available cities.
++                d->m_locations[tmp] = tmp;
++            }
++        }
++
++    }
++    return !d->m_xmlSetup.error();
++}
++
++WeatherData EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
++{
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "license") {
++                xml.readElementText();
++            } else if (xml.name() == "location") {
++                parseLocations(data, xml);
++            } else if (xml.name() == "warnings") {
++                parseWarnings(data, xml);
++            } else if (xml.name() == "currentConditions") {
++                parseConditions(data, xml);
++            } else if (xml.name() == "forecastGroup") {
++                parseWeatherForecast(data, xml);
++            } else if (xml.name() == "yesterdayConditions") {
++                parseYesterdayWeather(data, xml);
++            }
++            else if (xml.name() == "riseSet") {
++                parseAstronomicals(data, xml);
++            }
++            else if (xml.name() == "almanac") {
++              parseWeatherRecords(data, xml);
++            }
++            else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++    return data;
++}
++
++// Parse Weather data main loop, from here we have to decend into each tag pair
++bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml)
++{
++    WeatherData data;
++    data.comforttemp = "N/A";
++    data.recordHigh = 0.0;
++    data.recordLow = 0.0;
++    data.shortTerritoryName = d->m_place[source].territoryName;
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "siteData") {
++                data = parseWeatherSite(data, xml);
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++
++    d->m_weatherData[source] = data;
++    updateWeather(source);
++    return !xml.error();
++}
++
++void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WarningInfo *warning)
++{
++
++    Q_ASSERT(xml.isStartElement() && xml.name() == "dateTime");
++
++    // What kind of date info is this?
++    QString dateType = xml.attributes().value("name").toString();
++    QString dateZone = xml.attributes().value("zone").toString();
++
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (dateType == "xmlCreation") {
++                return;
++            }
++            if (xml.name() == "year") {
++                xml.readElementText();
++            } else if (xml.name() == "month") {
++                xml.readElementText();
++            } else if (xml.name() == "day") {
++                xml.readElementText();
++            } else if (xml.name() == "hour")
++                xml.readElementText();
++            else if (xml.name() == "minute")
++                xml.readElementText();
++            else if (xml.name() == "timeStamp") {
++                if (d->m_useUTC && dateZone == "UTC") {
++                    // Which timestamp are we for?
++
++                    if (dateType == "eventIssue") {
++                        if (warning) {
++                            warning->timestamp = xml.readElementText();
++                        }
++                    } else if (dateType == "observation") {
++                        data.obsTimestamp = xml.readElementText();
++                    } else if (dateType == "forecastIssue") {
++                        data.forecastTimestamp = xml.readElementText();
++                    } else if (dateType == "sunrise") {
++                        data.sunriseTimestamp = xml.readElementText();
++                    } else if (dateType == "sunset") {
++                        data.sunsetTimestamp = xml.readElementText();
++                    } else if (dateType == "moonrise") {
++                        data.moonriseTimestamp = xml.readElementText();
++                    } else if (dateType == "moonset") {
++                        data.moonsetTimestamp = xml.readElementText();
++                    }
++
++                } else if (dateZone != "UTC") {
++                    if (dateType == "eventIssue") {
++                        if (warning) {
++                            warning->timestamp = xml.readElementText();
++                        }
++                    } else if (dateType == "observation") {
++                        data.obsTimestamp = xml.readElementText();
++                    } else if (dateType == "forecastIssue") {
++                        data.forecastTimestamp = xml.readElementText();
++                    } else if (dateType == "sunrise") {
++                        data.sunriseTimestamp = xml.readElementText();
++                    } else if (dateType == "sunset") {
++                        data.sunsetTimestamp = xml.readElementText();
++                    } else if (dateType == "moonrise") {
++                        data.moonriseTimestamp = xml.readElementText();
++                    } else if (dateType == "moonset") {
++                        data.moonsetTimestamp = xml.readElementText();
++                    }
++                }
++            } else if (xml.name() == "textSummary") {
++                xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "location");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "country") {
++                data.countryName = xml.readElementText();
++            } else if (xml.name() == "province" || xml.name() == "territory") {
++                data.longTerritoryName = xml.readElementText();
++            } else if (xml.name() == "name") {
++                data.cityName = xml.readElementText();
++            } else if (xml.name() == "region") {
++                data.regionName = xml.readElementText();
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "wind");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "speed") {
++                data.windSpeed = xml.readElementText();
++            } else if (xml.name() == "gust") {
++                data.windGust = xml.readElementText();
++            } else if (xml.name() == "direction") {
++                data.windDirection = xml.readElementText();
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml)
++{
++
++    Q_ASSERT(xml.isStartElement() && xml.name() == "currentConditions");
++    data.temperature = "N/A";
++    data.dewpoint = "N/A";
++    data.condition = "N/A";
++    data.comforttemp = "N/A";
++    data.stationID = "N/A";
++    data.pressure = 0.0;
++    data.pressureTendency = "N/A";
++    data.visibility = 0;
++    data.humidity = "N/A";
++    data.windSpeed = "N/A";
++    data.windGust = "N/A";
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "currentConditions")
++            break;
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "station") {
++                data.stationID = xml.attributes().value("code").toString();
++            } else if (xml.name() == "dateTime") {
++                parseDateTime(data, xml);
++            } else if (xml.name() == "condition") {
++                data.condition = xml.readElementText();
++            } else if (xml.name() == "temperature") {
++                data.temperature = xml.readElementText();;
++            } else if (xml.name() == "dewpoint") {
++                data.dewpoint = xml.readElementText();
++            } else if (xml.name() == "humidex" || xml.name() == "windChill") {
++                data.comforttemp = xml.readElementText();
++            } else if (xml.name() == "pressure") {
++                data.pressureTendency = xml.attributes().value("tendency").toString();
++                if (data.pressureTendency.isEmpty()) {
++                    data.pressureTendency = "steady";
++                }
++                data.pressure = xml.readElementText().toFloat();
++            } else if (xml.name() == "visibility") {
++                data.visibility = xml.readElementText().toFloat();
++            } else if (xml.name() == "relativeHumidity") {
++                data.humidity = xml.readElementText();
++            } else if (xml.name() == "wind") {
++                parseWindInfo(data, xml);
++            }
++            //} else {
++            //    parseUnknownElement(xml);
++            //}
++        }
++    }
++}
++
++void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml)
++{
++    WeatherData::WarningInfo* warning = new WeatherData::WarningInfo;
++
++    Q_ASSERT(xml.isStartElement() && xml.name() == "warnings");
++    QString warningURL = xml.attributes().value("url").toString();
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "warnings") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "dateTime") {
++                parseDateTime(data, xml, warning);
++                if (!warning->timestamp.isEmpty() && !warning->url.isEmpty())  {
++                    data.warnings.append(warning);
++                    warning = new WeatherData::WarningInfo;
++                }
++            } else if (xml.name() == "event") {
++                // Append new event to list.
++                warning->url = warningURL;
++                warning->type = xml.attributes().value("type").toString();
++                warning->priority = xml.attributes().value("priority").toString();
++                warning->description = xml.attributes().value("description").toString();
++            } else {
++                if (xml.name() != "dateTime") {
++                    parseUnknownElement(xml);
++                }
++            }
++        }
++    }
++    delete warning;
++}
++
++
++void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml)
++{
++    WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo;
++    Q_ASSERT(xml.isStartElement() && xml.name() == "forecastGroup");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "forecastGroup") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "dateTime") {
++                parseDateTime(data, xml);
++            } else if (xml.name() == "regionalNormals") {
++                parseRegionalNormals(data, xml);
++            } else if (xml.name() == "forecast") {
++                parseForecast(data, xml, forecast);
++                forecast = new WeatherData::ForecastInfo;
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++    delete forecast;
++}
++
++void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "regionalNormals");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "textSummary") {
++                xml.readElementText();
++            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
++                data.normalHigh = xml.readElementText();
++            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
++                data.normalLow = xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast)
++{
++
++    Q_ASSERT(xml.isStartElement() && xml.name() == "forecast");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "forecast") {
++            data.forecasts.append(forecast);
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "period") {
++                forecast->forecastPeriod = xml.readElementText();
++            } else if (xml.name() == "textSummary") {
++                forecast->forecastSummary = xml.readElementText();
++            } else if (xml.name() == "abbreviatedForecast") {
++                parseShortForecast(forecast, xml);
++            } else if (xml.name() == "temperatures") {
++                parseForecastTemperatures(forecast, xml);
++            } else if (xml.name() == "winds") {
++                parseWindForecast(forecast, xml);
++            } else if (xml.name() == "precipitation") {
++                parsePrecipitationForecast(forecast, xml);
++            } else if (xml.name() == "uv") {
++                data.UVRating = xml.attributes().value("category").toString();
++                parseUVIndex(data, xml);
++                // else if (xml.name() == "frost") { FIXME: Wait until winter to see what this looks like.
++                //  parseFrost(xml, forecast);
++            } else {
++                if (xml.name() != "forecast") {
++                    parseUnknownElement(xml);
++                }
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "abbreviatedForecast");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "abbreviatedForecast") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "pop") {
++                forecast->popPrecent = xml.readElementText();
++            }
++            if (xml.name() == "textSummary") {
++                forecast->shortForecast = xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_UNUSED(data);
++    Q_ASSERT(xml.isStartElement() && xml.name() == "uv");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "uv") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "index") {
++                data.UVIndex = xml.readElementText();
++            }
++            if (xml.name() == "textSummary") {
++                xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "temperatures");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "temperatures") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
++                forecast->forecastTempLow = xml.readElementText();
++            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
++                forecast->forecastTempHigh = xml.readElementText();
++            } else if (xml.name() == "textSummary") {
++                xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "precipitation");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "precipitation") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            //kDebug() << "parsePrecipitationForecast() ====> TAG: " << xml.name().toString();
++            if (xml.name() == "textSummary") {
++                forecast->precipForecast = xml.readElementText();
++            } else if (xml.name() == "precipType") {
++                forecast->precipType = xml.readElementText();
++            } else if (xml.name() == "accumulation") {
++                parsePrecipTotals(forecast, xml);
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "accumulation");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "accumulation") {
++            break;
++        }
++
++        if (xml.name() == "name") {
++            xml.readElementText();
++        } else if (xml.name() == "amount") {
++            forecast->precipTotalExpected = xml.readElementText();
++        }
++    }
++}
++
++void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "winds");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "winds") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "textSummary") {
++                forecast->windForecast = xml.readElementText();
++            } else {
++                if (xml.name() != "winds") {
++                    parseUnknownElement(xml);
++                }
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "yesterdayConditions");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
++                data.prevHigh = xml.readElementText();
++            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
++                data.prevLow = xml.readElementText();
++            } else if (xml.name() == "precip") {
++                data.prevPrecipType = xml.attributes().value("units").toString();
++                if (data.prevPrecipType.isEmpty()) {
++                    data.prevPrecipType = "N/A";
++                }
++                data.prevPrecipTotal = xml.readElementText();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "almanac");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "almanac") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMax") {
++                data.recordHigh = xml.readElementText().toFloat();
++            } else if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMin") {
++                data.recordLow = xml.readElementText().toFloat();
++            } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeRainfall") {
++                data.recordRain = xml.readElementText().toFloat();
++            } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeSnowfall") {
++                data.recordSnow = xml.readElementText().toFloat();
++            }
++        }
++    }
++}
++
++void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "riseSet");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "riseSet") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "disclaimer") {
++                xml.readElementText();
++            } else if (xml.name() == "dateTime") {
++                parseDateTime(data, xml);
++            }
++        }
++    }
++}
++
++// handle when no XML tag is found
++void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml)
++{
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            parseUnknownElement(xml);
++        }
++    }
++}
++
++// User toggleable values set from the dataengine <-> Plasma Applet
++void EnvCanadaIon::option(int option, QVariant value)
++{
++    switch (option) {
++    case IonInterface::UNITS:
++        // Set the Units used (Depends on Ion)
++        if (value.toInt() == KLocale::Metric) {
++            d->m_useMetric = true;
++        }
++        if (value.toInt() == KLocale::Imperial) {
++            d->m_useMetric = false;
++        }
++        break;
++    case IonInterface::TIMEFORMAT:
++        if (value.toBool()) {
++            d->m_useUTC = true;
++        }
++        break;
++    case IonInterface::WINDFORMAT:
++        if (value.toBool()) {
++           d->m_windInMeters = true;
++        } else {
++           d->m_windInMeters = false;
++        }
++        break;
++    }
++}
++
++void EnvCanadaIon::updateWeather(const QString& source)
++{
++    QMap<QString, QString> dataFields;
++    QStringList fieldList;
++    QVector<QString> forecastList;
++    int i = 0;
++
++    setData(source, "Country", this->country(source));
++    setData(source, "Place", QString("%1, %2").arg(this->city(source)).arg(this->territory(source)));
++    setData(source, "Region", this->region(source));
++    setData(source, "Airport Code", this->station(source));
++
++    // Real weather - Current conditions
++    setData(source, "Observations At", this->observationTime(source));
++    setData(source, "Current Conditions", this->condition(source));
++    dataFields = this->temperature(source);
++    setData(source, "Temperature", dataFields["temperature"]);
++
++    // Do we have a comfort temperature? if so display it
++    if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) {
++        if (dataFields["comfortTemperature"].toFloat() <= 0 || (dataFields["comfortTemperature"].toFloat() <= 32 && !d->m_useMetric)) {
++            setData(source, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
++        } else {
++            setData(source, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
++        }
++     }
++
++     setData(source, "Dewpoint", this->dewpoint(source));
++     if (this->dewpoint(source) != "N/A") {
++         setData(source, "Dewpoint Unit", dataFields["temperatureUnit"]);
++     }
++
++     dataFields = this->pressure(source);
++     setData(source, "Pressure", dataFields["pressure"]);
++  
++     if (dataFields["pressure"] != "N/A") {
++         setData(source, "Pressure Tendency", dataFields["pressureTendency"]);
++         setData(source, "Pressure Unit", dataFields["pressureUnit"]);
++     }
++
++     dataFields = this->visibility(source);
++     setData(source, "Visibility", dataFields["visibility"]);
++     if (dataFields["visibility"] != "N/A") {
++         setData(source, "Visibility Unit", dataFields["visibilityUnit"]);
++     }
++
++     setData(source, "Humidity", this->humidity(source));
++
++     dataFields = this->wind(source);
++     setData(source, "Wind Speed", dataFields["windSpeed"]);
++     if (dataFields["windSpeed"] != "N/A") {
++         setData(source, "Wind Speed Unit", dataFields["windUnit"]);
++     }
++     setData(source, "Wind Gust", dataFields["windGust"]);
++     if (dataFields["windGust"] != "N/A") {
++         setData(source, "Wind Gust Unit", dataFields["windGustUnit"]);
++     }
++     setData(source, "Wind Direction", dataFields["windDirection"]);
++
++     dataFields = this->regionalTemperatures(source);
++     setData(source, "Normal High", dataFields["normalHigh"]);
++     setData(source, "Normal Low", dataFields["normalLow"]);
++     if (dataFields["normalHigh"] != "N/A" && dataFields["normalLow"] != "N/A") {
++         setData(source, "Regional Temperature Unit", dataFields["regionalTempUnit"]);
++     }
++
++     // Check if UV index is available for the location
++     dataFields = this->uvIndex(source);
++     setData(source, "UV Index", dataFields["uvIndex"]);
++     if (dataFields["uvIndex"] != "N/A") {
++         setData(source, "UV Rating", dataFields["uvRating"]);
++     }
++
++     dataFields = this->warnings(source);
++     // Check if we have warnings or watches
++     if (!dataFields["watch"].isEmpty()) {
++         fieldList = dataFields["watch"].split('|');
++         setData(source, "Watch Priority", fieldList[0]);
++         setData(source, "Watch Description", fieldList[1]);
++         setData(source, "Watch Info", fieldList[2]);
++         setData(source, "Watch Timestamp", fieldList[3]);
++     }
++     if (!dataFields["warning"].isEmpty()) {
++         fieldList = dataFields["warning"].split('|');
++         setData(source, "Warning Priority", fieldList[0]);
++         setData(source, "Warning Description", fieldList[1]);
++         setData(source, "Warning Info", fieldList[2]);
++         setData(source, "Warning Timestamp", fieldList[3]);
++     }
++
++     forecastList = this->forecasts(source);
++     foreach(QString forecastItem, forecastList) {
++         fieldList = forecastItem.split('|');
++
++         if (d->m_useMetric) {
++             setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
++                     .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5]));
++
++             setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
++                     .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \
++                     .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9]));
++          } else {
++              setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
++                      .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3] == "N/A" ? "N/A" : \
++                      QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()), 'd', 0)) \
++                      .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[5]));
++
++               setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
++                       .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3] == "N/A" ? "N/A" : \
++                       QString::number(d->m_formula.celsiusToF(fieldList[3].toFloat()),'d', 0)) \
++                       .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(d->m_formula.celsiusToF(fieldList[4].toFloat()),'d',0)).arg(fieldList[6]).arg(fieldList[7]) \
++                       .arg(fieldList[8]).arg(fieldList[9]));
++            }
++
++            i++;
++        }
++
++     dataFields = this->yesterdayWeather(source);
++     setData(source, "Yesterday High", dataFields["prevHigh"]);
++     setData(source, "Yesterday Low", dataFields["prevLow"]);
++   
++     if (dataFields["prevHigh"] != "N/A" && dataFields["prevLow"] != "N/A") {
++         setData(source ,"Yesterday Temperature Unit", dataFields["yesterdayTempUnit"]);
++     }
++
++     setData(source, "Yesterday Precip Total", dataFields["prevPrecip"]);
++     setData(source, "Yesterday Precip Unit", dataFields["prevPrecipUnit"]);
++
++     dataFields = this->sunriseSet(source);
++     setData(source, "Sunrise At", dataFields["sunrise"]);
++     setData(source, "Sunset At", dataFields["sunset"]);
++
++     dataFields = this->moonriseSet(source);
++     setData(source, "Moonrise At", dataFields["moonrise"]);
++     setData(source, "Moonset At", dataFields["moonset"]);
++
++     dataFields = this->weatherRecords(source);
++     setData(source, "Record High Temperature", dataFields["recordHigh"]);
++     setData(source, "Record Low Temperature", dataFields["recordLow"]);
++     if (dataFields["recordHigh"] != "N/A" && dataFields["recordLow"] != "N/A") {
++         setData(source, "Record Temperature Unit", dataFields["recordTempUnit"]);
++     }
++
++     setData(source, "Record Rainfall", dataFields["recordRain"]);
++     setData(source, "Record Rainfall Unit", dataFields["recordRainUnit"]);
++     setData(source, "Record Snowfall", dataFields["recordSnow"]);
++     setData(source, "Record Snowfall Unit", dataFields["recordSnowUnit"]);
++
++     setData(source, "Credit", "Environment Canada");
++}
++
++QString EnvCanadaIon::country(const QString& source)
++{
++    return d->m_weatherData[source].countryName;
++}
++QString EnvCanadaIon::territory(const QString& source)
++{
++    return d->m_weatherData[source].shortTerritoryName;
++}
++QString EnvCanadaIon::city(const QString& source)
++{
++    return d->m_weatherData[source].cityName;
++}
++QString EnvCanadaIon::region(const QString& source)
++{
++    return d->m_weatherData[source].regionName;
++}
++QString EnvCanadaIon::station(const QString& source)
++{
++    if (!d->m_weatherData[source].stationID.isEmpty()) {
++         return d->m_weatherData[source].stationID.toUpper();
++    }
++    
++    return QString("N/A");
++}
++
++QString EnvCanadaIon::observationTime(const QString& source)
++{
++    return d->m_weatherData[source].obsTimestamp;
++}
++QString EnvCanadaIon::condition(const QString& source)
++{
++    if (d->m_weatherData[source].condition.isEmpty()) {
++        d->m_weatherData[source].condition = "N/A";
++    }
++    return d->m_weatherData[source].condition;
++}
++
++QString EnvCanadaIon::dewpoint(const QString& source)
++{
++    if (d->m_useMetric) {
++        if (!d->m_weatherData[source].dewpoint.isEmpty()) {
++            return QString("%1").arg(QString::number(d->m_weatherData[source].dewpoint.toFloat(), 'f', 1));
++        }
++    }
++ 
++    if (!d->m_weatherData[source].dewpoint.isEmpty()) {
++         return QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].dewpoint.toFloat()), 'f', 1));
++    }
++
++    return QString("N/A");
++}
++
++QString EnvCanadaIon::humidity(const QString& source)
++{
++    if (!d->m_weatherData[source].humidity.isEmpty()) {
++        return QString("%1%").arg(d->m_weatherData[source].humidity);
++    }
++    return QString("N/A");
++}
++
++QMap<QString,QString> EnvCanadaIon::visibility(const QString& source)
++{
++    QMap<QString, QString> visibilityInfo;
++
++    if (!d->m_weatherData[source].visibility == 0) {
++        if (d->m_useMetric) {
++            visibilityInfo.insert("visibility", QString("%1").arg(QString::number(d->m_weatherData[source].visibility, 'f', 1)));
++            visibilityInfo.insert("visibilityUnit", "km");
++        } else {
++            visibilityInfo.insert("visibility", QString("%1").arg(QString::number(d->m_formula.kilometersToMI(d->m_weatherData[source].visibility), 'f', 2)));
++            visibilityInfo.insert("visibilityUnit", "mi");
++        }
++    } else {
++      visibilityInfo.insert("visibility", "N/A");
++    }
++    return visibilityInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::temperature(const QString& source)
++{
++    QMap<QString, QString> temperatureInfo;
++    if (d->m_useMetric) {
++        if (!d->m_weatherData[source].temperature.isEmpty()) {
++            temperatureInfo.insert("temperature", QString("%1").arg(QString::number(d->m_weatherData[source].temperature.toFloat(), 'f', 1)));
++        }
++    }
++    else {
++        if (!d->m_weatherData[source].temperature.isEmpty()) {
++            temperatureInfo.insert("temperature", QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].temperature.toFloat()), 'f', 1)));
++        } else {
++            temperatureInfo.insert("temperature", "N/A");
++        }
++    }  
++    temperatureInfo.insert("comfortTemperature", "N/A");
++
++    if (d->m_weatherData[source].comforttemp != "N/A") {
++        if (d->m_useMetric) {
++            temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].comforttemp);
++        }
++        else {
++            if (!d->m_weatherData[source].comforttemp.isEmpty()) {
++                temperatureInfo.insert("comfortTemperature", QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].comforttemp.toFloat()), 'f', 1));
++            }
++        }
++    }
++    return temperatureInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::warnings(const QString& source)
++{
++    QMap<QString, QString> warningData;
++    QString warnType;
++    for (int i = 0; i < d->m_weatherData[source].warnings.size(); ++i) {
++        if (d->m_weatherData[source].warnings[i]->type == "watch") {
++            warnType = "watch";
++        } else {
++            warnType = "warning";
++        }
++        warningData[warnType] = QString("%1|%2|%3|%4").arg(d->m_weatherData[source].warnings[i]->priority) \
++                                .arg(d->m_weatherData[source].warnings[i]->description) \
++                                .arg(d->m_weatherData[source].warnings[i]->url) \
++                                .arg(d->m_weatherData[source].warnings[i]->timestamp);
++    }
++    return warningData;
++}
++
++QVector<QString> EnvCanadaIon::forecasts(const QString& source)
++{
++    QVector<QString> forecastData;
++
++    // Do some checks for empty data
++    for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
++        if (d->m_weatherData[source].forecasts[i]->forecastPeriod.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->forecastPeriod = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->shortForecast.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->shortForecast = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->forecastSummary.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->forecastSummary = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->forecastTempHigh.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->forecastTempHigh = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->forecastTempLow.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->forecastTempLow = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->popPrecent.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->popPrecent = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->windForecast.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->windForecast = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->precipForecast.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->precipForecast = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->precipType.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->precipType = "N/A";
++        }
++        if (d->m_weatherData[source].forecasts[i]->precipTotalExpected.isEmpty()) {
++            d->m_weatherData[source].forecasts[i]->precipTotalExpected = "N/A";
++        }
++    }
++
++    for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
++        forecastData.append(QString("%1|%2|%3|%4|%5|%6|%7|%8|%9|%10") \
++                            .arg(d->m_weatherData[source].forecasts[i]->forecastPeriod) \
++                            .arg(d->m_weatherData[source].forecasts[i]->shortForecast) \
++                            .arg(d->m_weatherData[source].forecasts[i]->forecastSummary) \
++                            .arg(d->m_weatherData[source].forecasts[i]->forecastTempHigh) \
++                            .arg(d->m_weatherData[source].forecasts[i]->forecastTempLow) \
++                            .arg(d->m_weatherData[source].forecasts[i]->popPrecent) \
++                            .arg(d->m_weatherData[source].forecasts[i]->windForecast) \
++                            .arg(d->m_weatherData[source].forecasts[i]->precipForecast) \
++                            .arg(d->m_weatherData[source].forecasts[i]->precipType) \
++                            .arg(d->m_weatherData[source].forecasts[i]->precipTotalExpected));
++    }
++    return forecastData;
++}
++
++QMap<QString, QString> EnvCanadaIon::pressure(const QString& source)
++{
++    QMap<QString, QString> pressureInfo;
++
++    if (d->m_weatherData[source].pressure == 0) {
++        pressureInfo.insert("pressure", "N/A");
++        return pressureInfo;
++    } else {
++        if (d->m_useMetric) {
++            pressureInfo.insert("pressure", QString("%1").arg(QString::number(d->m_weatherData[source].pressure, 'f', 1)));
++            pressureInfo.insert("pressureUnit", "kPa");
++        } else {
++            pressureInfo.insert("pressure", QString("%1").arg(QString::number(d->m_formula.kilopascalsToInches(d->m_weatherData[source].pressure), 'f', 2)));
++            pressureInfo.insert("pressureUnit", "in");
++        }
++        pressureInfo.insert("pressureTendency", d->m_weatherData[source].pressureTendency);
++    }
++    return pressureInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::wind(const QString& source)
++{
++    QMap<QString, QString> windInfo;
++
++    // May not have any winds
++    if (d->m_weatherData[source].windSpeed.isEmpty()) {
++        windInfo.insert("windSpeed", "N/A");
++        windInfo.insert("windUnit", "N/A");
++    } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
++        windInfo.insert("windSpeed", "Calm");
++        windInfo.insert("windUnit", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            if (d->m_windInMeters) {
++                windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_formula.kilometersToMS(d->m_weatherData[source].windSpeed.toInt()), 'f', 2)));
++                windInfo.insert("windUnit", "m/s");
++            } else {
++                windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_weatherData[source].windSpeed.toInt())));
++                windInfo.insert("windUnit", "km/h");
++            }
++        } else {
++            windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_formula.kilometersToMI(d->m_weatherData[source].windSpeed.toInt()), 'f', 1)));
++            windInfo.insert("windUnit", "mph");
++        }
++    }
++
++    // May not always have gusty winds
++    if (d->m_weatherData[source].windGust.isEmpty()) {
++        windInfo.insert("windGust", "N/A");
++        windInfo.insert("windGustUnit", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            if (d->m_windInMeters) { 
++                windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_formula.kilometersToMS(d->m_weatherData[source].windGust.toInt()), 'f', 2)));
++                windInfo.insert("windGustUnit", "m/s");
++            } else { 
++                windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_weatherData[source].windGust.toInt())));
++                windInfo.insert("windGustUnit", "km/h");
++            }
++        } else {
++            windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_formula.kilometersToMI(d->m_weatherData[source].windGust.toInt()), 'f', 1)));
++            windInfo.insert("windGustUnit", "mph");
++        }
++    }
++
++    if (d->m_weatherData[source].windDirection.isEmpty() && d->m_weatherData[source].windSpeed.isEmpty()) {
++        windInfo.insert("windDirection", "N/A");
++    } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
++        windInfo.insert("windDirection", "VR");
++    } else {
++        windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
++    }
++    return windInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::uvIndex(const QString& source)
++{
++    QMap<QString, QString> uvInfo;
++
++    if (d->m_weatherData[source].UVRating.isEmpty()) {
++        uvInfo.insert("uvRating", "N/A");
++    } else {
++        uvInfo.insert("uvRating", d->m_weatherData[source].UVRating);
++    }
++
++    if (d->m_weatherData[source].UVIndex.isEmpty()) {
++        uvInfo.insert("uvIndex", "N/A");
++    } else {
++        uvInfo.insert("uvIndex", d->m_weatherData[source].UVIndex);
++    }
++
++    return uvInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::regionalTemperatures(const QString& source)
++{
++    QMap<QString, QString> regionalTempInfo;
++
++    if (d->m_weatherData[source].normalHigh.isEmpty()) {
++        regionalTempInfo.insert("normalHigh", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            regionalTempInfo.insert("normalHigh", QString("%1").arg(d->m_weatherData[source].normalHigh));
++        } else {
++            regionalTempInfo.insert("normalHigh", QString("%1").arg(d->m_formula.celsiusToF(d->m_weatherData[source].normalHigh.toFloat())));
++        }
++    }
++
++    if (d->m_weatherData[source].normalLow.isEmpty()) {
++        regionalTempInfo.insert("normalLow", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            regionalTempInfo.insert("normalLow", QString("%1").arg(d->m_weatherData[source].normalLow));
++        } else {
++            regionalTempInfo.insert("normalLow", QString("%1").arg(d->m_formula.celsiusToF(d->m_weatherData[source].normalLow.toFloat())));
++        }
++    }
++
++    if (d->m_useMetric) {
++        regionalTempInfo.insert("regionalTempUnit", QString("%1C").arg(QChar(176)));
++    } else {
++        regionalTempInfo.insert("regionalTempUnit", QString("%1F").arg(QChar(176)));
++    }
++
++    return regionalTempInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::yesterdayWeather(const QString& source)
++{
++    QMap<QString, QString> yesterdayInfo;
++
++    if (d->m_weatherData[source].prevHigh.isEmpty()) {
++        yesterdayInfo.insert("prevHigh", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            yesterdayInfo.insert("prevHigh", QString("%1").arg(d->m_weatherData[source].prevHigh)); 
++        } else {
++            yesterdayInfo.insert("prevHigh", QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].prevHigh.toFloat()))));
++        }
++    }
++
++    if (d->m_weatherData[source].prevLow.isEmpty()) {
++        yesterdayInfo.insert("prevLow", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            yesterdayInfo.insert("prevLow", QString("%1").arg(d->m_weatherData[source].prevLow));
++        } else {
++            yesterdayInfo.insert("prevLow", QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].prevLow.toFloat()), 'f', 1)));
++        }
++    }
++
++    if (d->m_useMetric) {
++        yesterdayInfo.insert("yesterdayTempUnit", QString("%1C").arg(QChar(176)));
++    } else {
++        yesterdayInfo.insert("yesterdayTempUnit", QString("%1F").arg(QChar(176)));
++    }
++
++    if (d->m_weatherData[source].prevPrecipTotal == "Trace") {
++            yesterdayInfo.insert("prevPrecip", "Trace");
++            return yesterdayInfo;
++    }
++
++    if (d->m_weatherData[source].prevPrecipTotal.isEmpty()) {
++        yesterdayInfo.insert("prevPrecip", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            yesterdayInfo.insert("prevPrecipTotal", QString("%1").arg(d->m_weatherData[source].prevPrecipTotal));
++            yesterdayInfo.insert("prevPrecipUnit", d->m_weatherData[source].prevPrecipType);
++        } else {
++            yesterdayInfo.insert("prevPrecipTotal", QString("%1").arg(QString::number(d->m_formula.millimetersToIN(d->m_weatherData[source].prevPrecipTotal.toFloat()), 'f', 1)));
++            yesterdayInfo.insert("prevPrecipUnit", QString("in"));
++        }
++    }
++
++    return yesterdayInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::sunriseSet(const QString& source)
++{
++    QMap<QString, QString> sunInfo;
++  
++    if (d->m_weatherData[source].sunriseTimestamp.isEmpty()) {
++        sunInfo.insert("sunrise", "N/A");
++    } else {
++        sunInfo.insert("sunrise", d->m_weatherData[source].sunriseTimestamp);
++    }
++ 
++    if (d->m_weatherData[source].sunsetTimestamp.isEmpty()) {
++        sunInfo.insert("sunset", "N/A");
++    } else {
++        sunInfo.insert("sunset", d->m_weatherData[source].sunsetTimestamp);
++    }
++
++    return sunInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::moonriseSet(const QString& source)
++{
++    QMap<QString, QString> moonInfo;
++ 
++    if (d->m_weatherData[source].moonriseTimestamp.isEmpty()) {
++        moonInfo.insert("moonrise", "N/A");
++    } else {
++        moonInfo.insert("moonrise", d->m_weatherData[source].moonriseTimestamp);
++    }
++   
++    if (d->m_weatherData[source].moonsetTimestamp.isEmpty()) {
++        moonInfo.insert("moonset", "N/A");
++    } else {
++        moonInfo.insert("moonset", d->m_weatherData[source].moonsetTimestamp);
++    }
++   
++    return moonInfo;
++}
++
++QMap<QString, QString> EnvCanadaIon::weatherRecords(const QString& source)
++{
++    QMap<QString, QString> recordInfo;
++
++    if (d->m_weatherData[source].recordHigh == 0) {
++        recordInfo.insert("recordHigh", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            recordInfo.insert("recordHigh", QString("%1").arg(d->m_weatherData[source].recordHigh));
++        } else {
++            recordInfo.insert("recordHigh", QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].recordHigh), 'f', 1)));
++        }
++    }
++
++    if (d->m_weatherData[source].recordLow == 0) {
++        recordInfo.insert("recordLow", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            recordInfo.insert("recordLow", QString("%1").arg(d->m_weatherData[source].recordLow));
++        } else {
++            recordInfo.insert("recordLow", QString("%1").arg(QString::number(d->m_formula.celsiusToF(d->m_weatherData[source].recordLow), 'f', 1)));
++        }
++       
++    }
++
++    if (d->m_useMetric) {
++        recordInfo.insert("recordTempUnit", QString("%1C").arg(QChar(176)));
++    } else {
++        recordInfo.insert("recordTempUnit", QString("%1F").arg(QChar(176)));
++    }
++
++    if (d->m_weatherData[source].recordRain == 0) {
++        recordInfo.insert("recordRain", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            recordInfo.insert("recordRain", QString("%1").arg(d->m_weatherData[source].recordRain));
++            recordInfo.insert("recordRainUnit", QString("mm"));
++        } else {
++            recordInfo.insert("recordRain", QString("%1").arg(QString::number(d->m_formula.millimetersToIN(d->m_weatherData[source].recordRain), 'f', 1)));
++            recordInfo.insert("recordRainUnit", QString("in"));
++        }
++    }
++
++    if (d->m_weatherData[source].recordSnow == 0) {
++        recordInfo.insert("recordSnow", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            recordInfo.insert("recordSnow", QString("%1").arg(d->m_weatherData[source].recordSnow));
++            recordInfo.insert("recordSnowUnit", QString("cm"));
++        } else {
++            recordInfo.insert("recordSnow", QString("%1").arg(QString::number(d->m_formula.centimetersToIN(d->m_weatherData[source].recordSnow), 'f', 1)));
++            recordInfo.insert("recordSnowUnit", QString("in"));
++        }
++    }
++
++    return recordInfo;
++}
++ 
++#include "ion_envcan.moc"
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_bbcukmet.cpp
+@@ -0,0 +1,399 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for BBC's Weather from the UK Met Office */
++
++#include "ion_bbcukmet.h"
++
++class UKMETIon::Private : public QObject
++{
++public:
++    Private() {}
++    ~Private() {}
++
++private:
++    struct XMLMapInfo {
++        QString place;
++        QString XMLurl;
++        bool ukPlace;
++    };
++
++public:
++    // Key dicts
++    QHash<QString, UKMETIon::Private::XMLMapInfo> m_place;
++    QVector<QString> m_locations;
++public:
++    // Weather information
++    QHash<QString, WeatherData> m_weatherData;
++
++    // Store KIO jobs - Search list
++    QMap<KJob *, QXmlStreamReader*> m_jobXml;
++    QMap<KJob *, QString> m_jobList;
++
++    QMap<KJob *, QXmlStreamReader*> m_forecastJobXml;
++    QMap<KJob *, QString> m_forecastJobList;
++
++    KUrl *m_url;
++    KIO::TransferJob *m_job;
++
++    bool m_useUTC;  // Ion option: Timezone may be local time or UTC time
++    bool m_useMetric; // Ion option: Units may be Metric or Imperial
++    bool m_windInMeters; // Ion option: Display wind format in meters per second only
++
++    WeatherFormula m_formula;
++};
++
++
++// ctor, dtor
++UKMETIon::UKMETIon(QObject *parent, const QVariantList &args)
++        : IonInterface(parent), d(new Private())
++{
++    Q_UNUSED(args)
++}
++
++UKMETIon::~UKMETIon()
++{
++    // Destroy dptr
++    delete d;
++}
++
++// Get the master list of locations to be parsed
++void UKMETIon::init()
++{
++return;
++}
++
++// Get a specific Ion's data
++bool UKMETIon::updateIonSource(const QString& source)
++{
++       Q_UNUSED(source)
++       //if (!d->m_locations.contains(source)) {
++       //    searchPlace(source);
++       //} else {
++       //    cachedLocation(source);
++      // }
++return true;
++}
++
++// Parses city list and gets the correct city based on ID number
++void UKMETIon::searchPlace(const QString& key)
++{
++    KUrl url;
++    url = "http://www.bbc.co.uk/cgi-perl/weather/search/new_search.pl?x=0&y=0&=Submit&search_query=" + key + "&tmpl=wap";
++    kDebug() << "URL: " << url;
++
++    d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
++    d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
++    d->m_jobList.insert(d->m_job, key);
++ 
++    if (d->m_job) {
++        connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
++        connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
++    }
++}
++
++bool UKMETIon::readSearchXMLData(const QString& key, QXmlStreamReader& xml)
++{
++    while (!xml.atEnd()) {
++        xml.readNext();
++ 
++        if (xml.isEndElement()) {
++            break;
++        }
++ 
++        if (xml.isStartElement()) {
++            kDebug() << "XML TAG: " << xml.name().toString();
++            if (xml.name() == "wml") {
++                parseSearchLocations(key, xml);
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++
++return !xml.error();
++}
++
++void UKMETIon::cachedLocation(const QString& key)
++{
++    d->m_job = 0;
++    kDebug() << "cachedLocation: d->m_place[key].place = " << d->m_place[key].place;
++    if (d->m_place.contains(key)) {
++        d->m_job = KIO::get(d->m_place[key].XMLurl, KIO::Reload, KIO::HideProgressInfo);
++        kDebug() << "URL: " << d->m_place[key].XMLurl;
++
++        if (d->m_job) {
++             d->m_forecastJobXml.insert(d->m_job, new QXmlStreamReader);
++             d->m_forecastJobList.insert(d->m_job, key);
++             kDebug() << "CACHE FORECAST FOR " << d->m_forecastJobList[d->m_job];
++             connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                     SLOT(forecast_slotDataArrived(KIO::Job *, const QByteArray &)));
++             connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(forecast_slotJobFinished(KJob *)));
++        }
++    }
++}
++ 
++void UKMETIon::parseSearchLocations(const QString& source, QXmlStreamReader& xml)
++{ 
++    Q_UNUSED(source) 
++    int flag = 0;
++    QString url;
++    QString place;
++    QStringList tokens;
++    Q_ASSERT(xml.isStartElement() && xml.name() == "wml");
++   
++    while (!xml.atEnd()) {
++        xml.readNext();
++  
++        if (xml.isEndElement() && xml.name() == "wml") {
++           break;
++        }
++     
++        if (xml.isStartElement()) {
++            if (xml.name() == "a" && !xml.attributes().value("href").isEmpty()) {
++                if (xml.attributes().value("href").toString().contains("5day.wml")) {
++
++                    // Split URL to determine station ID number
++                    tokens = xml.attributes().value("href").toString().split("=");
++                    if (xml.attributes().value("href").toString().contains("world")) {
++                        url = "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens[1] + ".xml";
++                        flag = 0;
++                    } else {
++                        url = "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens[1] + ".xml";
++                        flag = 1;
++                    }
++                    place = xml.readElementText();
++  
++                    if (!d->m_locations.contains(place)) {
++                        if (flag) {  // This is a UK specific location
++                            d->m_place[place].XMLurl = url;
++                            d->m_place[place].place = place;
++                            d->m_place[place].ukPlace = true;
++                        } else {
++                            d->m_place[place].XMLurl = url;
++                            d->m_place[place].place = place;
++                            d->m_place[place].ukPlace = false;
++                        }
++                        d->m_locations.append(place);
++                    }
++                }
++            }
++        } 
++    }
++    // All Locations
++    if (d->m_place[source].ukPlace) {
++        //kDebug() << "UKMET: LIST OF UK PLACE: " << source;
++        setData("FoundPlaces", source, QString("%1|%2").arg(source).arg("Local"));
++        //kDebug() << "UKMET: URL OF UK PLACE: " << d->m_place[source].XMLurl;
++    }
++
++    if (!d->m_place[source].ukPlace) {
++        //kDebug() << "UKMET: LIST OF WORLD PLACE: " << source;
++        setData("FoundPlaces", source, QString("%1|%2").arg(source).arg("World"));
++        //kDebug() << "UKMET: URL OF WORLD PLACE: " << d->m_place[source].XMLurl;
++    }
++}
++
++// handle when no XML tag is found
++void UKMETIon::parseUnknownElement(QXmlStreamReader& xml)
++{
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            parseUnknownElement(xml);
++        }
++    }
++}
++    
++void UKMETIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++    if (data.isEmpty() || !d->m_jobXml.contains(job)) {
++        return;
++    }
++
++    // Send to xml.
++    d->m_jobXml[job]->addData(data.data());
++}
++
++void UKMETIon::slotJobFinished(KJob *job)
++{
++    readSearchXMLData(d->m_jobList[job], *d->m_jobXml[job]);
++    d->m_jobList.remove(job);
++    delete d->m_jobXml[job];
++    d->m_jobXml.remove(job);
++}
++
++void UKMETIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++    kDebug() << "UKMET: RECEIVING FORECAST INFORMATION\n";
++    if (data.isEmpty() || !d->m_forecastJobXml.contains(job)) {
++        return;
++    }
++  
++    // Send to xml.
++    d->m_forecastJobXml[job]->addData(data.data());
++}
++
++void UKMETIon::forecast_slotJobFinished(KJob *job)
++{
++    kDebug() << "UKMET: FORECAST INFO FOR " << d->m_forecastJobList[job] << " FINISHED\n";
++    readObservationXMLData(d->m_forecastJobList[job], *d->m_forecastJobXml[job]);
++    d->m_forecastJobList.remove(job);
++    delete d->m_forecastJobXml[job];
++    d->m_forecastJobXml.remove(job);
++}
++
++void UKMETIon::parsePlaceObservation(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "rss");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "rss") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "channel") {
++                parseWeatherChannel(data, xml);
++            }
++        }
++    }
++}
++
++void UKMETIon::parseWeatherChannel(WeatherData& data, QXmlStreamReader& xml)
++{
++    Q_ASSERT(xml.isStartElement() && xml.name() == "channel");
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "channel") {
++            break;
++        }
++  
++        if (xml.isStartElement()) {
++            if (xml.name() == "title") {
++                kDebug() << "PLACE NAME: " << xml.readElementText();
++            } else if (xml.name() == "item") {
++                parseWeatherObservation(data, xml);
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++}
++
++void UKMETIon::parseWeatherObservation(WeatherData& data, QXmlStreamReader& xml)
++{   
++    Q_UNUSED(data)
++    Q_ASSERT(xml.isStartElement() && xml.name() == "item");
++ 
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement() && xml.name() == "item") {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "title") {
++                kDebug() << "CONDITIONS: " << xml.readElementText();
++            } else if (xml.name() == "description") {
++                kDebug() << "OBSERVATIONS: " << xml.readElementText();
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++}
++
++bool UKMETIon::readObservationXMLData(QString& key, QXmlStreamReader& xml)
++{
++    WeatherData data;
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            kDebug() << "XML TAG: " << xml.name().toString();
++            if (xml.name() == "rss") {
++                parsePlaceObservation(data, xml);
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++
++    d->m_weatherData[key] = data;
++    return !xml.error();
++}
++
++// User toggleable values set from the dataengine <-> Plasma Applet
++void UKMETIon::option(int option, QVariant value)
++{
++    switch (option) {
++    case IonInterface::UNITS:
++        // Set the Units used (Depends on Ion)
++        if (value.toInt() == KLocale::Metric) {
++            d->m_useMetric = true;
++        }
++        if (value.toInt() == KLocale::Imperial) {
++            d->m_useMetric = false;
++        }
++        break;
++    case IonInterface::TIMEFORMAT:
++        if (value.toBool()) {
++            d->m_useUTC = true;
++        }
++        break;
++    case IonInterface::WINDFORMAT:
++        if (value.toBool()) {
++            d->m_windInMeters = true;
++        }
++        break;
++    }
++}
++
++bool UKMETIon::validLocation(QString keyName)
++{
++    if (d->m_locations.contains(keyName)) {
++        return true;
++    }
++    return false;
++}
++
++void UKMETIon::updateWeather(const QString& source)
++{
++    Q_UNUSED(source)
++    return;
++}
++
++#include "ion_bbcukmet.moc"
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_noaa.cpp
+@@ -0,0 +1,594 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for NOAA's National Weather Service XML data */
++
++#include "ion_noaa.h"
++
++class NOAAIon::Private : public QObject
++{
++public:
++    Private() {}
++    ~Private() {}
++
++private:
++    struct XMLMapInfo {
++        QString stateName;
++        QString stationName;
++        QString XMLurl;
++    };
++
++public:
++    // Key dicts
++    QHash<QString, NOAAIon::Private::XMLMapInfo> m_place;
++    QHash<QString, QString> m_locations;
++    QString m_state;
++    QString m_station_name;
++    QString m_xmlurl;
++
++    // Weather information
++    QHash<QString, WeatherData> m_weatherData;
++
++    // Store KIO jobs
++    QMap<KJob *, QXmlStreamReader*> m_jobXml;
++    QMap<KJob *, QString> m_jobList;
++    QXmlStreamReader m_xmlSetup;
++    KUrl *m_url;
++    KIO::TransferJob *m_job;
++
++    bool m_useUTC;  // Ion option: Timezone may be local time or UTC time
++    bool m_useMetric; // Ion option: Units may be Metric or Imperial
++    bool m_windInMeters; // Ion option: Display wind format in meters per second only
++
++    WeatherFormula m_formula;
++};
++
++
++// ctor, dtor
++NOAAIon::NOAAIon(QObject *parent, const QVariantList &args)
++        : IonInterface(parent), d(new Private())
++{
++    Q_UNUSED(args)
++}
++
++NOAAIon::~NOAAIon()
++{
++    // Destroy dptr
++    delete d;
++}
++
++// Get the master list of locations to be parsed
++void NOAAIon::init()
++{
++    // Get the real city XML URL so we can parse this
++    getXMLSetup();
++}
++
++bool NOAAIon::validate(const QString& source) const
++{
++    QHash<QString, QString>::const_iterator it = d->m_locations.find(source);
++    if (it != d->m_locations.end()) {
++        return true;
++    }
++    return false;
++}
++
++bool NOAAIon::updateIonSource(const QString& source)
++{
++    getXMLData(source);
++    return true;
++}
++
++// Parses city list and gets the correct city based on ID number
++void NOAAIon::getXMLSetup()
++{
++    d->m_url = new KUrl("http://www.weather.gov/data/current_obs/index.xml");
++
++    KIO::TransferJob *job = KIO::get(d->m_url->url(), KIO::NoReload, KIO::HideProgressInfo);
++
++    if (job) {
++        connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
++        connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
++    }
++}
++
++// Gets specific city XML data
++void NOAAIon::getXMLData(const QString& source)
++{
++    KUrl url;
++    url = d->m_place[source].XMLurl;
++
++    kDebug() << "URL Location: " << url.url();
++
++    d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
++    d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
++    d->m_jobList.insert(d->m_job, source);
++
++    if (d->m_job) {
++        connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
++                SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
++        connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
++    }
++}
++
++void NOAAIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++    Q_UNUSED(job)
++
++    if (data.isEmpty()) {
++        return;
++    }
++
++    // Send to xml.
++    d->m_xmlSetup.addData(data.data());
++}
++
++void NOAAIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
++{
++
++    if (data.isEmpty() || !d->m_jobXml.contains(job)) {
++        return;
++    }
++
++    // Send to xml.
++    d->m_jobXml[job]->addData(data.data());
++}
++
++void NOAAIon::slotJobFinished(KJob *job)
++{
++    // Dual use method, if we're fetching location data to parse we need to do this first
++    readXMLData(d->m_jobList[job], *d->m_jobXml[job]);
++    d->m_jobList.remove(job);
++    delete d->m_jobXml[job];
++    d->m_jobXml.remove(job);
++}
++
++void NOAAIon::setup_slotJobFinished(KJob *job)
++{
++    Q_UNUSED(job)
++    readXMLSetup();
++    this->setInitialized(true);
++}
++
++void NOAAIon::parseStationID()
++{
++    QString tmp;
++    while (!d->m_xmlSetup.atEnd()) {
++        d->m_xmlSetup.readNext();
++
++        if (d->m_xmlSetup.isEndElement() && d->m_xmlSetup.name() == "station") {
++            break;
++        }
++
++        if (d->m_xmlSetup.isStartElement()) {
++            if (d->m_xmlSetup.name() == "state") {
++                d->m_state = d->m_xmlSetup.readElementText();
++            } else if (d->m_xmlSetup.name() == "station_name") {
++                d->m_station_name= d->m_xmlSetup.readElementText();
++            } else if (d->m_xmlSetup.name() == "xml_url") {
++                d->m_xmlurl = d->m_xmlSetup.readElementText();
++
++                tmp = "noaa:" + d->m_station_name + ", " + d->m_state; // Build the key name.
++                d->m_place[tmp].stateName = d->m_state;
++                d->m_place[tmp].stationName = d->m_station_name;
++	        d->m_place[tmp].XMLurl = d->m_xmlurl;
++
++                d->m_locations[tmp] = tmp;
++            } else {
++                parseUnknownElement(d->m_xmlSetup);
++            }
++        }
++    }
++}
++
++void NOAAIon::parseStationList()
++{
++    while (!d->m_xmlSetup.atEnd()) {
++        d->m_xmlSetup.readNext();
++
++        if (d->m_xmlSetup.isEndElement()) {
++            break;
++        }
++
++        if (d->m_xmlSetup.isStartElement()) {
++            if (d->m_xmlSetup.name() == "station") {
++                parseStationID();
++            } else {
++                parseUnknownElement(d->m_xmlSetup);
++            }
++        }
++    }
++}
++
++// Parse the city list and store into a QMap
++bool NOAAIon::readXMLSetup()
++{
++    while (!d->m_xmlSetup.atEnd()) {
++        d->m_xmlSetup.readNext();
++
++        if (d->m_xmlSetup.isStartElement()) {
++            if (d->m_xmlSetup.name() == "wx_station_index") {
++                parseStationList();
++            }
++        }
++    }
++    return !d->m_xmlSetup.error();
++}
++
++WeatherData NOAAIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
++{
++    data.temperature_C = "N/A";
++    data.temperature_F = "N/A";
++    data.dewpoint_C = "N/A";
++    data.dewpoint_F = "N/A";
++    data.weather = "N/A";
++    data.stationID = "N/A";
++    data.pressure = "N/A";
++    data.visibility = "N/A";
++    data.humidity = "N/A";
++    data.windSpeed = "N/A";
++    data.windGust = "N/A";
++    data.windchill_F = "N/A";
++    data.windchill_C = "N/A";
++    data.heatindex_F = "N/A";
++    data.heatindex_C = "N/A";
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "location") {
++                data.locationName = xml.readElementText();
++            } else if (xml.name() == "station_id") {
++                data.stationID = xml.readElementText();
++            } else if (xml.name() == "observation_time") {
++                data.observationTime = xml.readElementText();
++            } else if (xml.name() == "weather") { 
++                data.weather = xml.readElementText();
++            } else if (xml.name() == "temp_f") {
++                data.temperature_F = xml.readElementText();
++            } else if (xml.name() == "temp_c") {
++                data.temperature_C = xml.readElementText();
++            } else if (xml.name() == "relative_humidity") {
++                data.humidity = xml.readElementText();
++            } else if (xml.name() == "wind_dir") {
++                data.windDirection = xml.readElementText();
++            } else if (xml.name() == "wind_mph") {
++                data.windSpeed = xml.readElementText();
++            } else if (xml.name() == "wind_gust_mph") {
++                data.windGust = xml.readElementText();
++            } else if (xml.name() == "pressure_in") {
++                data.pressure = xml.readElementText();
++            } else if (xml.name() == "dewpoint_f") { 
++                data.dewpoint_F = xml.readElementText();
++            } else if (xml.name() == "dewpoint_c") {
++                data.dewpoint_C = xml.readElementText();
++            } else if (xml.name() == "heat_index_f") {
++                data.heatindex_F = xml.readElementText();
++            } else if (xml.name() == "heat_index_c") {
++                data.heatindex_C = xml.readElementText();
++            } else if (xml.name() == "windchill_f") {
++                data.windchill_F = xml.readElementText();
++            } else if (xml.name() == "windchill_c") {
++                data.windchill_C = xml.readElementText();
++            } else if (xml.name() == "visibility_mi") {
++                data.visibility = xml.readElementText();
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++    return data;
++}
++
++// Parse Weather data main loop, from here we have to decend into each tag pair
++bool NOAAIon::readXMLData(const QString& source, QXmlStreamReader& xml)
++{
++    WeatherData data;
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            if (xml.name() == "current_observation") {
++                data = parseWeatherSite(data, xml);
++            } else {
++                parseUnknownElement(xml);
++            }
++        }
++    }
++
++    d->m_weatherData[source] = data;
++    updateWeather(source);
++    return !xml.error();
++}
++
++// handle when no XML tag is found
++void NOAAIon::parseUnknownElement(QXmlStreamReader& xml)
++{
++
++    while (!xml.atEnd()) {
++        xml.readNext();
++
++        if (xml.isEndElement()) {
++            break;
++        }
++
++        if (xml.isStartElement()) {
++            parseUnknownElement(xml);
++        }
++    }
++}
++
++// User toggleable values set from the dataengine <-> Plasma Applet
++void NOAAIon::option(int option, QVariant value)
++{
++    switch (option) {
++    case IonInterface::UNITS:
++        // Set the Units used (Depends on Ion)
++        if (value.toInt() == KLocale::Metric) {
++            d->m_useMetric = true;
++        }
++        if (value.toInt() == KLocale::Imperial) {
++            d->m_useMetric = false;
++        }
++        break;
++    case IonInterface::TIMEFORMAT:
++        if (value.toBool()) {
++            d->m_useUTC = true;
++        }
++        break;
++    case IonInterface::WINDFORMAT:
++        if (value.toBool()) {
++           d->m_windInMeters = true;
++        } else {
++           d->m_windInMeters = false;
++        }
++        break;
++    }
++}
++
++void NOAAIon::updateWeather(const QString& source)
++{
++    QMap<QString, QString> dataFields;
++    QStringList fieldList;
++
++    setData(source, "Country", this->country(source));
++    setData(source, "Place", this->place(source));
++    setData(source, "Airport Code", this->station(source));
++
++    // Real weather - Current conditions
++    setData(source, "Observations At", this->observationTime(source));
++    setData(source, "Current Conditions", this->condition(source));
++    dataFields = this->temperature(source);
++    setData(source, "Temperature", dataFields["temperature"]);
++
++    if (dataFields["temperature"] != "N/A") {
++        setData(source, "Temperature Unit", dataFields["temperatureUnit"]);
++    }
++
++    // Do we have a comfort temperature? if so display it
++    if (dataFields["comfortTemperature"] != "N/A") {
++        if (d->m_weatherData[source].windchill_F != "NA") {
++            setData(source, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
++        }
++        if (d->m_weatherData[source].heatindex_F != "NA" && d->m_weatherData[source].temperature_F.toInt() != d->m_weatherData[source].heatindex_F.toInt()) {
++            setData(source, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
++        }
++     }
++
++     setData(source, "Dewpoint", this->dewpoint(source));
++     if (this->dewpoint(source) != "N/A") {
++         setData(source, "Dewpoint Unit", dataFields["temperatureUnit"]);
++     }
++ 
++     dataFields = this->pressure(source);
++     setData(source, "Pressure", dataFields["pressure"]);
++
++     if (dataFields["pressure"] != "N/A") {
++         setData(source, "Pressure Unit", dataFields["pressureUnit"]);
++     }
++
++     dataFields = this->visibility(source);
++     setData(source, "Visibility", dataFields["visibility"]);
++
++     if (dataFields["visibility"] != "N/A") {
++         setData(source, "Visibility Unit", dataFields["visibilityUnit"]);
++     }
++
++     setData(source, "Humidity", this->humidity(source));
++
++     dataFields = this->wind(source);
++     setData(source, "Wind Speed", dataFields["windSpeed"]);
++
++     if (dataFields["windSpeed"] != "Calm") {
++         setData(source, "Wind Speed Unit", dataFields["windUnit"]);
++     }
++
++     setData(source, "Wind Gust", dataFields["windGust"]);
++     if (dataFields["windGust"] != "N/A") {
++         setData(source, "Wind Gust Unit", dataFields["windGustUnit"]);
++     }
++
++     setData(source, "Wind Direction", dataFields["windDirection"]);
++
++     setData(source, "Credit", "NOAA National Weather Service");
++}
++
++QString NOAAIon::country(const QString& source)
++{
++    Q_UNUSED(source);
++    return QString("United States of America");
++}
++QString NOAAIon::place(const QString& source)
++{
++    return d->m_weatherData[source].locationName;
++}
++QString NOAAIon::station(const QString& source)
++{
++    return d->m_weatherData[source].stationID;
++}
++
++QString NOAAIon::observationTime(const QString& source)
++{
++    return d->m_weatherData[source].observationTime;
++}
++QString NOAAIon::condition(const QString& source)
++{
++    if (d->m_weatherData[source].weather.isEmpty() || d->m_weatherData[source].weather == "NA") {
++        d->m_weatherData[source].weather = "N/A";
++    }
++    return d->m_weatherData[source].weather;
++}
++
++QString NOAAIon::dewpoint(const QString& source)
++{
++    if (d->m_useMetric) {
++        return QString("%1").arg(d->m_weatherData[source].dewpoint_C);
++    }
++    return QString("%1").arg(d->m_weatherData[source].dewpoint_F);
++}
++
++QString NOAAIon::humidity(const QString& source)
++{
++   if (d->m_weatherData[source].humidity == "NA") {
++       return QString("N/A");
++   } else {
++       return QString("%1%").arg(d->m_weatherData[source].humidity);
++   }
++}
++
++QMap<QString, QString> NOAAIon::visibility(const QString& source)
++{
++    QMap<QString, QString> visibilityInfo;
++    if (d->m_weatherData[source].visibility.isEmpty()) {
++        visibilityInfo.insert("visibility", QString("N/A"));
++        return visibilityInfo;
++    }
++    if (d->m_useMetric) {
++        visibilityInfo.insert("visibility", QString("%1").arg(QString::number(d->m_formula.milesToKM(d->m_weatherData[source].visibility.toFloat()), 'f', 1)));
++        visibilityInfo.insert("visibilityUnit", "km");
++        return visibilityInfo;
++    } 
++    visibilityInfo.insert("visibility", QString("%1").arg(d->m_weatherData[source].visibility));
++    visibilityInfo.insert("visibilityUnit", "mi");
++    return visibilityInfo;
++}
++
++QMap<QString, QString> NOAAIon::temperature(const QString& source)
++{
++    QMap<QString, QString> temperatureInfo;
++    if (d->m_useMetric) {
++        temperatureInfo.insert("temperature", QString("%1").arg(d->m_weatherData[source].temperature_C));
++        temperatureInfo.insert("temperatureUnit", QString("%1C").arg(QChar(176)));
++    } else {
++        temperatureInfo.insert("temperature", QString("%1").arg(d->m_weatherData[source].temperature_F));
++        temperatureInfo.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
++    }
++    temperatureInfo.insert("comfortTemperature", "N/A");
++
++    if (d->m_weatherData[source].heatindex_F != "NA" && d->m_weatherData[source].windchill_F == "NA") {
++        if (d->m_useMetric) {
++            temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].heatindex_C);
++        } else {
++            temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].heatindex_F);
++        }
++    }
++    if (d->m_weatherData[source].windchill_F != "NA" && d->m_weatherData[source].heatindex_F == "NA") {
++        if (d->m_useMetric) {
++            temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].windchill_C);
++        } else {
++            temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].windchill_F);
++        }
++    }
++
++    return temperatureInfo;
++}
++
++QMap<QString, QString> NOAAIon::pressure(const QString& source)
++{
++    QMap<QString, QString> pressureInfo;
++    if (d->m_weatherData[source].pressure.isEmpty()) {
++        pressureInfo.insert("pressure", "N/A");
++        return pressureInfo;
++    } 
++    if (d->m_useMetric) {
++        pressureInfo.insert("pressure", QString("%1").arg(QString::number(d->m_formula.inchesToKilopascals(d->m_weatherData[source].pressure.toFloat()), 'f', 1)));
++        pressureInfo.insert("pressureUnit", "kPa");
++    } else {
++        pressureInfo.insert("pressure", QString("%1").arg(d->m_weatherData[source].pressure));
++        pressureInfo.insert("pressureUnit", "in");
++    }
++    return pressureInfo;
++}
++
++QMap<QString, QString> NOAAIon::wind(const QString& source)
++{
++    QMap<QString, QString> windInfo;
++
++    // May not have any winds
++    if (d->m_weatherData[source].windSpeed == "NA") {
++        windInfo.insert("windSpeed", "Calm");
++    } else {
++        if (d->m_useMetric) {
++            if (d->m_windInMeters) {
++                windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_formula.milesToMS(d->m_weatherData[source].windSpeed.toFloat()), 'f', 2)));
++                windInfo.insert("windUnit", "m/s");
++            } else {
++                windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_formula.milesToKM(d->m_weatherData[source].windSpeed.toFloat()), 'f', 1)));
++                windInfo.insert("windUnit", "km/h");
++            }
++        } else {
++            windInfo.insert("windSpeed", QString("%1").arg(QString::number(d->m_weatherData[source].windSpeed.toFloat(), 'f', 1)));
++            windInfo.insert("windUnit", "mph");
++        }
++    }
++
++    // May not always have gusty winds
++    if (d->m_weatherData[source].windGust == "NA") {
++        windInfo.insert("windGust", "N/A");
++    } else {
++        if (d->m_useMetric) {
++            if (d->m_windInMeters) {
++                windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_formula.milesToMS(d->m_weatherData[source].windGust.toFloat()), 'f', 2)));
++                windInfo.insert("windGustUnit", "m/s");
++            } else {
++                windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_formula.milesToKM(d->m_weatherData[source].windGust.toFloat()), 'f', 1)));
++                windInfo.insert("windGustUnit", "km/h");
++            }
++        } else {
++            windInfo.insert("windGust", QString("%1").arg(QString::number(d->m_weatherData[source].windGust.toFloat(), 'f', 1)));
++            windInfo.insert("windGustUnit", "mph");
++        }
++    }
++
++    if (d->m_weatherData[source].windDirection.isEmpty()) {
++        windInfo.insert("windDirection", "N/A");
++    } else {
++        windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
++    }
++    return windInfo;
++}
++
++#include "ion_noaa.moc"
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion-envcan.desktop
+@@ -0,0 +1,31 @@
++[Desktop Entry]
++Name=Environment Canada
++Name[el]=Περιβάλλον Καναδά
++Name[km]=បរិស្ថាន​ប្រទេស​កាណាដា
++Name[ko]=캐나다 환경부
++Name[nds]=Ümwelt Kanada
++Name[x-test]=xxEnvironment Canadaxx
++Name[zh_CN]=加拿大环境
++Comment=XML Data from Environment Canada
++Comment[el]=Δεδομένα XML για το περιβάλλον του Καναδά
++Comment[et]=Environment Canada XML-andmed
++Comment[ga]=Sonraí XML ó Environment Canada
++Comment[ja]=Environment Canada の XML データ
++Comment[kk]=Environment Canada-ның XML дерегі
++Comment[km]=ទិន្នន័យ XML ពី​បរិស្ថាន​ប្រទេស​កាណាដា
++Comment[ko]=캐나다 환경부의 XML 데이터
++Comment[nb]=XML-data fra Environment Canada
++Comment[nds]=XML-Daten vun Ümwelt Kanada
++Comment[nl]=XML-gegevens van Environment Canada
++Comment[nn]=XML-data frå Environment Canada
++Comment[pt]=Dados em XML do Environment Canada
++Comment[pt_BR]=Dados em XML do Environment Canada
++Comment[sv]=XML-data från Environment Canada
++Comment[x-test]=xxXML Data from Environment Canadaxx
++Comment[zh_CN]=来自加拿大环境的 XML 数据
++Comment[zh_TW]=從 Environment Canada 來的 XML 資料
++ServiceTypes=WeatherEngine/Ion
++Type=Service
++Icon=noneyet
++X-KDE-Library=ion_envcan
++X-IonName=envcan
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_envcan.h
+@@ -0,0 +1,212 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for Environment Canada XML data */
++
++#ifndef _ION_ENVCAN_H_
++#define _ION_ENVCAN_H_
++
++#include <QtXml/QXmlStreamReader>
++#include <QtCore/QStringList>
++#include <QDebug>
++#include <kurl.h>
++#include <kio/job.h>
++#include <kio/scheduler.h>
++#include <kdemacros.h>
++#include <plasma/dataengine.h>
++#include "ion.h"
++#include "weather_formula.h"
++
++class WeatherData
++{
++
++public:
++    // Warning info, can have more than one, especially in Canada, eh? :)
++    struct WarningInfo {
++        QString url;
++        QString type;
++        QString priority;
++        QString description;
++        QString timestamp;
++    };
++
++    // Five day forecast
++    struct ForecastInfo {
++        QString forecastPeriod;
++        QString forecastSummary;
++        QString shortForecast;
++
++        QString forecastTempHigh;
++        QString forecastTempLow;
++        QString popPrecent;
++        QString windForecast;
++
++        QString precipForecast;
++        QString precipType;
++        QString precipTotalExpected;
++        int forecastHumidity;
++    };
++
++    QString countryName;
++    QString longTerritoryName;
++    QString shortTerritoryName;
++    QString cityName;
++    QString regionName;
++    QString stationID;
++
++    // Current observation information.
++    QString obsTimestamp;
++    QString condition;
++    QString temperature;
++    QString dewpoint;
++
++    // In winter windchill, in summer, humidex
++    QString comforttemp;
++
++    float pressure;
++    QString pressureTendency;
++
++    float visibility;
++    QString humidity;
++
++    QString windSpeed;
++    QString windGust;
++    QString windDirection;
++
++    QVector <WeatherData::WarningInfo *> warnings;
++
++    QString normalHigh;
++    QString normalLow;
++
++    QString forecastTimestamp;
++
++    QString UVIndex;
++    QString UVRating;
++
++    // 5 day Forecast
++    QVector <WeatherData::ForecastInfo *> forecasts;
++
++    // Historical data from previous day.
++    QString prevHigh;
++    QString prevLow;
++    QString prevPrecipType;
++    QString prevPrecipTotal;
++
++    // Almanac info
++    QString sunriseTimestamp;
++    QString sunsetTimestamp;
++    QString moonriseTimestamp;
++    QString moonsetTimestamp;
++
++    // Historical Records
++    float recordHigh;
++    float recordLow;
++    float recordRain;
++    float recordSnow;
++};
++
++class KDE_EXPORT EnvCanadaIon : public IonInterface
++{
++    Q_OBJECT
++
++public:
++    EnvCanadaIon(QObject *parent, const QVariantList &args);
++    ~EnvCanadaIon();
++    void init();  // Setup the city location, fetching the correct URL name.
++    bool updateIonSource(const QString& source); // Sync data source with Applet
++    void option(int option, QVariant value);
++    void updateWeather(const QString& source);
++
++protected slots:
++    void setup_slotDataArrived(KIO::Job *, const QByteArray &);
++    void setup_slotJobFinished(KJob *);
++
++    void slotDataArrived(KIO::Job *, const QByteArray &);
++    void slotJobFinished(KJob *);
++
++private:
++    /* Environment Canada Methods - Internal for Ion */
++
++    // Place information
++    QString country(const QString& source);
++    QString territory(const QString& source);
++    QString city(const QString& source);
++    QString region(const QString& source);
++    QString station(const QString& source);
++
++    // Current Conditions Weather info
++    QString observationTime(const QString& source);
++    QMap<QString, QString> warnings(const QString& source);
++    QString condition(const QString& source);
++    QMap<QString, QString> temperature(const QString& source);
++    QString dewpoint(const QString& source);
++    QString humidity(const QString& source);
++    QMap<QString, QString> visibility(const QString& source);
++    QMap<QString, QString> pressure(const QString& source);
++    QMap<QString, QString> wind(const QString& source);
++    QMap<QString, QString> regionalTemperatures(const QString& source);
++    QMap<QString, QString> uvIndex(const QString& source);
++    QVector<QString> forecasts(const QString& source);
++    QMap<QString, QString> yesterdayWeather(const QString& source);
++    QMap<QString, QString> sunriseSet(const QString& source);
++    QMap<QString, QString> moonriseSet(const QString& source);
++    QMap<QString, QString> weatherRecords(const QString& source);
++
++    // Load and Parse the place XML listing
++    void getXMLSetup(void);
++    bool readXMLSetup(void);
++
++    // Load and parse the specific place(s)
++    void getXMLData(const QString& source);
++    bool readXMLData(const QString& source, QXmlStreamReader& xml);
++
++    // Check if place specified is valid or not
++    QString validate(const QString& source);
++
++    // Catchall for unknown XML tags
++    void parseUnknownElement(QXmlStreamReader& xml);
++
++    // Parse weather XML data
++    WeatherData parseWeatherSite(WeatherData& data, QXmlStreamReader& xml);
++    void parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WarningInfo* warning = NULL);
++    void parseLocations(WeatherData& data, QXmlStreamReader& xml);
++    void parseConditions(WeatherData& data, QXmlStreamReader& xml);
++    void parseWarnings(WeatherData& data, QXmlStreamReader& xml);
++    void parseWindInfo(WeatherData& data, QXmlStreamReader& xml);
++    void parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml);
++    void parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml);
++    void parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo* forecast);
++    void parseShortForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml);
++    void parseForecastTemperatures(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml);
++    void parseWindForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml);
++    void parsePrecipitationForecast(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml);
++    void parsePrecipTotals(WeatherData::ForecastInfo* forecast, QXmlStreamReader& xml);
++    void parseUVIndex(WeatherData& data, QXmlStreamReader& xml);
++    void parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml);
++    void parseAstronomicals(WeatherData& data, QXmlStreamReader& xml);
++    void parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml);
++
++private:
++    class Private;
++    Private *const d;
++};
++
++K_EXPORT_PLASMA_ION(envcan, EnvCanadaIon)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/weather_formula.cpp
+@@ -0,0 +1,89 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++#include <math.h>
++#include "weather_formula.h"
++
++WeatherFormula::WeatherFormula()
++{
++}
++
++WeatherFormula::~WeatherFormula()
++{
++}
++
++float WeatherFormula::celsiusToF(float temperature) const
++{
++    return (temperature * 9 / 5 + 32);
++}
++
++float WeatherFormula::fahrenheitToC(float temperature) const
++{
++    return (temperature - 32) * 5 / 9;
++}
++
++float WeatherFormula::milesToKM(float miles) const
++{
++    return (1.609344 * miles);
++}
++
++float WeatherFormula::kilometersToMI(float km) const
++{
++    return (0.621371192 * km);
++}
++
++float WeatherFormula::kilopascalsToInches(float kpa) const
++{
++    return ((0.02952997 * kpa) * 10);
++}
++
++float WeatherFormula::inchesToKilopascals(float inches) const
++{
++    return (inches * 3.386389);
++}
++
++float WeatherFormula::centimetersToIN(float cm) const 
++{
++    return (cm * 0.393700787);
++}
++
++float WeatherFormula::inchesToCM(float inch) const
++{
++    return (inch * 2.54);
++}
++
++float WeatherFormula::millimetersToIN(float mm) const
++{
++    return (mm * 0.0393700787);
++}
++
++float WeatherFormula::inchesToMM(float inch) const
++{
++    return (inch * 25.4);
++}
++
++float WeatherFormula::kilometersToMS(float km) const
++{
++    return (km * 0.277778);
++}
++
++float WeatherFormula::milesToMS(float miles) const
++{
++    return (miles * 0.44704);
++}
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion.cpp
+@@ -0,0 +1,101 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++#include "ion.h"
++#include "ion.moc"
++
++class IonInterface::Private : public QObject
++{
++public:
++    Private(IonInterface *i)
++            : ion(i),
++              initialized(false)
++    {}
++
++    int ref;
++    IonInterface *ion;
++    bool valid;
++    bool initialized;
++};
++
++IonInterface::IonInterface(QObject *parent)
++        : Plasma::DataEngine(parent),
++        d(new Private(this))
++{
++}
++
++// Increment reference counter
++void IonInterface::ref()
++{
++    ++d->ref;
++}
++
++// Decrement reference counter
++void IonInterface::deref()
++{
++    --d->ref;
++}
++
++// Check if Ion is used
++bool IonInterface::isUsed() const
++{
++    return d->ref != 0;
++}
++
++// Check if Ion is valid - Not used yet
++bool IonInterface::isValid() const
++{
++    return d->valid;
++}
++
++bool IonInterface::sourceRequested(const QString &source)
++{
++    setData(source, Plasma::DataEngine::Data());
++   
++    if (d->initialized) {
++        this->updateSource(source);
++    }
++
++    return true;
++}
++
++bool IonInterface::updateSource(const QString& source) 
++{
++     kDebug() << "SOURCE IS = " << source; 
++     if (d->initialized) {
++         if(this->updateIonSource(source)) {
++            return true;
++         } else {
++            return false;
++         }
++     }
++
++     return false; 
++}
++
++void IonInterface::setInitialized(const bool initialized)
++{
++    d->initialized = initialized;
++
++    if (d->initialized) {
++        foreach (const QString &source, sources()) {
++            updateSource(source);
++        }
++    }
++}
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion-bbcukmet.desktop
+@@ -0,0 +1,42 @@
++[Desktop Entry]
++Name=BBC Weather from UK MET Office
++Name[el]=Καιρός του BBC από το γραφείο UK MET
++Name[et]=BBC ilmateade Briti ilmateenistusest
++Name[ga]=Aimsir BBC ó Oifig UK MET
++Name[ja]=英国 Met Office の BBC Weather
++Name[kk]=UK MET Оффистің BBC ауа райы болжамы
++Name[km]=អាកាសធាតុ BBC ពី​ការិយាល័យ UK MET
++Name[ko]=영국 MET 사무소의 BBC 날씨
++Name[nb]=BBC vær fra det britiske meteorologi-kontoret
++Name[nds]=BBC-Weder vun't engelsche Wederkunn-Kontoor
++Name[nl]=BBC Weather van UK MET Office
++Name[nn]=BBC-vêr frå UK MET Office
++Name[pt]=Meteorologia da BBC do Escritório MET na GB
++Name[pt_BR]=BBC Weather do Escritório MET no Reino Unido
++Name[sv]=BBC-väder från brittiska meteorologiska departementet
++Name[x-test]=xxBBC Weather from UK MET Officexx
++Name[zh_CN]=来自英国 MET 办公室来的 BBC 天气报告
++Name[zh_TW]=BBC 天氣報告,從 UK MET 辦公室來
++Comment=XML Data from the UK MET Office
++Comment[el]=Δεδομένα XML από το γραφείο UK MET
++Comment[et]=Briti ilmateenistuse XML-andmed
++Comment[ga]=Sonraí XML ó Oifig UK MET
++Comment[ja]=英国 Met Office の XML データ
++Comment[kk]=UK MET Оффстің XML дерегі
++Comment[km]=ទិន្នន័យ XML ពី​ការិយាល័យ UK MET
++Comment[ko]=영국 MET 사무소의 XML 데이터
++Comment[nb]=XML-data fra det britiske meteorologi-kontoret
++Comment[nds]=XML-Daten vun't engelsche Wederkunn-Kontoor
++Comment[nl]=XML-gegevens van UK MET Office
++Comment[nn]=XML-data frå UK MET Office
++Comment[pt]=Dados em XML do Escritório MET na GB
++Comment[pt_BR]=Dados em XML do Escritório MET no Reino Unido
++Comment[sv]=XML-data från brittiska meteorologiska departementet
++Comment[x-test]=xxXML Data from the UK MET Officexx
++Comment[zh_CN]=来自英国 MET 办公室来的 XML 数据
++Comment[zh_TW]=從 UK MET 辦公室來的 XML 資料
++ServiceTypes=WeatherEngine/Ion
++Type=Service
++Icon=noneyet
++X-KDE-Library=ion_bbcukmet
++X-IonName=bbcukmet
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_bbcukmet.h
+@@ -0,0 +1,90 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for BBC Weather from UKMET Office */
++
++#ifndef _ION_UKMET_H
++#define _ION_UKMET_H
++
++#include <QtXml/QXmlStreamReader>
++#include <QtCore/QStringList>
++#include <QDebug>
++#include <kurl.h>
++#include <kio/job.h>
++#include <kio/scheduler.h>
++#include <kdemacros.h>
++#include <plasma/dataengine.h>
++#include "ion.h"
++#include "weather_formula.h"
++
++class WeatherData
++{
++
++public:
++    QString title;
++
++    // Current observation information.
++    QString conditionTime;
++    QString weather;
++    QString observations;
++};
++
++class KDE_EXPORT UKMETIon : public IonInterface
++{
++    Q_OBJECT
++
++public:
++    UKMETIon(QObject *parent, const QVariantList &args);
++    ~UKMETIon();
++    void init();  // Setup the city location, fetching the correct URL name.
++    bool updateIonSource(const QString& source);
++    void updateWeather(const QString& source); // Sync data source with Applet
++    void option(int option, QVariant value);
++
++protected slots:
++    void slotDataArrived(KIO::Job *, const QByteArray &);
++    void slotJobFinished(KJob *);
++    void forecast_slotDataArrived(KIO::Job *, const QByteArray &);
++    void forecast_slotJobFinished(KJob *);
++
++private:
++    /* UKMET Methods - Internal for Ion */
++
++    // Load and Parse the place search XML listings
++    void searchPlace(const QString& key);
++    void cachedLocation(const QString& key);
++    bool readSearchXMLData(const QString& key, QXmlStreamReader& xml);
++    void parseSearchLocations(const QString& key, QXmlStreamReader& xml);
++    bool validLocation(QString key);
++
++    // Observation parsing methods
++    bool readObservationXMLData(QString &key, QXmlStreamReader& xml);
++    void parsePlaceObservation(WeatherData& data, QXmlStreamReader& xml);
++    void parseWeatherChannel(WeatherData& data, QXmlStreamReader& xml);
++    void parseWeatherObservation(WeatherData& data, QXmlStreamReader& xml);
++    void parseUnknownElement(QXmlStreamReader& xml);
++
++private:
++    class Private;
++    Private *const d;
++};
++
++K_EXPORT_PLASMA_ION(bbcukmet, UKMETIon)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion-noaa.desktop
+@@ -0,0 +1,41 @@
++[Desktop Entry]
++Name=NOAA's National Weather Service
++Name[el]=Υπηρεσία καιρού NOAA
++Name[et]=NOAA riiklik ilmateenistus
++Name[ja]=NOAA (アメリカ海洋大気圏局) National Weather Service
++Name[kk]=NOAA Ұлттық ауа райы қызметі
++Name[km]=សេវា​អាកាសធាតុ​ជាតិ​របស់ NOAA
++Name[ko]=NOAA 미국 기상 서비스
++Name[nb]=NOAAs nasjonale værtjeneste
++Name[nds]=Wederdeenst vun't US-Ozeaankunn- un Wederamt
++Name[nl]=NOAA's nationale weerdienst
++Name[nn]=NOAAs amerikanske vêrteneste
++Name[pt]=Serviço Meteorológico Nacional da NOAA
++Name[pt_BR]=Serviço Meteorológico Nacional da NOAA
++Name[sv]=NOAA:s nationella vädertjänst
++Name[x-test]=xxNOAA's National Weather Servicexx
++Name[zh_CN]=NOAA 的 国家天气服务
++Name[zh_TW]=NOAA 的國家天氣服務
++Comment=XML Data from NOAA's National Weather Service
++Comment[el]=Δεδομένα XML από την υπηρεσία καιρού NOAA
++Comment[et]=NOAA riikliku ilmateenistuse XML-andmed
++Comment[it]=Dati XML dal NOAA (National Weather Service)
++Comment[ja]=NOAA (アメリカ海洋大気圏局) National Weather Service の XML データ
++Comment[kk]=NOAA Ұлттық ауа райы қызметінің XML дерегі
++Comment[km]=ទិន្នន័យ XML ពី​សេវា​អាកាសធាតុ​ជាតិ​របស់ NOAA
++Comment[ko]=NOAA 미국 기상 서비스의 XML 데이터
++Comment[nb]=XML-data fra NOAAs nasjonale værtjeneste
++Comment[nds]=XML-Daten vun't US-Ozeaankunn- un Wederamt
++Comment[nl]=XML-gegevens van NOAA's nationale weerdienst
++Comment[nn]=XML-data frå NOAAs amerikanske vêrteneste
++Comment[pt]=Dados em XML do Serviço Meteorológico Nacional da NOAA
++Comment[pt_BR]=Dados em XML do Serviço Meteorológico Nacional da NOAA
++Comment[sv]=XML-data från NOAA:s nationella vädertjänst
++Comment[x-test]=xxXML Data from NOAA's National Weather Servicexx
++Comment[zh_CN]=来自 NOAA 的 国家天气服务的 XML 数据
++Comment[zh_TW]=從 NOAA 的國家天氣服務來的 XML 資料
++ServiceTypes=WeatherEngine/Ion
++Type=Service
++Icon=noneyet
++X-KDE-Library=ion_noaa
++X-IonName=noaa
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion_noaa.h
+@@ -0,0 +1,128 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Ion for NOAA's National Weather Service XML data */
++
++#ifndef _ION_NOAA_H
++#define _ION_NOAA_H
++
++#include <QtXml/QXmlStreamReader>
++#include <QtCore/QStringList>
++#include <QDebug>
++#include <kurl.h>
++#include <kio/job.h>
++#include <kio/scheduler.h>
++#include <kdemacros.h>
++#include <plasma/dataengine.h>
++#include "ion.h"
++#include "weather_formula.h"
++
++class WeatherData
++{
++
++public:
++    //QString countryName; // USA
++    QString locationName;
++    QString stationID;
++    QString stateName;
++
++    // Current observation information.
++    QString observationTime;
++    QString weather;
++    QString temperature_F;
++    QString temperature_C;
++    QString humidity;
++    QString windString;
++    QString windDirection;
++    QString windSpeed; // Float value
++    QString windGust; // Float value
++    QString pressure; 
++    QString dewpoint_F;
++    QString dewpoint_C;
++    QString heatindex_F;
++    QString heatindex_C;
++    QString windchill_F;
++    QString windchill_C;
++    QString visibility;
++};
++
++class KDE_EXPORT NOAAIon : public IonInterface
++{
++    Q_OBJECT
++
++public:
++    NOAAIon(QObject *parent, const QVariantList &args);
++    ~NOAAIon();
++    void init(void);  // Setup the city location, fetching the correct URL name.
++    void option(int option, QVariant value);
++    bool updateIonSource(const QString& source); // Sync data source with Applet
++    void updateWeather(const QString& source);
++
++protected slots:
++    void setup_slotDataArrived(KIO::Job *, const QByteArray &);
++    void setup_slotJobFinished(KJob *);
++
++    void slotDataArrived(KIO::Job *, const QByteArray &);
++    void slotJobFinished(KJob *);
++
++private:
++    /* NOAA Methods - Internal for Ion */
++
++    // Place information
++    QString country(const QString& source);
++    QString place(const QString& source);
++    QString station(const QString& source);
++
++    // Current Conditions Weather info
++    QString observationTime(const QString& source);
++    QString condition(const QString& source);
++    QMap<QString, QString> temperature(const QString& source);
++    QString dewpoint(const QString& source);
++    QString humidity(const QString& source);
++    QMap<QString, QString> visibility(const QString& source);
++    QMap<QString, QString> pressure(const QString& source);
++    QMap<QString, QString> wind(const QString& source);
++
++    // Load and Parse the place XML listing
++    void getXMLSetup(void);
++    bool readXMLSetup(void);
++
++    // Load and parse the specific place(s)
++    void getXMLData(const QString& source);
++    bool readXMLData(const QString& source, QXmlStreamReader& xml);
++
++    // Check if place specified is valid or not
++    bool validate(const QString& source) const;
++
++    // Catchall for unknown XML tags
++    void parseUnknownElement(QXmlStreamReader& xml);
++
++    // Parse weather XML data
++    WeatherData parseWeatherSite(WeatherData& data, QXmlStreamReader& xml);
++    void parseStationID(void);
++    void parseStationList(void);
++
++private:
++    class Private;
++    Private *const d;
++};
++
++K_EXPORT_PLASMA_ION(noaa, NOAAIon)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/weather_formula.h
+@@ -0,0 +1,49 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++/* Meteorological formula class */
++
++#ifndef _WEATHERFORMULA_H
++#define _WEATHERFORMULA_H
++
++#include <kdemacros.h>
++
++class KDE_EXPORT WeatherFormula
++{
++public:
++    WeatherFormula();
++    ~WeatherFormula();
++    // Convert Temperatures, pressures
++    float celsiusToF(float temperature) const;
++    float fahrenheitToC(float temperature) const;
++    float milesToKM(float miles) const;
++    float kilometersToMI(float km) const;
++    float kilopascalsToInches(float kpa) const;
++    float inchesToKilopascals(float inches) const;
++    float centimetersToIN(float cm) const;
++    float inchesToCM(float inch) const;
++    float millimetersToIN(float mm) const;
++    float inchesToMM(float inch) const;
++
++    // Winds measured in meters per second
++    float kilometersToMS(float km) const;
++    float milesToMS(float miles) const;
++};
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/ion.h
+@@ -0,0 +1,114 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++#ifndef _ION_H
++#define _ION_H
++
++#include <QObject>
++#include <kdemacros.h>
++#include <KGenericFactory>
++#include <plasma/dataengine.h>
++
++/**
++* This is the base class to be used to implement new ions for the WeatherEngine.
++* The idea is that you can have multiple ions which provide weather information from different services to the engine from which an applet will request the data from.
++* 
++* Basically an ion is a Plasma::DataEngine, which is queried by the WeatherEngine instead of some applet.
++*/
++class KDE_EXPORT IonInterface : public Plasma::DataEngine
++{
++    Q_OBJECT
++public:
++    typedef QHash<QString, IonInterface*> IonDict; // Define Dict as a QHash for Ions
++
++    /**
++    * Constructor for the ion
++    */
++    IonInterface(QObject *parent = 0);
++    /**
++    * Destructor for the ion
++    */
++    virtual ~IonInterface() {}
++
++    /**
++    * Reimplement to do the initialization of the ion.
++    * For example fetching the list of available cities or weather data sources should be fetched here.
++    */
++    virtual void init(void) = 0;
++
++    /**
++    * Increment ion counter. This is used to watch if the ion is being used.
++    */
++    void ref();
++
++    /**
++    * Decrement ion counter.
++    */
++    void deref();
++
++    /**
++    * Returns whether the ion is being used.
++    * @return true if the ion is being used, false otherwise
++    */
++    bool isUsed() const;
++
++    /**
++    * Returns whether the ion is valid. Not used for now.
++    * @return true if the ion is valid.
++    */
++    bool isValid() const;
++
++    enum ionOptions { UNITS, TIMEFORMAT, WINDFORMAT };
++    /**
++    * Reimplement to set the wanted options for the ion such as unit and time, and wind speed formats.
++    */
++    virtual void option(int option, QVariant value) = 0;
++
++public slots:
++    bool updateSource(const QString& source);
++
++protected:
++    /**
++     * Call this method to flush waiting source requests that may be pending
++     * initialization
++     *
++     * @arg initialized whether or not the ion is currently ready to fetch data
++     */
++    void setInitialized(const bool initialized);
++
++    /**
++     * reimplemented from DataEngine
++     */
++    bool sourceRequested(const QString &name);
++
++    /**
++     * Reimplement to fetch the data from the ion
++     * 
++     */
++    virtual bool updateIonSource(const QString &name) = 0;
++   
++private:
++    class Private;
++    Private* const d;
++};
++
++#define K_EXPORT_PLASMA_ION(name, classname) \
++K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
++K_EXPORT_PLUGIN(factory("ion_" #name))
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/weather_ion.desktop
+@@ -0,0 +1,24 @@
++[Desktop Entry]
++Encoding=UTF-8
++Type=ServiceType
++X-KDE-ServiceType=WeatherEngine/Ion
++
++Comment=WeatherEngine Ion
++Comment[el]=Μηχανή καιρού Ion
++Comment[ja]=WeatherEngine イオン
++Comment[kk]=Ауа райы болжау қызметтер
++Comment[km]=ម៉ាស៊ីន​ស្វែងរក​អាកាសធាតុ lon
++Comment[ko]=날씨 엔진 Ion
++Comment[nb]=Værmotor Ion
++Comment[nds]=Ion-Wederkarn
++Comment[nl]=Weer-engine Ion
++Comment[nn]=Vêrmotor Ion
++Comment[pt]=Motor Meteorológico Ion
++Comment[pt_BR]=Motor Meteorológico Ion
++Comment[sv]=Vädergränssnittsjon
++Comment[x-test]=xxWeatherEngine Ionxx
++Comment[zh_CN]=天气引擎离子
++Comment[zh_TW]=天氣引擎 Ion
++
++[PropertyDef::X-IonName]
++Type=QString
+--- /dev/null
++++ b/plasma/dataengines/weather/ions/CMakeLists.txt
+@@ -0,0 +1,20 @@
++SET (ion_envcan_SRCS ion_envcan.cpp)
++SET (ion_noaa_SRCS ion_noaa.cpp)
++SET (ion_bbcukmet_SRCS ion_bbcukmet.cpp)
++
++kde4_add_plugin(ion_envcan ${ion_envcan_SRCS})
++kde4_add_plugin(ion_noaa ${ion_noaa_SRCS})
++kde4_add_plugin(ion_bbcukmet ${ion_bbcukmet_SRCS})
++
++TARGET_LINK_LIBRARIES (ion_envcan ${KDE4_KDEUI_LIBS} plasma weather_ion)
++TARGET_LINK_LIBRARIES (ion_noaa ${KDE4_KDEUI_LIBS} plasma weather_ion)
++TARGET_LINK_LIBRARIES (ion_bbcukmet ${KDE4_KDEUI_LIBS} plasma weather_ion)
++
++INSTALL (TARGETS ion_envcan DESTINATION ${PLUGIN_INSTALL_DIR})
++INSTALL (TARGETS ion_noaa DESTINATION ${PLUGIN_INSTALL_DIR})
++INSTALL (TARGETS ion_bbcukmet DESTINATION ${PLUGIN_INSTALL_DIR})
++
++INSTALL (FILES weather_ion.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
++INSTALL (FILES ion-envcan.desktop DESTINATION ${SERVICES_INSTALL_DIR})
++INSTALL (FILES ion-noaa.desktop DESTINATION ${SERVICES_INSTALL_DIR})
++INSTALL (FILES ion-bbcukmet.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+--- /dev/null
++++ b/plasma/dataengines/weather/weatherengine.h
+@@ -0,0 +1,69 @@
++/***************************************************************************
++ *   Copyright (C) 2007 by Shawn Starr <shawn.starr at rogers.com>            *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
++ ***************************************************************************/
++
++#ifndef _WEATHER_ENGINE_H_
++#define _WEATHER_ENGINE_H_
++
++#include <KService>
++#include <KGenericFactory>
++#include <plasma/dataengine.h>
++#include "ions/ion.h"
++
++class QTimer;
++
++/* DataEngine class
++   - Loads Ions (data sources from various inputs).
++   - Handles interaction from Applet <-> Dataengine
++*/
++class WeatherEngine : protected Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    // ctor, dtor
++    WeatherEngine(QObject *parent, const QVariantList &args);
++    ~WeatherEngine();
++
++    // Ion plugin methods
++    IonInterface* Ion(const QString& name) const;  // Returns an Ion instance.
++    IonInterface* loadIon(const KService::Ptr& service);    // Loads an Ion plugin.
++    void unloadIon(const QString& name);           // Unloads an Ion plugin.
++    KService::List knownIons();                // Returns a list of Ion plugin names.
++
++protected:
++    // dataEngine method - We use it to communicate to the Ion plugins to set the data sources
++    bool sourceRequested(const QString &source);
++
++protected slots:
++    // SLOT: trigger to indicate new data is available from an Ion. There are two modes.
++    // When using a timer no ion is specified, otherwise when loading an ion an ion is
++    // specified.
++    void updated(const QString& source, Plasma::DataEngine::Data data);
++    void newIonSource(const QString& source);
++    void removeIonSource(const QString& source);
++    bool updateSource(const QString& source);
++
++private:
++    class Private;
++    Private *const d;
++};
++
++K_EXPORT_PLASMA_DATAENGINE(weather, WeatherEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/weather/CMakeLists.txt
+@@ -0,0 +1,13 @@
++ADD_SUBDIRECTORY(ions)
++
++SET (ionlib_SRCS ions/ion.cpp ions/weather_formula.cpp)
++kde4_add_library (weather_ion SHARED ${ionlib_SRCS})
++TARGET_LINK_LIBRARIES (weather_ion ${KDE4_KIO_LIBS} plasma)
++set_target_properties(weather_ion PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION})
++INSTALL (TARGETS weather_ion DESTINATION ${LIB_INSTALL_DIR})
++
++SET(weather_SRCS weatherengine.cpp)
++kde4_add_plugin(plasma_engine_weather ${weather_SRCS})
++TARGET_LINK_LIBRARIES (plasma_engine_weather ${KDE4_KIO_LIBS} plasma weather_ion)
++INSTALL (TARGETS plasma_engine_weather DESTINATION ${PLUGIN_INSTALL_DIR})
++INSTALL (FILES plasma-engine-weather.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+--- /dev/null
++++ b/plasma/dataengines/weather/README
+@@ -0,0 +1 @@
++Plasma Weather dataengine
+--- /dev/null
++++ b/plasma/dataengines/hotplug/plasma-engine-hotplug.desktop
+@@ -0,0 +1,17 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Hotplug Event Data Engine
++Name[et]=Hotplug-sündmuste andmete mootor
++Name[ja]=Hotplug イベントデータエンジン
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​ព្រឹត្តិការណ៍​ដោតដើរ​
++Name[nds]=Tokoppel-Hanteerkarn
++Name[nl]=Hotplug-gebeurtenis (gegevensengine)
++Name[pt]=Motor de Dados de Eventos do Hotplug
++Name[pt_BR]=Mecanismo de Dados de Eventos do Hotplug
++Name[sv]=Datagränssnitt för inkopplingshändelse
++Name[zh_TW]=熱插拔事件資料引擎
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=notifier
++X-KDE-Library=plasma_engine_hotplug
++X-EngineName=hotplug
+--- /dev/null
++++ b/plasma/dataengines/hotplug/hotplugengine.cpp
+@@ -0,0 +1,104 @@
++/*
++ *   Copyright (C) 2007 Menard Alexis <darktears31 at gmail.com>
++ *
++ * This program is free software you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++*/
++
++#include "hotplugengine.h"
++
++#include <KConfigGroup>
++#include <KDebug>
++#include <KLocale>
++#include <KStandardDirs>
++#include <KDesktopFile>
++#include "plasma/datacontainer.h"
++
++//solid specific includes
++#include <solid/devicenotifier.h>
++#include <solid/device.h>
++#include <solid/deviceinterface.h>
++#include <solid/predicate.h>
++
++
++
++HotplugEngine::HotplugEngine(QObject* parent, const QVariantList& args)
++    : Plasma::DataEngine(parent)
++{
++    Q_UNUSED(args)
++    connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString &)),
++            this, SLOT(onDeviceAdded(const QString &)));
++    connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString &)),
++            this, SLOT(onDeviceRemoved(const QString &)));
++    files = KGlobal::dirs()->findAllResources("data", "solid/actions/*.desktop");
++    //kDebug() <<files.size();
++    new_device=false;
++}
++
++HotplugEngine::~HotplugEngine()
++{
++
++}
++
++void HotplugEngine::onDeviceAdded(const QString &udi)
++{
++    Solid::Device device(udi);
++
++    QStringList interestingDesktopFiles;
++    //search in all desktop configuration file if the device inserted is a correct device
++    foreach (QString path, files) {
++        KDesktopFile cfg(path);
++        QString string_predicate = cfg.desktopGroup().readEntry("X-KDE-Solid-Predicate");
++        //kDebug()<<string_predicate;
++        Solid::Predicate predicate = Solid::Predicate::fromString(string_predicate);
++        if (predicate.matches(device)) {
++            new_device=true;
++            interestingDesktopFiles<<path;
++        }
++    }
++
++    if (new_device) {
++        //kDebug()<<device.product();
++        //kDebug()<<device.vendor();
++        //kDebug()<< "number of interesting desktop file : " << interestingDesktopFiles.size();
++        setData(udi, "added", true);
++        setData(udi, "udi", device.udi());
++
++        if (device.vendor().length()==0) {
++            setData(udi, "text", device.product());
++        } else {
++            setData(udi, "text", device.vendor() + ' ' + device.product());
++        }
++        setData(udi, "icon", device.icon());
++        setData(udi, "predicateFiles", interestingDesktopFiles);
++
++        kDebug() << "add hardware solid : " << udi;
++        checkForUpdates();
++    }
++
++    new_device=false;
++}
++
++void HotplugEngine::onDeviceRemoved(const QString &udi)
++{
++    removeSource(udi);
++    Solid::Device device(udi);
++
++    kDebug() << "remove hardware solid : " << udi;
++
++    checkForUpdates();
++}
++
++#include "hotplugengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/hotplug/CMakeLists.txt
+@@ -0,0 +1,9 @@
++set(hotplug_engine_SRCS
++    hotplugengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_hotplug ${hotplug_engine_SRCS})
++target_link_libraries(plasma_engine_hotplug plasma ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS})
++
++install(TARGETS plasma_engine_hotplug DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-hotplug.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
+--- /dev/null
++++ b/plasma/dataengines/hotplug/hotplugengine.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (C) 2007 Menard Alexis <darktears31 at gmail.com>
++ *
++ * This program is free software you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++*/
++
++
++#ifndef SOLIDNOTIFIERENGINE_H
++#define SOLIDNOTIFIERENGINE_H
++
++#include <QObject>
++#include <QString>
++#include <QList>
++
++#include "plasma/dataengine.h"
++
++/**
++ * This class is connected with solid, filter devices and provide signal with source for applet in Plasma
++ */
++class HotplugEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++    public:
++        HotplugEngine( QObject* parent, const QVariantList& args);
++        ~HotplugEngine();
++    protected slots :
++        void onDeviceAdded(const QString &udi);
++        void onDeviceRemoved(const QString &udi);
++    private :
++        QStringList files;
++        bool new_device;
++};
++
++K_EXPORT_PLASMA_DATAENGINE(hotplug, HotplugEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/dict/dictengine.h
+@@ -0,0 +1,62 @@
++/*
++ *   Copyright (C) 2007 Thomas Georgiou <TAGeorgiou at gmail.com> and Jeff Cooper <weirdsox11 at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef DICTENGINE_H
++#define DICTENGINE_H
++#include <plasma/dataengine.h>
++#include <QMap>
++#include <QString>
++#include <QList>
++class QTcpSocket;
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++
++
++class DictEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++    public:
++        DictEngine( QObject* parent, const QVariantList& args );
++        ~DictEngine();
++        void setDict(const QString &dict);
++        void setServer(const QString &server);
++        QHash<QString, QString> *dictHash;
++
++    protected:
++        bool sourceRequested(const QString &word);
++
++    protected slots:
++	void getDefinition();
++        void socketClosed();
++        void getDicts();
++
++    private:
++	QString parseToHtml(QByteArray &text);
++	QTcpSocket *tcpSocket;
++	QString currentWord;
++	QString dictName;
++        QString serverName;
++
++};
++
++K_EXPORT_PLASMA_DATAENGINE(dict, DictEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/dict/Messages.sh
+@@ -0,0 +1,2 @@
++#! /usr/bin/env bash
++$XGETTEXT *.cpp -o $podir/plasma_engine_dict.pot
+--- /dev/null
++++ b/plasma/dataengines/dict/plasma-engine-dict.desktop
+@@ -0,0 +1,42 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Dictionary Data Engine
++Name[el]=Μηχανή δεδομένων λεξικού
++Name[et]=Sõnaraamatu andmete mootor
++Name[ga]=Inneall Sonraí Foclóra
++Name[ja]=辞書データエンジン
++Name[kk]=Сөздік деректер тетігі
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​វចនានុក្រម
++Name[ko]=사전 데이터 엔진
++Name[nb]=Ordboksdata-motor
++Name[nds]=Wöörbook-Hanteerkarn
++Name[nl]=Woordenboek (gegevensengine)
++Name[nn]=Ordboksdatamotor
++Name[pt]=Motor de Dados do Dicionário
++Name[pt_BR]=Mecanismo de Dados do Dicionário
++Name[sv]=Datagränssnitt för ordlista
++Name[x-test]=xxDictionary Data Enginexx
++Name[zh_CN]=字典数据引擎
++Name[zh_TW]=字典資料引擎
++Comment=Look up word meanings
++Comment[el]=Αναζήτηση σημασίας λέξεων
++Comment[et]=Sõna tähenduse otsimine
++Comment[ja]=単語の意味を調べる
++Comment[kk]=Сөздің мәнін қарастыру
++Comment[km]=រក​មើល​អត្ថន័យ​របស់​ពាក្យ
++Comment[ko]=단어의 뜻 찾기
++Comment[nb]=Slåopp betydningen av ord
++Comment[nds]=Woortbedüden naslaan
++Comment[nl]=Zoek de betekenis van woorden op
++Comment[nn]=Slå opp tydinga til ord
++Comment[pt]=Procurar os significados das palavras
++Comment[pt_BR]=Procurar os significados das palavras
++Comment[sv]=Slå upp ords betydelse
++Comment[x-test]=xxLook up word meaningsxx
++Comment[zh_CN]=查阅单词含义
++Comment[zh_TW]=尋找單字的意義
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=accessories-dictionary
++X-KDE-Library=plasma_engine_dict
++X-EngineName=dict
+--- /dev/null
++++ b/plasma/dataengines/dict/dictengine.cpp
+@@ -0,0 +1,235 @@
++/*
++ *   Copyright (C) 2007 Thomas Georgiou <TAGeorgiou at gmail.com> and Jeff Cooper <weirdsox11 at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "dictengine.h"
++#include <iostream>
++
++#include <QtNetwork/QTcpSocket>
++#include <KDebug>
++#include <KLocale>
++
++#include <plasma/datacontainer.h>
++
++DictEngine::DictEngine(QObject* parent, const QVariantList& args)
++    : Plasma::DataEngine(parent),
++      dictHash(0),
++      tcpSocket(0)
++{
++    Q_UNUSED(args)
++    serverName="dict.org"; //In case we need to switch it later
++    dictName="wn"; //Default, good dictionary
++}
++
++DictEngine::~DictEngine()
++{
++}
++
++void DictEngine::setDict(const QString &dict)
++{
++	dictName=dict;
++}
++
++void DictEngine::setServer(const QString &server)
++{
++    serverName=server;
++}
++
++void DictEngine::getDefinition()
++{
++      if(currentWord == QLatin1String("about"))
++      {
++          setData(currentWord, "gcide", "<!--PAGE START--><!--DEFINITION START--><dl><dt><b>Developers</b></dt><!--PAGE START--><dd>KDE4 Dictionary Applet for Plasma was written by <i>Thomas Georgiou</i> and <i>Jeff Cooper</i></dd></dl>");
++            return;
++      }
++
++      tcpSocket->waitForReadyRead();
++      tcpSocket->readAll();
++      QByteArray ret;
++
++      tcpSocket->write(QByteArray("DEFINE "));
++      tcpSocket->write(dictName.toAscii());
++      tcpSocket->write(QByteArray(" \""));
++      tcpSocket->write(currentWord.toAscii());
++      tcpSocket->write(QByteArray("\"\n"));
++      tcpSocket->flush();
++
++      while (!ret.contains("250") && !ret.contains("552"))
++      {
++        tcpSocket->waitForReadyRead();
++        ret += tcpSocket->readAll();
++      }
++
++      connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
++      tcpSocket->disconnectFromHost();
++      setData(currentWord, dictName, parseToHtml(ret));
++}
++
++
++QString DictEngine::parseToHtml(QByteArray &text)
++{
++      QList<QByteArray> retLines = text.split('\n');
++      QString def;
++      if(currentWord == QLatin1String("plasma")) //EASTER EGG!
++      {
++          def += "<dl><!--PAGE START--><!--DEFINITION START--><dt><b>Plasma</b>  \\Plas\"ma\\, a.(for awesome)</dt><!--PAGE START--><dd>OOH! I know that one! Plasma is that awesome new desktop thing for KDE4! Oh wait, you want an actual definition? Here, No fun...</dd></dl><br />";
++      }
++      def += "<dl>\n";
++
++      bool isFirst=true;
++      QString wordRegex; //case insensitive regex of the word
++      for(int i=0;i<currentWord.size();i++)
++      {
++          wordRegex += ('['+QString(currentWord[i].toUpper())+QString(currentWord[i].toLower())+']');
++      }
++
++      while (!retLines.empty()) //iterate through all the lines
++      {
++          QString currentLine = QString(retLines.takeFirst());
++          if (currentLine.startsWith("552")) //if no match was found
++          {
++              def += "<dt>";
++              def += i18n("<b>No match found for %1 in database "+dictName.toAscii()+".</b>\n",
++                          currentWord).toUtf8();
++              def += "</dt>";
++              break;
++          }
++          if (currentLine.startsWith("151")) //begin definition
++          {
++              isFirst = true;
++              continue;
++          }
++          if (currentLine.startsWith('.')) //end definition
++          {
++              def += "</dd><!--PERIOD-->";
++              continue;
++          }
++          if (!(currentLine.startsWith("150") || currentLine.startsWith("151")// if it is a definition line
++             || currentLine.startsWith("250") || currentLine.startsWith("552")))
++          {
++              currentLine = currentLine.trimmed();
++              if (currentLine.startsWith("1."))
++                  def += "<br />";
++              if (currentLine.contains(QRegExp("^([1-9]{1,2}\\.)")))
++                  def += "<br />";
++              currentLine.replace(QRegExp("\\{([A-Za-z ]+)\\}"), "<a href=\"\\1\" style=\"color: #0000FF\" >\\1</a>");
++              currentLine.replace(QRegExp("^([1-9]{1,2}\\.)"), "<!--PAGE START--><b>\\1</b>");
++              currentLine.replace(QRegExp("((^| |\\.)"+wordRegex+"( |\\.|(i?e)?s|$))"), "<b>\\1</b>"); //the i?e?s is for most plurals... i'll fix it soon
++              currentLine.replace(QRegExp("(^| |\\.)(\\[[^]]+\\])( |\\.|$)"), "<i>\\2</i>");
++
++              //currentLine.replace(currentWord, "<b>"+currentWord+"</b>", Qt::CaseInsensitive);
++
++              if(isFirst)
++              {
++                  def += "<!--PAGE START--><!--DEFINITION START--><dt>" + currentLine.toAscii() + "</dt>\n<dd>\n";
++                  isFirst = false;
++                  continue;
++              }
++
++              if(currentLine == "." || currentLine.isEmpty())
++                  def += "\n<br />\n";
++              else
++                  def += currentLine.toAscii() + '\n';
++          }
++
++      }
++      def+="</dl>";
++      return def;
++}
++
++void DictEngine::getDicts()
++{
++    QMap<QString, QString> theHash;
++    tcpSocket->waitForReadyRead();
++    tcpSocket->readAll();
++    QByteArray ret;
++
++    tcpSocket->write(QByteArray("SHOW DB\n"));;
++    tcpSocket->flush();
++
++    tcpSocket->waitForReadyRead();
++    while (!ret.contains("250"))
++      {
++        tcpSocket->waitForReadyRead();
++        ret += tcpSocket->readAll();
++      }
++
++    QList<QByteArray> retLines = ret.split('\n');
++
++    QString tmp1, tmp2;
++
++
++    while (!retLines.empty())
++    {
++        QString curr = QString(retLines.takeFirst());
++        if (curr.startsWith("554"))
++        {
++            //TODO: What happens if no DB available?
++            //TODO: Eventually there will be functionality to change the server...
++            break;
++        }
++        if (!curr.startsWith('-'))
++        {
++            curr = curr.trimmed();
++            tmp1=curr.section(' ',0,1);
++            tmp2=curr.section(' ',1);
++  //          theHash.insert(tmp1, tmp2);
++            kDebug() << tmp1 + "  " + tmp2;
++            setData("showDictionaries",tmp1,tmp2);
++        }
++    }
++    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
++    tcpSocket->disconnectFromHost();
++//    setData("showDictionaries", "dictionaries", QByteArray(theHash);
++}
++
++
++
++void DictEngine::socketClosed()
++{
++    tcpSocket->deleteLater();
++    tcpSocket = 0;
++}
++
++bool DictEngine::sourceRequested(const QString &word)
++{
++      if (tcpSocket && currentWord != word)
++      {
++          tcpSocket->abort(); //stop if lookup is in progress and new word is requested
++          tcpSocket->deleteLater();
++          tcpSocket = 0;
++      }
++      currentWord = word;
++      if (currentWord.simplified().count() != 0)
++      {
++          setData(currentWord, dictName, QString());
++          tcpSocket = new QTcpSocket(this);
++          tcpSocket->abort();
++          if (currentWord == "showDictionaries")
++          {
++              connect(tcpSocket, SIGNAL(connected()), this, SLOT(getDicts()));
++          } else {
++              connect(tcpSocket, SIGNAL(connected()), this ,SLOT(getDefinition()));
++          }
++          tcpSocket->connectToHost(serverName, 2628);
++      } else {
++          setData(currentWord, dictName, QString());
++      }
++      return true;
++}
++
++#include "dictengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/dict/buggywords
+@@ -0,0 +1 @@
++which
+--- /dev/null
++++ b/plasma/dataengines/dict/CMakeLists.txt
+@@ -0,0 +1,12 @@
++project(plasma-dictengine)
++
++set(dict_engine_SRCS
++    dictengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_dict ${dict_engine_SRCS})
++target_link_libraries(plasma_engine_dict ${KDE4_KDECORE_LIBS} plasma)
++
++install(TARGETS plasma_engine_dict DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-dict.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/filebrowser/filebrowserengine.h
+@@ -0,0 +1,60 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU General Public License version 2 (or, at
++ *   your option, any later version) as published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef FILEBROWSERENGINE_H
++#define FILEBROWSERENGINE_H
++
++#include "plasma/dataengine.h"
++#include <QMap>
++
++class KDirWatch;
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++class FileBrowserEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    FileBrowserEngine( QObject* parent, const QVariantList& args );
++    ~FileBrowserEngine();
++
++protected:
++    bool sourceRequested(const QString &path);
++    void init();
++
++protected slots:
++    void dirDirty (const QString &path);
++    void dirCreated(const QString &path);
++    void dirDeleted(const QString &path);
++
++private:
++    enum EventType {INIT, DIRTY, CREATED, DELETED};
++    enum ObjectType {NOTHING, FILE, DIRECTORY};
++
++    KDirWatch * m_dirWatch;
++    void updateData(const QString &path, EventType event);
++    void clearData(const QString &path);
++
++    //QMap < QString, QStringList > m_regiteredListeners;
++};
++
++K_EXPORT_PLASMA_DATAENGINE(filebrowser, FileBrowserEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/filebrowser/plasma-engine-filebrowser.desktop
+@@ -0,0 +1,39 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=File and Directory Browser Engine
++Name[el]=Μηχανή περιήγησης αρχείων και φακέλων
++Name[et]=Faili- ja kataloogisirvija mootor
++Name[ja]=ファイルとディレクトリのブラウザエンジン
++Name[km]=ម៉ាស៊ីន​រុករក​ថត និង​ឯកសារ
++Name[ko]=파일 및 디렉터리 탐색 엔진
++Name[nb]=Motor for blaing i filer og mapper
++Name[nds]=Kiekerkarn för Dateien un Ornern
++Name[nl]=Engine voor het bladeren door mappen en bestanden
++Name[nn]=Motor for fil- og mappelesing
++Name[pt]=Motor de Navegação em Ficheiros e Pastas
++Name[pt_BR]=Mecanismo de Navegação em Arquivos e Pastas
++Name[sv]=Gränssnitt för fil- och katalogbläddring
++Name[x-test]=xxFile and Directory Browser Enginexx
++Name[zh_CN]=文件和目录浏览器引擎
++Name[zh_TW]=檔案與目錄瀏覽器引擎
++Comment=Info about files and directories for Plasmoids
++Comment[el]=Πληροφορίες για αρχεία και καταλόγους για πλασμοειδή
++Comment[et]=Failide ja kataloogide info plasmoididele
++Comment[ja]=Plasmoid のためのファイルとディレクトリに関する情報
++Comment[km]=ព័ត៌មាន​អំពី​ឯកសារ និង​ថត​សម្រាប់ Plasmoids
++Comment[ko]=Plasmoid를 위한 파일과 디렉터리 정보
++Comment[nb]=Informasjon om filer og mapper for Plasmoids
++Comment[nds]=Infos över Dateien un Ornern för Plasmoiden
++Comment[nl]=Informatie over bestanden en mappen voor Plasmoids
++Comment[nn]=Informasjon om filer og mapper for Plasmoidar
++Comment[pt]=Informação sobre os ficheiros e pastas nos Plasmóides
++Comment[pt_BR]=Informações sobre arquivos e diretórios, para os Plasmoids
++Comment[sv]=Information om filer och kataloger för Plasmoider
++Comment[x-test]=xxInfo about files and directories for Plasmoidsxx
++Comment[zh_CN]=Plasmoids 下关于文件和目录的信息
++Comment[zh_TW]=Plasmoids 關於檔案與目錄的資訊
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=unknown
++X-KDE-Library=plasma_engine_filebrowser
++X-EngineName=filebrowser
+--- /dev/null
++++ b/plasma/dataengines/filebrowser/filebrowserengine.cpp
+@@ -0,0 +1,159 @@
++/*
++ *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU General Public License version 2 (or, at
++ *   your option, any later version) as published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "filebrowserengine.h"
++
++#include "plasma/datacontainer.h"
++
++#include <QDir>
++#include <KDirWatch>
++#include <KDebug>
++#include <KFileMetaInfo>
++
++#define InvalidIfEmpty(A) ((A.isEmpty())?(QVariant()):(QVariant(A)))
++#define forMatchingSources for (DataEngine::SourceDict::iterator it = sources.begin(); it != sources.end(); it++) \
++  if (dir == QDir(it.key()))
++
++FileBrowserEngine::FileBrowserEngine(QObject* parent, const QVariantList& args) :
++    Plasma::DataEngine(parent), m_dirWatch(NULL)
++{
++    Q_UNUSED(args)
++
++    m_dirWatch = new KDirWatch(this);
++    connect(m_dirWatch, SIGNAL(created(
++        const QString &)), this, SLOT(dirCreated(const QString &)));
++    connect(m_dirWatch, SIGNAL(deleted(
++        const QString &)), this, SLOT(dirDeleted(const QString &)));
++    connect(m_dirWatch, SIGNAL(dirty(
++        const QString &)), this, SLOT(dirDirty(const QString &)));
++}
++
++FileBrowserEngine::~FileBrowserEngine()
++{
++    delete m_dirWatch;
++}
++
++void FileBrowserEngine::init()
++{
++    kDebug() << "init() called";
++}
++
++bool FileBrowserEngine::sourceRequested(const QString &path)
++{
++    kDebug() << "source requested() called: "<< path;
++    m_dirWatch->addDir(path);
++    setData(path, "type", QVariant("unknown"));
++    updateData (path, INIT);
++    return true;
++}
++
++void FileBrowserEngine::dirDirty(const QString &path)
++{
++    updateData(path, DIRTY);
++}
++
++void FileBrowserEngine::dirCreated(const QString &path)
++{
++    updateData(path, CREATED);
++}
++
++void FileBrowserEngine::dirDeleted(const QString &path)
++{
++    updateData(path, DELETED);
++}
++
++void FileBrowserEngine::updateData(const QString &path, EventType event)
++{
++    Q_UNUSED(event)
++
++    ObjectType type = NOTHING;
++    if (QDir(path).exists()) {
++        type = DIRECTORY;
++    } else if (QFile::exists(path)) {
++        type = FILE;
++    }
++
++    DataEngine::SourceDict sources = sourceDict();
++
++    QDir dir(path);
++    clearData(path);
++
++    if (type == DIRECTORY) {
++        kDebug() << "directory info processing: "<< path;
++        if (dir.isReadable()) {
++            QStringList visibleFiles = dir.entryList(QDir::Files, QDir::Name);
++            QStringList allFiles = dir.entryList(QDir::Files | QDir::Hidden,
++                    QDir::Name);
++
++            QStringList visibleDirectories = dir.entryList(QDir::Dirs
++                    | QDir::NoDotAndDotDot, QDir::Name);
++            QStringList allDirectories = dir.entryList(QDir::Dirs
++                    | QDir::NoDotAndDotDot | QDir::Hidden, QDir::Name);
++
++            forMatchingSources {
++                kDebug() << "MATCH";
++                it.value()->setData("item.type", QVariant("directory"));
++
++                it.value()->setData("directories.visible", InvalidIfEmpty(visibleDirectories));
++                it.value()->setData("directories.all", InvalidIfEmpty(allDirectories));
++                it.value()->setData("files.visible", InvalidIfEmpty(visibleFiles));
++                it.value()->setData("files.all", InvalidIfEmpty(allFiles));
++            }
++        }
++    } else if (type == FILE) {
++        kDebug() << "file info processing: "<< path;
++        KFileMetaInfo kfmi(path, QString::null, KFileMetaInfo::Everything);
++        if (kfmi.isValid()) {
++            kDebug() << "METAINFO: " << kfmi.keys();
++
++            forMatchingSources {
++                kDebug() << "MATCH";
++                it.value()->setData("item.type", QVariant("file"));
++
++                for (QHash< QString, KFileMetaInfoItem >::const_iterator i = kfmi.items().constBegin(); i != kfmi.items().constEnd(); i++) {
++                    it.value()->setData(i.key(), i.value().value());
++                }
++            }
++        }
++    } else {
++        forMatchingSources {
++            it.value()->setData("item.type", QVariant("imaginary"));
++        }
++    };
++
++    checkForUpdates();
++
++}
++
++void FileBrowserEngine::clearData(const QString &path)
++{
++    QDir dir(path);
++    DataEngine::SourceDict sources = sourceDict();
++    for (DataEngine::SourceDict::iterator it = sources.begin(); it
++            != sources.end(); it++) {
++        if (dir == QDir(it.key())) {
++            kDebug() << "matched: "<< path << " "<< it.key();
++            it.value()->clearData();
++
++        } else {
++            kDebug() << "didn't match: "<< path << " "<< it.key();
++        }
++    }
++}
++
++#include "filebrowserengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/filebrowser/CMakeLists.txt
+@@ -0,0 +1,10 @@
++set(filebrowser_engine_SRCS
++    filebrowserengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_filebrowser ${filebrowser_engine_SRCS})
++target_link_libraries(plasma_engine_filebrowser ${KDE4_KDECORE_LIBS} plasma)
++
++install(TARGETS plasma_engine_filebrowser DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-filebrowser.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/tasks/tasksengine.h
+@@ -0,0 +1,56 @@
++/*
++ *   Copyright (C) 2007 Robert Knight <robertknight at gmail.com> 
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef TASKSENGINE_H
++#define TASKSENGINE_H
++
++// Qt
++#include <QObject>
++#include <QString>
++#include <QList>
++
++// Plasma
++#include <plasma/dataengine.h>
++#include <taskmanager/taskmanager.h>
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++class TasksEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++    public:
++		TasksEngine( QObject* parent, const QVariantList& args);
++
++    protected:
++        virtual void init();
++
++    private slots:
++        void taskChanged();
++        void taskAdded(Task::TaskPtr task);
++        void taskRemoved(Task::TaskPtr task);
++
++    private:
++        void connectTask(Task::TaskPtr task);
++        void setDataForTask(Task::TaskPtr task);
++};
++
++K_EXPORT_PLASMA_DATAENGINE(tasks, TasksEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/tasks/plasma-engine-tasks.desktop
+@@ -0,0 +1,17 @@
++[Desktop Entry]
++Name=Task Management Data Engine
++Name[et]=Tegumihalduse andmete mootor
++Name[ja]=タスク管理データエンジン
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​ការ​គ្រប់គ្រង​ថាមពល
++Name[nb]=Motor for oppgavedata
++Name[nds]=Opgavenpleeg-Hanteerkarn
++Name[nl]=Taakbeheer (gegevensengine)
++Name[pt]=Motor de Dados de Gestão de Tarefas
++Name[pt_BR]=Mecanismo de Dados de Gerenciamento Tarefas
++Name[sv]=Datagränssnitt för aktivitetshantering
++Name[zh_TW]=工作管理資料引擎
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=alarmclock
++X-KDE-Library=plasma_engine_tasks
++X-EngineName=tasks
+--- /dev/null
++++ b/plasma/dataengines/tasks/tasksengine.cpp
+@@ -0,0 +1,81 @@
++/*
++ *   Copyright (C) 2007 Robert Knight <robertknight at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "tasksengine.h"
++
++#include <KDebug>
++#include <KLocale>
++
++#include <plasma/datacontainer.h>
++
++using namespace Plasma;
++
++TasksEngine::TasksEngine(QObject* parent, const QVariantList& args)
++    : Plasma::DataEngine(parent)
++{
++}
++void TasksEngine::connectTask( Task::TaskPtr task )
++{
++        connect( task.constData() , SIGNAL(changed()) , this , SLOT(taskChanged()) );
++}
++void TasksEngine::init()
++{
++    foreach( Task::TaskPtr task , TaskManager::self()->tasks().values() ) {
++        connectTask(task);
++        setDataForTask(task);
++    }
++
++    connect( TaskManager::self() , SIGNAL(taskAdded(Task::TaskPtr)) , this , SLOT(taskAdded(Task::TaskPtr)) );
++    connect( TaskManager::self() , SIGNAL(taskRemoved(Task::TaskPtr)) , this , SLOT(taskRemoved(Task::TaskPtr)) );
++
++}
++
++void TasksEngine::taskAdded(Task::TaskPtr task)
++{
++    connectTask(task);
++    setDataForTask(task);
++}
++void TasksEngine::taskRemoved(Task::TaskPtr task)
++{
++    removeSource( QString::number(task->window()) );
++}
++void TasksEngine::taskChanged()
++{
++    Task* task = qobject_cast<Task*>(sender());
++
++    Q_ASSERT(task);
++
++    setDataForTask( Task::TaskPtr(task) );
++}
++
++void TasksEngine::setDataForTask(Task::TaskPtr task)
++{
++    Q_ASSERT( task );
++
++    QString name = QString::number(task->window());
++
++    const QMetaObject* metaObject = task->metaObject();
++
++    for ( int i = 0 ; i < metaObject->propertyCount() ; i++ ) {
++        QMetaProperty property = metaObject->property(i);
++
++        setData(name,property.name(),property.read(task.constData()));
++    }
++}
++
++#include "tasksengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/tasks/CMakeLists.txt
+@@ -0,0 +1,11 @@
++set(tasks_engine_SRCS
++    tasksengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_tasks ${tasks_engine_SRCS})
++target_link_libraries(plasma_engine_tasks ${KDE4_KDEUI_LIBS} plasma
++                      taskmanager)
++
++install(TARGETS plasma_engine_tasks DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-tasks.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/places/placesengine.h
+@@ -0,0 +1,58 @@
++/*
++ *   Copyright (C) 2007 Alex Merry <huntedhacker at tiscali.co.uk>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef PLACESENGINE_H
++#define PLACESENGINE_H
++
++#include <plasma/dataengine.h>
++
++#include <QtCore/QMap>
++#include <QtCore/QString>
++#include <QtCore/QStringList>
++
++#include <kfileplacesmodel.h>
++
++class PlacesEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    PlacesEngine(QObject* parent, const QVariantList& args);
++    ~PlacesEngine();
++
++private Q_SLOTS:
++    // KFilePlacesModel
++    void modelReset();
++    void placesAdded(const QModelIndex &parent, int start, int end);
++
++    // KFreeDiskSpace
++    void diskFreeSpaceFound(const QString &mountPoint,
++                            quint64 kBSize,
++                            quint64 kBUsed,
++                            quint64 kBAvailable);
++
++private:
++    void tryGetFreeSpace(const KUrl &url);
++
++    void sendData();
++
++    KFilePlacesModel m_placesModel;
++};
++
++
++#endif // PLACESENGINE_H
+--- /dev/null
++++ b/plasma/dataengines/places/TODO
+@@ -0,0 +1,2 @@
++* periodic refresh? KFilePlacesModel doesn't broadcast
++  device setups etc. between programs
+--- /dev/null
++++ b/plasma/dataengines/places/CMakeLists.txt
+@@ -0,0 +1,10 @@
++set(places_engine_SRCS
++    placesengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_places ${places_engine_SRCS})
++target_link_libraries(plasma_engine_places plasma ${KDE4_KFILE_LIBS})
++
++install(TARGETS plasma_engine_places DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-places.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/places/plasma-engine-places.desktop
+@@ -0,0 +1,31 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Places Data Engine
++Name[et]=Asukohtade andmete mootor
++Name[ga]=Inneall Sonraí Áiteanna
++Name[ja]=場所データエンジン
++Name[km]=ដាក់​ម៉ាស៊ីន​ទិន្នន័យ
++Name[nb]=Steder datamotor
++Name[nds]=Steden-Hanteerkarn
++Name[nl]=Locaties (gegevensengine)
++Name[pt]=Motor de Dados dos Locais
++Name[pt_BR]=Mecanismo de Dados de Locais
++Name[sv]=Datagränssnitt för platser
++Name[zh_TW]=Places 資料引擎
++Comment=Places data for Plasmoids
++Comment[et]=Asukohtade andmed plasmoididele
++Comment[ga]=Sonraí áiteanna le haghaidh Plasmoids
++Comment[ja]=Plasmoid のための場所データ
++Comment[km]=ដាក់​ម៉ាស៊ីន​ទិន្នន័យ Plasmoids
++Comment[nb]=Stedsdata for Plasmoids
++Comment[nds]=Steeddaten för Plasmoiden
++Comment[nl]=Locatiegegevens voor Plasmoids
++Comment[pt]=Dados dos locais para os Plasmóides
++Comment[pt_BR]=Dados de locais para os Plasmoids
++Comment[sv]=Platsdata för Plasmoider
++Comment[zh_TW]=Plasmoid 的 Places 資料
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=folder
++X-KDE-Library=plasma_engine_places
++X-EngineName=places
+--- /dev/null
++++ b/plasma/dataengines/places/placesengine.cpp
+@@ -0,0 +1,135 @@
++/*
++ *   Copyright (C) 2007 Alex Merry <huntedhacker at tiscali.co.uk>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++// Local includes
++#include "placesengine.h"
++
++// Qt includes
++#include <QtCore/QString>
++#include <QtCore/QVariantList>
++
++
++// KDE includes
++#include <KDiskFreeSpace>
++
++PlacesEngine::PlacesEngine(QObject* parent, const QVariantList&)
++    : Plasma::DataEngine(parent)
++{
++    // dataChanged(), rowsRemoved() and setupDone() signals from
++    // KFilePlacesModel are not propagated between applications.
++    // layoutChanged() is not emitted at all.
++    connect(&m_placesModel, SIGNAL(modelReset()),
++            this, SLOT(modelReset()));
++    connect(&m_placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
++            this, SLOT(placesAdded(QModelIndex,int,int)));
++
++    sendData();
++}
++
++PlacesEngine::~PlacesEngine()
++{
++}
++
++void PlacesEngine::modelReset()
++{
++    kDebug() << "Model reset";
++
++    clearSources();
++}
++
++void PlacesEngine::placesAdded(const QModelIndex &parent, int start, int end)
++{
++    kDebug() << "Places added:" << parent << "from" << start << "to" << end;
++    sendData();
++}
++
++void PlacesEngine::diskFreeSpaceFound(const QString &mountPoint,
++                                      quint64 kBSize,
++                                      quint64 kBUsed,
++                                      quint64 kBAvailable)
++{
++    kDebug() << "Sir! We got one!" << mountPoint + ": "
++        << "size =" << kBSize
++        << "used =" << kBUsed
++        << "avail =" << kBAvailable;
++    QString source;
++
++    foreach (QString testsource, sources()) {
++        kDebug() << "Testing" << query(testsource)["url"];
++        KUrl url(query(testsource)["url"].toString());
++        if (url.isLocalFile() && url.path() == mountPoint) {
++            source = testsource;
++            break;
++        }
++    }
++
++    kDebug() << "Source:" << source;
++    if (!source.isEmpty()) {
++        setData(source, "kBSize", kBSize);
++        setData(source, "kBUsed", kBUsed);
++        setData(source, "kBAvailable", kBAvailable);
++    }
++}
++
++void PlacesEngine::tryGetFreeSpace(const KUrl &url)
++{
++    if (!url.isLocalFile()) {
++        return;
++    }
++
++    kDebug() << "Requesting free space on" << url;
++
++    // suicidal object: don't need to worry about cleanup
++    KDiskFreeSpace *diskFreeSpace = new KDiskFreeSpace(this);
++    connect(diskFreeSpace,
++            SIGNAL(foundMountPoint(QString,quint64,quint64,quint64)),
++            this,
++            SLOT(diskFreeSpaceFound(QString,quint64,quint64,quint64)));
++    diskFreeSpace->readDF(url.path());
++}
++
++void PlacesEngine::sendData()
++{
++    int rowCount = m_placesModel.rowCount();
++    for (int i = 0; i < rowCount; ++i) {
++        QModelIndex index = m_placesModel.index(i,0);
++
++        Data map;
++
++        QString source = QString::number(i);
++
++        setData(source, "name", m_placesModel.text(index));
++        setData(source, "url", m_placesModel.url(index).url());
++        setData(source, "icon", m_placesModel.icon(index));
++        setData(source, "hidden",
++                m_placesModel.data(index, KFilePlacesModel::HiddenRole));
++        setData(source, "setupNeeded",
++                m_placesModel.data(index, KFilePlacesModel::SetupNeededRole));
++
++        if (m_placesModel.deviceForIndex(index).isValid()) {
++            setData(source, "isDevice", true);
++            tryGetFreeSpace(m_placesModel.url(index));
++        } else {
++            setData(source, "isDevice", false);
++        }
++    }
++}
++
++K_EXPORT_PLASMA_DATAENGINE(places, PlacesEngine)
++
++
+--- /dev/null
++++ b/plasma/dataengines/mouse/mouseengine.cpp
+@@ -0,0 +1,100 @@
++/*
++ *   Copyright © 2007 Fredrik Höglund <fredrik at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include <QCursor>
++
++#include "mouseengine.h"
++#include "mouseengine.moc"
++
++#include <config-X11.h>
++
++#ifdef HAVE_XFIXES
++#  include "cursornotificationhandler.h"
++#endif
++
++
++MouseEngine::MouseEngine(QObject* parent, const QVariantList& args)
++    : Plasma::DataEngine(parent), timerId(0), handler(0)
++{
++    Q_UNUSED(args)
++}
++
++
++MouseEngine::~MouseEngine()
++{
++    if (timerId)
++        killTimer(timerId);
++
++    delete handler;
++}
++
++
++QStringList MouseEngine::sources() const
++{
++   QStringList list;
++
++   list << QLatin1String("Position");
++#ifdef HAVE_XFIXES
++   list << QLatin1String("Name");
++#endif
++
++   return list;
++}
++
++
++void MouseEngine::init()
++{
++    if (!timerId)
++        timerId = startTimer(40);
++
++    // Init cursor position
++    QPoint pos = QCursor::pos();
++    setData(QLatin1String("Position"), QVariant(pos));
++    lastPosition = pos;
++
++#ifdef HAVE_XFIXES
++    handler = new CursorNotificationHandler;
++    connect(handler, SIGNAL(cursorNameChanged(QString)), SLOT(updateCursorName(QString)));
++
++    setData(QLatin1String("Name"), QVariant(handler->cursorName()));
++#endif
++
++    checkForUpdates();
++}
++
++
++void MouseEngine::timerEvent(QTimerEvent *)
++{
++    QPoint pos = QCursor::pos();
++
++    if (pos != lastPosition)
++    {
++        setData(QLatin1String("Position"), QVariant(pos));
++        lastPosition = pos;
++
++        checkForUpdates();
++    }
++}
++
++
++void MouseEngine::updateCursorName(const QString &name)
++{
++    setData(QLatin1String("Name"), QVariant(name));
++    checkForUpdates();
++}
++
+--- /dev/null
++++ b/plasma/dataengines/mouse/cursornotificationhandler.cpp
+@@ -0,0 +1,112 @@
++/*
++ *   Copyright © 2007 Fredrik Höglund <fredrik at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include <QX11Info>
++
++#include "cursornotificationhandler.h"
++#include "cursornotificationhandler.moc"
++
++#include <X11/extensions/Xfixes.h>
++
++
++/*
++ * This class is a QWidget because we need an X window to
++ * be able to receive XFixes events. We don't actually map
++ * the widget.
++ */
++
++CursorNotificationHandler::CursorNotificationHandler()
++    : QWidget(), currentName(0)
++{
++    Display *dpy = QX11Info::display();
++    int errorBase;
++    haveXfixes = false;
++
++    // Request cursor change notification events
++    if (XFixesQueryExtension(dpy, &fixesEventBase, &errorBase))
++    {
++        int major, minor;
++        XFixesQueryVersion(dpy, &major, &minor);
++
++        if (major >= 2)
++        {
++            XFixesSelectCursorInput(dpy, winId(), XFixesDisplayCursorNotifyMask);
++            haveXfixes = true;
++        }
++    }
++}
++
++
++CursorNotificationHandler::~CursorNotificationHandler()
++{
++}
++
++
++QString CursorNotificationHandler::cursorName()
++{
++    if (!haveXfixes)
++        return QString();
++
++    if (!currentName)
++    {
++        // Xfixes doesn't have a request for getting the current cursor name,
++        // but it's included in the XFixesCursorImage struct.
++        XFixesCursorImage *image = XFixesGetCursorImage(QX11Info::display());
++        currentName = image->atom;
++        XFree(image);
++    }
++
++    return cursorName(currentName);
++}
++
++
++QString CursorNotificationHandler::cursorName(Atom cursor)
++{
++    QString name;
++
++    // XGetAtomName() is a synchronous call, so we cache the name
++    // in an atom<->string map the first time we see a name
++    // to keep the X server round trips down.
++    if (names.contains(cursor))
++        name = names[cursor];
++    else
++    {
++        char *data = XGetAtomName(QX11Info::display(), cursor);
++        name = QString::fromUtf8(data);
++        XFree(data);
++
++        names.insert(cursor, name);
++    }
++
++    return name;
++}
++
++
++bool CursorNotificationHandler::x11Event(XEvent* event)
++{
++    if (event->type != fixesEventBase + XFixesCursorNotify)
++        return false;
++
++    XFixesCursorNotifyEvent *xfe = reinterpret_cast<XFixesCursorNotifyEvent*>(event);
++    currentName = xfe->cursor_name;
++
++    emit cursorNameChanged(cursorName(currentName));
++
++    return false;
++}
++
+--- /dev/null
++++ b/plasma/dataengines/mouse/mouseengine.h
+@@ -0,0 +1,53 @@
++/*
++ *   Copyright © 2007 Fredrik Höglund <fredrik at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef MOUSEENGINE_H
++#define MOUSEENGINE_H
++
++#include <plasma/dataengine.h>
++
++
++class CursorNotificationHandler;
++
++
++class MouseEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    MouseEngine(QObject* parent, const QVariantList& args);
++    ~MouseEngine();
++
++    QStringList sources() const;
++
++protected:
++    void init();
++    void timerEvent(QTimerEvent*);
++
++private slots:
++    void updateCursorName(const QString &name);
++
++private:
++    QPoint lastPosition;
++    int timerId;
++    CursorNotificationHandler *handler;
++};
++
++K_EXPORT_PLASMA_DATAENGINE(mouse, MouseEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/mouse/cursornotificationhandler.h
+@@ -0,0 +1,53 @@
++/*
++ *   Copyright © 2007 Fredrik Höglund <fredrik at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef CURSORNOTIFICATIONHANDLER_H
++#define CURSORNOTIFICATIONHANDLER_H
++
++#include <QWidget>
++#include <QMap>
++
++#include <X11/Xlib.h>
++
++class CursorNotificationHandler : public QWidget
++{
++    Q_OBJECT
++
++public:
++    CursorNotificationHandler();
++    ~CursorNotificationHandler();
++
++    QString cursorName();
++
++signals:
++    void cursorNameChanged(const QString &name);
++
++protected:
++    bool x11Event(XEvent *);
++
++private:
++    QString cursorName(Atom cursor);
++
++private:
++    bool haveXfixes;
++    int fixesEventBase;
++    Atom currentName;
++    QMap<Atom, QString> names;
++};
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/mouse/CMakeLists.txt
+@@ -0,0 +1,19 @@
++include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../../)
++
++set(mouse_engine_SRCS
++    mouseengine.cpp
++)
++
++if (X11_Xfixes_FOUND)
++    set(mouse_engine_SRCS ${mouse_engine_SRCS} cursornotificationhandler.cpp)
++endif (X11_Xfixes_FOUND)
++
++kde4_add_plugin(plasma_engine_mouse ${mouse_engine_SRCS})
++target_link_libraries(plasma_engine_mouse ${KDE4_KDEUI_LIBS} plasma)
++if (X11_Xfixes_FOUND)
++	target_link_libraries(plasma_engine_mouse ${X11_Xfixes_LIB})
++endif (X11_Xfixes_FOUND)
++
++install(TARGETS plasma_engine_mouse DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-mouse.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/mouse/plasma-engine-mouse.desktop
+@@ -0,0 +1,31 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Mouse Data Engine
++Name[et]=Hiire andmete mootor
++Name[ja]=マウスデータエンジン
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​កណ្ដុរ
++Name[nb]=Musedata-motor
++Name[nds]=Muus-Hanteerkarn
++Name[nl]=Muis (gegevensengine)
++Name[pt]=Motor de Dados do Rato
++Name[pt_BR]=Mecanismo de Dados de Mouse
++Name[sv]=Datagränssnitt för mus
++Name[zh_TW]=滑鼠資料引擎
++Comment=Mouse data for Plasmoids
++Comment[et]=Hiire andmed plasmoididele
++Comment[ga]=Sonraí luiche le haghaidh Plasmoids
++Comment[ja]=Plasmoid のためのマウスデータ
++Comment[km]=ទិន្នន័យកណ្ដុរ​​សម្រាប់ Plasmoids
++Comment[nb]=Musedata for Plasmoids
++Comment[nds]=Muusdaten för Plasmoiden
++Comment[nl]=Muisgegevens voor Plasmoids
++Comment[pt]=Dados do rato para os Plasmóides
++Comment[pt_BR]=Dados de mouse para os Plasmoids
++Comment[sv]=Musdata för Plasmoider
++Comment[zh_TW]=Plasmoid 的滑鼠資料
++Type=Service
++ServiceTypes=Plasma/DataEngine
++Icon=
++X-KDE-Library=plasma_engine_mouse
++X-EngineName=mouse
++
+--- /dev/null
++++ b/plasma/dataengines/powermanagement/plasma-engine-powermanagement.desktop
+@@ -0,0 +1,21 @@
++[Desktop Entry]
++Name=Powermanagement Data Engine
++Name[el]=Μηχανή δεδομένων διαχείρισης ενέργειας
++Name[et]=Voolutarbe andmete mootor
++Name[ga]=Inneall Sonraí Powermanagement
++Name[ja]=電源管理データエンジン
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​ការ​គ្រប់គ្រង​ថាមពល
++Name[nb]=Motor for strømstyringsdata
++Name[nds]=Stroomkuntrull-Hanteerkarn
++Name[nl]=Energiebeheer (gegevensengine)
++Name[pt]=Motor de Dados de Gestão de Energia
++Name[pt_BR]=Mecanismo de Dados de Gerenciamento de Energia
++Name[sv]=Datagränssnitt för strömsparfunktion
++Name[x-test]=xxPowermanagement Data Enginexx
++Name[zh_CN]=电源管理数据引擎
++Name[zh_TW]=電源管理資料引擎
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=power
++X-KDE-Library=plasma_engine_powermanagement
++X-EngineName=powermanagement
+--- /dev/null
++++ b/plasma/dataengines/powermanagement/powermanagementengine.cpp
+@@ -0,0 +1,168 @@
++/*
++ *   Copyright (C) 2007 Aaron Seigo <aseigo at kde.org>
++ *   Copyright (C) 2007 Sebastian Kuegler <sebas at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "powermanagementengine.h"
++
++//solid specific includes
++#include <solid/devicenotifier.h>
++#include <solid/device.h>
++#include <solid/deviceinterface.h>
++#include <solid/battery.h>
++#include <solid/powermanagement.h>
++
++#include <KDebug>
++#include <KLocale>
++
++#include "plasma/datacontainer.h"
++
++PowermanagementEngine::PowermanagementEngine(QObject* parent, const QVariantList& args)
++        : Plasma::DataEngine(parent)
++        , m_battery(0)
++        , m_acadapter(0)
++        , m_sources(0)
++{
++    Q_UNUSED(args)
++    
++    m_sources = QStringList();
++    m_sources << I18N_NOOP("Battery") << I18N_NOOP("AC Adapter") << I18N_NOOP("Sleepstates");
++    
++    // This following call can be removed, but if we do, the
++    // data is not shown in the plasmaengineexplorer.
++    // sourceRequested("Battery");
++}
++
++PowermanagementEngine::~PowermanagementEngine()
++{}
++
++void PowermanagementEngine::init()
++{}
++
++QStringList PowermanagementEngine::sources() const 
++{
++    return m_sources;
++}
++
++bool PowermanagementEngine::sourceRequested(const QString &name)
++{
++    if (name == I18N_NOOP("Battery")) {
++        // TODO: some machines have more than one battery, right now we only catch the first
++        QList<Solid::Device> list_battery =
++                        Solid::Device::listFromType(Solid::DeviceInterface::Battery, QString());
++        if (list_battery.count() == 0) {
++            setData(I18N_NOOP("Battery"), I18N_NOOP("has Battery"), false);
++            return true;
++        }
++        foreach (Solid::Device device_battery, list_battery) {
++            setData(I18N_NOOP("Battery"), I18N_NOOP("has Battery"), true);
++            m_battery = device_battery.as<Solid::Battery>();
++            if (m_battery->type() != Solid::Battery::PrimaryBattery) {
++                kDebug() << "Some other battery found.";
++            } else {
++                kDebug() << "PMEngine::Primary battery found.";
++
++                connect(m_battery, SIGNAL(chargeStateChanged(int)), this,
++                        SLOT(updateBatteryChargeState(int)));
++                connect(m_battery, SIGNAL(chargePercentChanged(int)), this,
++                        SLOT(updateBatteryChargePercent(int)));
++                connect(m_battery, SIGNAL(plugStateChanged(bool)), this,
++                        SLOT(updateBatteryPlugState(bool)));
++
++                // Set initial values
++                updateBatteryChargeState(m_battery->chargeState());
++                updateBatteryChargePercent(m_battery->chargePercent());
++                updateBatteryPlugState(m_battery->isPlugged());
++            }
++        }
++    } else if (name == I18N_NOOP("AC Adapter")) {
++        // AC Adapter handling
++        QList<Solid::Device> list_ac =
++                        Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter, QString());
++        foreach (Solid::Device device_ac, list_ac) {
++            m_acadapter = device_ac.as<Solid::AcAdapter>();
++            updateAcPlugState(m_acadapter->isPlugged());
++            connect(m_acadapter, SIGNAL(plugStateChanged(bool)), this,
++                    SLOT(updateAcPlugState(bool)));
++        }
++
++    } else if (name == I18N_NOOP("Sleepstates")) {
++        QSet<Solid::PowerManagement::SleepState> sleepstates =
++                                Solid::PowerManagement::supportedSleepStates();
++        kDebug() << sleepstates.count() << " sleepstates supported.";
++
++        // We first set all possible sleepstates to false, then enable the ones that are available
++        setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Standby"), false);
++        setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Suspend"), false);
++        setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Hibernate"), false);
++
++        foreach (Solid::PowerManagement::SleepState sleepstate, sleepstates) {
++            if (sleepstate == Solid::PowerManagement::StandbyState) {
++                setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Supports standby"), true);
++            } else if (sleepstate == Solid::PowerManagement::SuspendState) {
++                setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Supports suspend"), true);
++            } else if (sleepstate == Solid::PowerManagement::HibernateState) {
++                setData(I18N_NOOP("Sleepstates"), I18N_NOOP("Supports hibernate"), true);
++            }
++            kDebug() << "Sleepstate \"" << sleepstate << "\" supported.";
++        }
++    } else {
++        kDebug() << "Data for '" << name << "' not found";
++    }
++    
++    return true;
++}
++
++void PowermanagementEngine::updateBatteryChargeState(int newState)
++{
++    QString state;
++    if (newState == Solid::Battery::NoCharge) {
++        state = I18N_NOOP("NoCharge");
++    } else if (newState == Solid::Battery::Charging) {
++        state = I18N_NOOP("Charging");
++    } else if (newState == Solid::Battery::Discharging) {
++        state = I18N_NOOP("Discharging");
++    } else {
++        state = I18N_NOOP("Could not determine battery status. Something is fishy here. :o");
++    }
++    setData(I18N_NOOP("Battery"), I18N_NOOP("State"), state);
++    kDebug() << "PMEngine::Battery: updateChargeState " << state;
++    checkForUpdates();
++}
++
++void PowermanagementEngine::updateBatteryPlugState(bool newState)
++{
++    kDebug() << "PMEngine::Battery: updatePlugState" << newState;
++    setData(I18N_NOOP("Battery"), I18N_NOOP("Plugged in"), newState);
++    checkForUpdates();
++}
++
++void PowermanagementEngine::updateBatteryChargePercent(int newValue)
++{
++    kDebug() << "PMEngine::Battery: new chargepercent: " << newValue;
++    setData(I18N_NOOP("Battery"), I18N_NOOP("Percent"), newValue);
++    checkForUpdates();
++}
++
++void PowermanagementEngine::updateAcPlugState(bool newState)
++{
++    kDebug() << "PMEngine::AcAdapter: updatePlugState" << newState;
++    setData(I18N_NOOP("AC Adapter"), I18N_NOOP("Plugged in"), newState);
++    checkForUpdates();
++}
++
++#include "powermanagementengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/powermanagement/powermanagementengine.h
+@@ -0,0 +1,59 @@
++/*
++ *   Copyright (C) 2007 Aaron Seigo <aseigo at kde.org>
++ *   Copyright (C) 2007 Sebastian Kuegler <sebas at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef POWERMANAGEMENTENGINE_H
++#define POWERMANAGEMENTENGINE_H
++
++#include "plasma/dataengine.h"
++
++#include <solid/battery.h>
++#include <solid/acadapter.h>
++
++/**
++ * This class provides runtime information about the battery and AC status
++ * for use in a simple batter monitor application.
++ */
++class PowermanagementEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    PowermanagementEngine( QObject* parent, const QVariantList& args );
++    ~PowermanagementEngine();
++    QStringList sources() const;
++
++protected:
++    bool sourceRequested(const QString &name);
++    void init();
++
++protected slots:
++    void updateBatteryChargeState(int newState);
++    void updateBatteryChargePercent(int newValue);
++    void updateBatteryPlugState(bool newState);
++    void updateAcPlugState(bool newState);
++
++private:
++    Solid::Battery* m_battery;
++    Solid::AcAdapter* m_acadapter;
++    QStringList m_sources;
++};
++
++K_EXPORT_PLASMA_DATAENGINE(powermanagement, PowermanagementEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/powermanagement/README.txt
+@@ -0,0 +1,30 @@
++TODO:
++======
++- some machines have more than one battery
++- find a way to compute remaining minutes
++- Sleepstates don't match what solidshell reports
++- ac plug state does not get updated
++- this engine probably shares some functionality with
++  the solidengine, have a look at that and evaluate
++
++Notes
++======
++Check out into workspace/plasma/engines/
++
++There's also a battery applet which uses this engine, find it in
++the
++
++Patch plasma/engines/CMakeLists.txt like this to enable building 
++of the battery engine:
++
++-- sebas
++
++Index: CMakeLists.txt
++===================================================================
++--- CMakeLists.txt      (revision 680923)
+++++ CMakeLists.txt      (working copy)
++@@ -1,4 +1,5 @@
++ add_subdirectory("time")
+++add_subdirectory("powermanagement")
++ add_subdirectory("soliddevice")
++ add_subdirectory("systemmonitor")
+\ No newline at end of file
+--- /dev/null
++++ b/plasma/dataengines/powermanagement/CMakeLists.txt
+@@ -0,0 +1,11 @@
++
++set(powermanagement_engine_SRCS
++    powermanagementengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_powermanagement ${powermanagement_engine_SRCS})
++target_link_libraries(plasma_engine_powermanagement ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS} plasma )
++
++install(TARGETS plasma_engine_powermanagement DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-powermanagement.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/Mainpage.dox
+@@ -0,0 +1,10 @@
++/**
++* @mainpage Engines
++*
++* Plasma engines power widgets.
++*
++*/
++
++// DOXYGEN_SET_PROJECT_NAME = Engines
++// DOXYGEN_SET_RECURSIVE = YES
++// vim:ts=4:sw=4:expandtab:filetype=doxygen
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/plasma-engine-soliddevice.desktop
+@@ -0,0 +1,22 @@
++[Desktop Entry]
++Name=SolidDevice Data Engine
++Name[ga]=Inneall Sonraí SolidDevice
++Name[ja]=SolidDevice データエンジン
++Name[nds]=SolidDevice-Hanteerkarn
++Name[ne]=ठोस यन्त्र डेटा इन्जिन
++Name[pt_BR]=Mecanismo de Dados SolidDevice
++Name[sv]=Datagränssnitt för Solid-enhet
++Name[zh_TW]=SolidDevice 資料引擎
++Comment=SolidDevice data for Plasmoids
++Comment[ga]=Sonraí SolidDevice le haghaidh Plasmoids
++Comment[ja]=Plasmoid のための SolidDevice データ
++Comment[nds]=SolidDevice-Daten för Plasmoiden
++Comment[ne]=प्लासमोइड्सका लागि ठोस यन्त्र डेटा
++Comment[pt_BR]=Dados de SolidDevice para os Plasmoids
++Comment[sv]=Data från Solid-enhet för Plasmoider
++Comment[zh_TW]=Plasmoids 的 SolidDevice 資料
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=alarmclock
++X-KDE-Library=plasma_engine_soliddevice
++X-EngineName=soliddevice
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/soliddeviceengine.cpp
+@@ -0,0 +1,699 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "soliddeviceengine.h"
++
++#include <KDebug>
++#include <KLocale>
++
++#include "plasma/datacontainer.h"
++
++#include <sys/stat.h>
++#include <sys/vfs.h>
++
++SolidDeviceEngine::SolidDeviceEngine(QObject* parent, const QVariantList& args)
++        : Plasma::DataEngine(parent)
++{
++    Q_UNUSED(args)
++    signalmanager = new DeviceSignalMapManager(this);
++}
++
++SolidDeviceEngine::~SolidDeviceEngine()
++{
++    delete signalmanager;
++}
++
++bool SolidDeviceEngine::sourceRequested(const QString &name)
++{
++    /* This creates a list of all available devices.  This must be called first before any other sources
++     * will be available.
++     */
++    if (name == "Devices") {
++        //if the devicelist is already populated, return
++        if (!devicelist.isEmpty()) {
++            return true;
++        }
++
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Processor)) {
++            processorlist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Proccessor List"), processorlist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Block)) {
++            blocklist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Block List"), blocklist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess)) {
++            storageaccesslist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Storage Access List"), storageaccesslist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::StorageDrive)) {
++            storagedrivelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Storage Drive List"), storagedrivelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::OpticalDrive)) {
++            opticaldrivelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Optical Drive List"), opticaldrivelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::StorageVolume)) {
++            storagevolumelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Storage Volume List"), storagevolumelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::OpticalDisc)) {
++            opticaldisclist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Optical Disc List"), opticaldisclist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Camera)) {
++            cameralist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Camera List"), cameralist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::PortableMediaPlayer)) {
++            portablemediaplayerlist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Portable Media Player List"), portablemediaplayerlist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::NetworkInterface)) {
++            networkinterfacelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Network Interface List"), networkinterfacelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::AcAdapter)) {
++            acadapterlist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Ac Adapter List"), acadapterlist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Battery)) {
++            batterylist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Battery List"), batterylist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Button)) {
++            buttonlist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Button List"), buttonlist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::AudioInterface)) {
++            audiointerfacelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Audio Interface List"), audiointerfacelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::DvbInterface)) {
++            dvbinterfacelist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("DVB Interface List"), dvbinterfacelist);
++        foreach(Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::Unknown)) {
++            unknownlist << device.udi();
++            if (!devicelist.contains(device.udi())) {
++                devicelist << device.udi();
++                devicemap[device.udi()] = device;
++            }
++        }
++        setData(name, I18N_NOOP("Unknown List"), unknownlist);
++
++        if (devicelist.isEmpty() ) {
++            return false;
++        }
++        setData(name, I18N_NOOP("Device List"), devicelist);
++
++        //detect when new devices are added
++        Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
++        connect(notifier, SIGNAL(deviceAdded(const QString&)),
++                this, SLOT(deviceAdded(const QString&)));
++        connect(notifier, SIGNAL(deviceRemoved(const QString&)),
++                this, SLOT(deviceRemoved(const QString&)));
++
++        return true;
++    }
++    else {
++        if (devicelist.contains(name) ) {
++            return populateDeviceData(name);
++        }
++        else {
++            return false;
++        }
++    }
++}
++
++bool SolidDeviceEngine::populateDeviceData(const QString &name)
++{
++    Solid::Device device = devicemap[name];
++    if (!device.isValid()) {
++        return false;
++    }
++
++    QStringList devicetypes;
++    setData(name, I18N_NOOP("Parent UDI"), device.parentUdi());
++    setData(name, I18N_NOOP("Vendor"), device.vendor());
++    setData(name, I18N_NOOP("Product"), device.product());
++    setData(name, I18N_NOOP("Icon"), device.icon());
++
++    if (processorlist.contains(name)) {
++        Solid::Processor *processor = device.as<Solid::Processor>();
++        if (processor == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Processor");
++        setData(name, I18N_NOOP("Number"), processor->number());
++        setData(name, I18N_NOOP("Max Speed"), processor->maxSpeed());
++        setData(name, I18N_NOOP("Can Change Frequency"), processor->canChangeFrequency());
++    }
++    if (blocklist.contains(name)) {
++        Solid::Block *block = device.as<Solid::Block>();
++        if (block == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Block");
++        setData(name, I18N_NOOP("Major"), block->deviceMajor());
++        setData(name, I18N_NOOP("Minor"), block->deviceMajor());
++        setData(name, I18N_NOOP("Device"), block->device());
++    }
++    if (storageaccesslist.contains(name)) {
++        Solid::StorageAccess *storageaccess = device.as<Solid::StorageAccess>();
++        if (storageaccess == 0) return false;
++
++        devicetypes << I18N_NOOP("Storage Access");
++        setData(name, I18N_NOOP("Accessible"), storageaccess->isAccessible());
++        setData(name, I18N_NOOP("File Path"), storageaccess->filePath());
++        setData(name, I18N_NOOP("Free Space"), freeDiskSpace(storageaccess->filePath()));
++
++        //signalmanager->mapDevice(storageaccess, device.udi());
++    }
++    if (storagedrivelist.contains(name)) {
++        Solid::StorageDrive *storagedrive = device.as<Solid::StorageDrive>();
++        if (storagedrive == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Storage Drive");
++
++        QStringList bus;
++        bus << I18N_NOOP("Ide") << I18N_NOOP("Usb") << I18N_NOOP("Ieee1394") << I18N_NOOP("Scsi") << I18N_NOOP("Sata") << I18N_NOOP("Platform");
++        QStringList drivetype;
++        drivetype << I18N_NOOP("Hard Disk") <<  I18N_NOOP("Cdrom Drive") <<  I18N_NOOP("Floppy") <<  I18N_NOOP("Tape") <<  I18N_NOOP("Compact Flash") <<  I18N_NOOP("Memory Stick") <<  I18N_NOOP("Smart Media") <<  I18N_NOOP("SdMmc") <<  I18N_NOOP("Xd");
++
++        setData(name, I18N_NOOP("Bus"), bus.at((int)storagedrive->bus()));
++        setData(name, I18N_NOOP("Drive Type"), drivetype.at((int)storagedrive->driveType()));
++        setData(name, I18N_NOOP("Removable"), storagedrive->isRemovable());
++        setData(name, I18N_NOOP("Hotpluggable"), storagedrive->isHotpluggable());
++    }
++    if (opticaldrivelist.contains(name)) {
++        Solid::OpticalDrive *opticaldrive = device.as<Solid::OpticalDrive>();
++        if (opticaldrive == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Optical Drive");
++
++        QStringList supportedtypes;
++        Solid::OpticalDrive::MediumTypes mediatypes = opticaldrive->supportedMedia();
++        if (mediatypes & Solid::OpticalDrive::Cdr) {
++            supportedtypes << I18N_NOOP("Cdr");
++        }
++        if (mediatypes & Solid::OpticalDrive::Cdrw) {
++            supportedtypes << I18N_NOOP("Cdrw");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvd) {
++            supportedtypes << I18N_NOOP("Dvd");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdr) {
++            supportedtypes << I18N_NOOP("Dvdr");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdrw) {
++            supportedtypes << I18N_NOOP("Dvdrw");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdram) {
++            supportedtypes << I18N_NOOP("Dvdram");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdplusr) {
++            supportedtypes << I18N_NOOP("Dvdplusr");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdplusrw) {
++            supportedtypes << I18N_NOOP("Dvdplusrw");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdplusdl) {
++            supportedtypes << I18N_NOOP("Dvdplusdl");
++        }
++        if (mediatypes & Solid::OpticalDrive::Dvdplusdlrw) {
++            supportedtypes << I18N_NOOP("Dvdplusdlrw");
++        }
++        if (mediatypes & Solid::OpticalDrive::Bd) {
++            supportedtypes << I18N_NOOP("Bd");
++        }
++        if (mediatypes & Solid::OpticalDrive::Bdr) {
++            supportedtypes << I18N_NOOP("Bdr");
++        }
++        if (mediatypes & Solid::OpticalDrive::Bdre) {
++            supportedtypes << I18N_NOOP("Bdre");
++        }
++        if (mediatypes & Solid::OpticalDrive::HdDvd) {
++            supportedtypes << I18N_NOOP("HdDvd");
++        }
++        if (mediatypes & Solid::OpticalDrive::HdDvdr) {
++            supportedtypes << I18N_NOOP("HdDvdr");
++        }
++        if (mediatypes & Solid::OpticalDrive::HdDvdrw) {
++            supportedtypes << I18N_NOOP("HdDvdrw");
++        }
++        setData(name, I18N_NOOP("Supported Media"), supportedtypes);
++
++        setData(name, I18N_NOOP("Read Speed"), opticaldrive->readSpeed());
++        setData(name, I18N_NOOP("Write Speed"), opticaldrive->writeSpeed());
++
++        //the following method return QList<int> so we need to convert it to QList<QVariant>
++        QList<int> writespeeds = opticaldrive->writeSpeeds();
++        QList<QVariant> variantlist = QList<QVariant>();
++        foreach(int num, writespeeds) {
++            variantlist << QVariant(num);
++        }
++        setData(name, I18N_NOOP("Write Speeds"), variantlist);
++
++    }
++    if (storagevolumelist.contains(name)) {
++        Solid::StorageVolume *storagevolume = device.as<Solid::StorageVolume>();
++        if (storagevolume == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Storage Volume");
++
++        QStringList usagetypes;
++        usagetypes << I18N_NOOP("File System") << I18N_NOOP("Partition Table") << I18N_NOOP("Raid") << I18N_NOOP("Other") << I18N_NOOP("Unused");
++
++        setData(name, I18N_NOOP("Ignored"), storagevolume->isIgnored());
++        setData(name, I18N_NOOP("Usage"), usagetypes.at((int)storagevolume->usage()));
++        setData(name, I18N_NOOP("File System Type"), storagevolume->fsType());
++        setData(name, I18N_NOOP("Label"), storagevolume->label());
++        setData(name, I18N_NOOP("Uuid"), storagevolume->uuid());
++        setData(name, I18N_NOOP("Size"), storagevolume->size());
++    }
++    if (opticaldisclist.contains(name)) {
++        Solid::OpticalDisc *opticaldisc = device.as<Solid::OpticalDisc>();
++        if (opticaldisc == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("OpticalDisc");
++
++        //get the content types
++        QStringList contenttypelist;
++        Solid::OpticalDisc::ContentTypes contenttypes = opticaldisc->availableContent();
++        if (contenttypes & Solid::OpticalDisc::Audio) {
++            contenttypelist << I18N_NOOP("Audio");
++        }
++        if (contenttypes & Solid::OpticalDisc::Audio) {
++            contenttypelist << I18N_NOOP("Data");
++        }
++        if (contenttypes & Solid::OpticalDisc::Audio) {
++            contenttypelist << I18N_NOOP("Video Cd");
++        }
++        if (contenttypes & Solid::OpticalDisc::Audio) {
++            contenttypelist << I18N_NOOP("Super Video Cd");
++        }
++        if (contenttypes & Solid::OpticalDisc::Audio) {
++            contenttypelist << I18N_NOOP("Video Dvd");
++        }
++        setData(name, I18N_NOOP("Available Content"), contenttypelist);
++
++        QStringList disctypes;
++        disctypes << I18N_NOOP("Unknown Disc Type") << I18N_NOOP("CD Rom") << I18N_NOOP("CD Recordable")
++                << I18N_NOOP("CD Rewritable") << I18N_NOOP("DVD Rom") << I18N_NOOP("DVD Ram")
++                << I18N_NOOP("DVD Recordable") << I18N_NOOP("DVD Rewritable") << I18N_NOOP("DVD Plus Recordable")
++                << I18N_NOOP("DVD Plus Rewritable") << I18N_NOOP("DVD Plus Recordable Duallayer")
++                << I18N_NOOP("DVD Plus Rewritable Duallayer") << I18N_NOOP("Blu Ray Rom") << I18N_NOOP("Blu Ray Recordable")
++                << I18N_NOOP("Blu Ray Rewritable") << I18N_NOOP("HD DVD Rom") <<  I18N_NOOP("HD DVD Recordable")
++                << I18N_NOOP("HD DVD Rewritable");
++        //+1 because the enum starts at -1
++        setData(name, I18N_NOOP("Disc Type"), disctypes.at((int)opticaldisc->discType() + 1));
++        setData(name, I18N_NOOP("Appendable"), opticaldisc->isAppendable());
++        setData(name, I18N_NOOP("Blank"), opticaldisc->isBlank());
++        setData(name, I18N_NOOP("Rewritable"), opticaldisc->isRewritable());
++        setData(name, I18N_NOOP("Capacity"), opticaldisc->capacity());
++    }
++    if (cameralist.contains(name)) {
++        Solid::Camera *camera = device.as<Solid::Camera>();
++        if (camera == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Camera");
++
++        setData(name, I18N_NOOP("Supported Protocols"), camera->supportedProtocols());
++        setData(name, I18N_NOOP("Supported Drivers"), camera->supportedDrivers());
++    }
++    if (portablemediaplayerlist.contains(name)) {
++        Solid::PortableMediaPlayer *mediaplayer = device.as<Solid::PortableMediaPlayer>();
++        if (mediaplayer == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Portable Media Player");
++
++        setData(name, I18N_NOOP("Supported Protocols"), mediaplayer->supportedProtocols());
++        setData(name, I18N_NOOP("Supported Drivers"), mediaplayer->supportedDrivers());
++    }
++    if (networkinterfacelist.contains(name)) {
++        Solid::NetworkInterface *networkinterface = device.as<Solid::NetworkInterface>();
++        if (networkinterface == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Network Interface");
++
++        setData(name, I18N_NOOP("Interface Name"), networkinterface->ifaceName());
++        setData(name, I18N_NOOP("Wireless"), networkinterface->isWireless());
++        setData(name, I18N_NOOP("Hardware Address"), networkinterface->hwAddress());
++        setData(name, I18N_NOOP("Mac Address"), networkinterface->macAddress());
++    }
++    if (acadapterlist.contains(name)) {
++        Solid::AcAdapter *ac = device.as<Solid::AcAdapter>();
++        if (ac == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("AD Adapter");
++
++        setData(name, I18N_NOOP("Plugged In"), ac->isPlugged());
++        signalmanager->mapDevice(ac, device.udi());
++    }
++    if (batterylist.contains(name)) {
++        Solid::Battery *battery = device.as<Solid::Battery>();
++        if (battery == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Battery");
++
++        QStringList batterytype;
++        batterytype << I18N_NOOP("Unknown Battery") << I18N_NOOP("PDA Battery") << I18N_NOOP("UPS Battery")
++                << I18N_NOOP("Primary Battery") << I18N_NOOP("Mouse Battery") << I18N_NOOP("Keyboard Battery")
++                << I18N_NOOP("Keyboard Mouse Battery") << I18N_NOOP("Camera Battery");
++
++        QStringList chargestate;
++        chargestate << I18N_NOOP("Fully Charged") << I18N_NOOP("Charging") << I18N_NOOP("Discharging");
++
++        setData(name, I18N_NOOP("Plugged In"), battery->isPlugged());
++        setData(name, I18N_NOOP("Type"), batterytype.at((int)battery->type()));
++        setData(name, I18N_NOOP("Charge Percent"), battery->chargePercent());
++        setData(name, I18N_NOOP("Rechargeable"), battery->isRechargeable());
++        setData(name, I18N_NOOP("Charge State"), chargestate.at((int)battery->chargeState()));
++
++        signalmanager->mapDevice(battery, device.udi());
++    }
++    if (buttonlist.contains(name)) {
++        Solid::Button *button = device.as<Solid::Button>();
++        if (button == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Button");
++
++        QStringList buttontype;
++        buttontype << I18N_NOOP("Lid Button") << I18N_NOOP("Power Button") << I18N_NOOP("Sleep Button")
++                << I18N_NOOP("Unknown Button Type");
++
++        setData(name, I18N_NOOP("Type"), buttontype.at((int)button->type()));
++        setData(name, I18N_NOOP("Has State"), button->hasState());
++        setData(name, I18N_NOOP("State Value"), button->stateValue());
++        setData(name, I18N_NOOP("Pressed"), false);  //this is an extra value that is tracked by the button signals
++
++        signalmanager->mapDevice(button, device.udi());
++    }
++    if (audiointerfacelist.contains(name)) {
++        Solid::AudioInterface *audiointerface = device.as<Solid::AudioInterface>();
++        if (audiointerface == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("Audio Interface");
++
++        QStringList audiodriver;
++        audiodriver << I18N_NOOP("ALSA") << I18N_NOOP("Open Sound System") << I18N_NOOP("Unknown Audio Driver");
++
++        setData(name, I18N_NOOP("Driver"), audiodriver.at((int)audiointerface->driver()));
++        setData(name, I18N_NOOP("Driver Handle"), audiointerface->driverHandle());
++        setData(name, I18N_NOOP("Name"), audiointerface->name());
++
++        //get AudioInterfaceTypes
++        QStringList audiointerfacetypes;
++        Solid::AudioInterface::AudioInterfaceTypes devicetypes = audiointerface->deviceType();
++        if (devicetypes & Solid::AudioInterface::UnknownAudioInterfaceType) {
++            audiointerfacetypes << I18N_NOOP("Unknown Audio Interface Type");
++        }
++        if (devicetypes & Solid::AudioInterface::AudioControl) {
++            audiointerfacetypes << I18N_NOOP("Audio Control");
++        }
++        if (devicetypes & Solid::AudioInterface::AudioInput) {
++            audiointerfacetypes << I18N_NOOP("Audio Input");
++        }
++        if (devicetypes & Solid::AudioInterface::AudioOutput) {
++            audiointerfacetypes << I18N_NOOP("Audio Output");
++        }
++        setData(name, I18N_NOOP("Audio Device Type"), audiointerfacetypes);
++
++        //get SoundCardTypes
++        QStringList soundcardtype;
++        soundcardtype << I18N_NOOP("Internal Soundcard") << I18N_NOOP("USB Soundcard") << I18N_NOOP("Firewire Soundcard")
++                << I18N_NOOP("Headset") << I18N_NOOP("Modem");
++        setData(name, I18N_NOOP("Soundcard Type"), soundcardtype.at((int)audiointerface->soundcardType()));
++    }
++    if (dvbinterfacelist.contains(name)) {
++        Solid::DvbInterface *dvbinterface = device.as<Solid::DvbInterface>();
++        if (dvbinterface == 0) {
++            return false;
++        }
++
++        devicetypes << I18N_NOOP("DVB Interface");
++
++        setData(name, I18N_NOOP("Device"), dvbinterface->device());
++        setData(name, I18N_NOOP("Device Adapter"), dvbinterface->deviceAdapter());
++
++        //get devicetypes
++        QStringList dvbdevicetypes;
++        dvbdevicetypes << I18N_NOOP("DVB Unknown") << I18N_NOOP("DVB Audio") << I18N_NOOP("DVB Ca")
++                << I18N_NOOP("DVB Demux") << I18N_NOOP("DVB DVR") << I18N_NOOP("DVB Frontend")
++                << I18N_NOOP("DVB Net") << I18N_NOOP("DVB OSD") << I18N_NOOP("DVB Sec") << I18N_NOOP("DVB Video");
++
++        setData(name, I18N_NOOP("DVB Device Type"), dvbdevicetypes.at((int)dvbinterface->deviceType()));
++        setData(name, I18N_NOOP("Device Index"), dvbinterface->deviceIndex());
++    }
++    setData(name, I18N_NOOP("Device Types"), devicetypes);
++    return true;
++}
++
++void SolidDeviceEngine::deviceAdded(const QString& udi)
++{
++    devicelist << udi;
++    QString name = I18N_NOOP("Devices");
++    setData(name, I18N_NOOP("Device List"), devicelist);
++
++    //add to device specific lists
++    Solid::Device device(udi);
++    if (device.is<Solid::Processor>()) {
++        processorlist << udi;
++        setData(name, I18N_NOOP("Proccessor List"), processorlist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::Block>()) {
++        blocklist << udi;
++        setData(name, I18N_NOOP("Block List"), blocklist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::StorageAccess>()) {
++        storageaccesslist << udi;
++        setData(name, I18N_NOOP("Storage Access List"), storageaccesslist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::StorageDrive>()) {
++        storagedrivelist << udi;
++        setData(name, I18N_NOOP("Storage Drive List"), storagedrivelist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::OpticalDrive>()) {
++        opticaldrivelist << udi;
++        setData(name, I18N_NOOP("Optical Drive List"), opticaldrivelist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::StorageVolume>()) {
++        storagevolumelist << udi;
++        setData(name, I18N_NOOP("Storage Volume List"), storagevolumelist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::OpticalDisc>()) {
++        opticaldisclist << udi;
++        setData(name, I18N_NOOP("Optical Disc List"), opticaldisclist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::Camera>()) {
++        cameralist << udi;
++        setData(name, I18N_NOOP("Camera List"), cameralist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::PortableMediaPlayer>()) {
++        portablemediaplayerlist << udi;
++        setData(name, I18N_NOOP("Portable Media Player List"), portablemediaplayerlist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::NetworkInterface>()) {
++        networkinterfacelist << udi;
++        setData(name, I18N_NOOP("Network Interface List"), networkinterfacelist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::AcAdapter>()) {
++        acadapterlist << udi;
++        setData(name, I18N_NOOP("AD Adapter List"), acadapterlist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::Battery>()) {
++        batterylist << udi;
++        setData(name, I18N_NOOP("Battery List"), batterylist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::Button>()) {
++        buttonlist << udi;
++        setData(name, I18N_NOOP("Button List"), buttonlist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::AudioInterface>()) {
++        audiointerfacelist << udi;
++        setData(name, I18N_NOOP("Audio Interface List"), audiointerfacelist);
++        devicemap[udi] = device;
++    }
++    if (device.is<Solid::DvbInterface>()) {
++        dvbinterfacelist << udi;
++        setData(name, I18N_NOOP("DVB Interface List"), dvbinterfacelist);
++        devicemap[udi] = device;
++    }
++
++    checkForUpdates();
++}
++
++qlonglong SolidDeviceEngine::freeDiskSpace(const QString &mountPoint)
++{
++    //determine the free space available on the device
++    const char *path=mountPoint.toAscii().constData();
++
++    struct statfs fs_obj;
++    if (statfs(path,&fs_obj) < 0){
++        return -1;
++    }
++    else{
++        return (qlonglong)fs_obj.f_bfree*(qlonglong)fs_obj.f_bsize;
++    }
++}
++
++bool SolidDeviceEngine::updateFreeSpace(const QString &udi)
++{
++    if (storageaccesslist.contains(udi)){
++        Solid::Device device = devicemap[udi];
++        if (!device.isValid()) {
++            return false;
++        }
++        
++        Solid::StorageAccess *storageaccess = device.as<Solid::StorageAccess>();
++        if (storageaccess == 0) return false;
++        setData(udi, I18N_NOOP("Free Space"), freeDiskSpace(storageaccess->filePath()));
++        return true;
++    }
++    return false;
++}
++
++bool SolidDeviceEngine::updateSource(const QString& source)
++{
++    if (storageaccesslist.contains(source)){
++        updateFreeSpace(source);
++        return true;
++    }
++    else{
++        return false;
++    }
++}
++
++void SolidDeviceEngine::deviceRemoved(const QString& udi)
++{
++    int pos = devicelist.indexOf(udi);
++    if (pos > -1) {
++        devicelist.removeAt(pos);
++        devicemap.remove(udi);
++        removeSource(udi);
++        setData(I18N_NOOP("Devices"), I18N_NOOP("Device List"), devicelist);
++    }
++    checkForUpdates();
++}
++
++void SolidDeviceEngine::deviceChanged(const QString& udi, const QString &property, const QVariant &value)
++{
++    setData(udi, property, value);
++    checkForUpdates();
++}
++
++#include "soliddeviceengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/devicesignalmapper.cpp
+@@ -0,0 +1,100 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "devicesignalmapper.h"
++
++DeviceSignalMapper::DeviceSignalMapper(QObject *parent) : QSignalMapper(parent)
++{
++}
++
++DeviceSignalMapper::~DeviceSignalMapper()
++{
++}
++
++void DeviceSignalMapper::setMapping(QObject* device, const QString &udi)
++{
++    signalmap[device] = udi;
++}
++
++AcAdapterSignalMapper::AcAdapterSignalMapper(QObject *parent) : DeviceSignalMapper(parent)
++{
++}
++
++AcAdapterSignalMapper::~AcAdapterSignalMapper()
++{
++}
++
++void AcAdapterSignalMapper::plugStateChanged(bool newState)
++{
++    emit(deviceChanged(signalmap[sender()], "Plugged In", newState));
++}
++
++
++ButtonSignalMapper::ButtonSignalMapper(QObject *parent) : DeviceSignalMapper(parent)
++{
++}
++
++ButtonSignalMapper::~ButtonSignalMapper()
++{
++}
++
++void ButtonSignalMapper::pressed(Solid::Button::ButtonType type)
++{
++    Q_UNUSED(type)
++    emit(deviceChanged(signalmap[sender()], "Pressed", true));
++}
++
++BatterySignalMapper::BatterySignalMapper(QObject *parent) : DeviceSignalMapper(parent)
++{
++}
++
++BatterySignalMapper::~BatterySignalMapper()
++{
++}
++
++void BatterySignalMapper::chargePercentChanged(int value)
++{
++    emit(deviceChanged(signalmap[sender()], "Charge Percent", value));
++}
++
++void BatterySignalMapper::chargeStateChanged(int newState)
++{
++    QStringList chargestate;
++    chargestate << "Fully Charged" << "Charging" << "Discharging";
++    emit(deviceChanged(signalmap[sender()], "Charge State", chargestate.at(newState)));
++}
++
++void BatterySignalMapper::plugStateChanged(bool newState)
++{
++    emit(deviceChanged(signalmap[sender()], "Plugged In", newState));
++}
++
++StorageAccessSignalMapper::StorageAccessSignalMapper(QObject *parent) : DeviceSignalMapper(parent)
++{
++}
++
++StorageAccessSignalMapper::~StorageAccessSignalMapper()
++{
++}
++
++void StorageAccessSignalMapper::accessibilityChanged(bool accessible)
++{
++    emit(deviceChanged(signalmap[sender()], "Accessible", accessible));
++}
++
++#include "devicesignalmapper.moc"
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/soliddeviceengine.h
+@@ -0,0 +1,81 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef SOLIDDEVICEENGINE_H
++#define SOLIDDEVICEENGINE_H
++
++#include <QObject>
++#include <QString>
++#include <QList>
++#include <QMap>
++
++#include "plasma/dataengine.h"
++#include "devicesignalmapmanager.h"
++#include "devicesignalmapper.h"
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++class SolidDeviceEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++public:
++    SolidDeviceEngine( QObject* parent, const QVariantList& args);
++    ~SolidDeviceEngine();
++
++protected:
++    bool sourceRequested(const QString &name);
++    bool updateSource(const QString& source);
++
++private:
++    bool populateDeviceData(const QString &name);
++    qlonglong freeDiskSpace(const QString &mountPoint);
++    bool updateFreeSpace(const QString &udi);
++    
++    QStringList devicelist;
++    //setup lists for devicetypes
++    QStringList processorlist;
++    QStringList blocklist;
++    QStringList storageaccesslist;
++    QStringList storagedrivelist;
++    QStringList opticaldrivelist;
++    QStringList storagevolumelist;
++    QStringList opticaldisclist;
++    QStringList cameralist;
++    QStringList portablemediaplayerlist;
++    QStringList networkinterfacelist;
++    QStringList acadapterlist;
++    QStringList batterylist;
++    QStringList buttonlist;
++    QStringList audiointerfacelist;
++    QStringList dvbinterfacelist;
++    QStringList unknownlist;
++    
++    QMap<QString, Solid::Device> devicemap;
++    DeviceSignalMapManager *signalmanager;
++
++private Q_SLOTS:
++    void deviceAdded(const QString &udi);
++    void deviceRemoved(const QString &udi);
++    void deviceChanged(const QString& udi, const QString &property, const QVariant &value);
++};
++
++K_EXPORT_PLASMA_DATAENGINE(soliddevice, SolidDeviceEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/devicesignalmapmanager.cpp
+@@ -0,0 +1,130 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "devicesignalmapmanager.h"
++
++DeviceSignalMapManager::DeviceSignalMapManager(QObject *parent) : QObject(parent)
++{
++    user = parent;
++}
++
++DeviceSignalMapManager::~DeviceSignalMapManager()
++{
++}
++
++void DeviceSignalMapManager::mapDevice(Solid::AcAdapter *ac, const QString &udi)
++{
++    AcAdapterSignalMapper *map=0;
++    if(!signalmap.contains(Solid::DeviceInterface::AcAdapter)) {
++        signalmap[Solid::DeviceInterface::AcAdapter] = new AcAdapterSignalMapper();
++    }
++    map = (AcAdapterSignalMapper*)signalmap[Solid::DeviceInterface::AcAdapter];
++
++    connect(ac, SIGNAL(plugStateChanged(bool)), map, SLOT(plugStateChanged(bool)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    map->setMapping(ac, udi);
++}
++
++void DeviceSignalMapManager::mapDevice(Solid::Button *button, const QString &udi)
++{
++    ButtonSignalMapper *map=0;
++    if(!signalmap.contains(Solid::DeviceInterface::Button)) {
++        signalmap[Solid::DeviceInterface::Button] = new ButtonSignalMapper();
++    }
++    map = (ButtonSignalMapper*)signalmap[Solid::DeviceInterface::Button];
++
++    connect(button, SIGNAL(pressed(Solid::Button::ButtonType)), map, SLOT(pressed(Solid::Button::ButtonType)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    map->setMapping(button, udi);
++}
++
++void DeviceSignalMapManager::mapDevice(Solid::Battery *battery, const QString &udi)
++{
++    BatterySignalMapper *map=0;
++    if(!signalmap.contains(Solid::DeviceInterface::Battery)) {
++        signalmap[Solid::DeviceInterface::Battery] = new BatterySignalMapper();
++    }
++    map = (BatterySignalMapper*)signalmap[Solid::DeviceInterface::Battery];
++
++    connect(battery, SIGNAL(chargePercentChanged(int)), map, SLOT(chargePercentChanged(int)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    connect(battery, SIGNAL(chargeStateChanged(int)), map, SLOT(chargeStateChanged(int)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    connect(battery, SIGNAL(plugStateChanged(bool)), map, SLOT(plugStateChanged(bool)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    map->setMapping(battery, udi);
++}
++
++void DeviceSignalMapManager::mapDevice(Solid::StorageAccess *storageaccess, const QString &udi)
++{
++    StorageAccessSignalMapper *map=0;
++    if(!signalmap.contains(Solid::DeviceInterface::StorageAccess)) {
++        signalmap[Solid::DeviceInterface::StorageAccess] = new StorageAccessSignalMapper();
++    }
++    map = (StorageAccessSignalMapper*)signalmap[Solid::DeviceInterface::StorageAccess];
++
++    connect(storageaccess, SIGNAL(chargePercentChanged(int)), map, SLOT(chargePercentChanged(int)));
++    connect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    map->setMapping(storageaccess, udi);
++}
++
++void DeviceSignalMapManager::unmapDevice(Solid::AcAdapter *ac)
++{
++    if(!signalmap.contains(Solid::DeviceInterface::AcAdapter)) {
++        return;
++    }
++    AcAdapterSignalMapper *map = (AcAdapterSignalMapper*)signalmap[Solid::DeviceInterface::AcAdapter];
++    disconnect(ac, SIGNAL(plugStateChanged(bool)), map, SLOT(plugStateChanged(bool)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++}
++
++void DeviceSignalMapManager::unmapDevice(Solid::Button *button)
++{
++    if(!signalmap.contains(Solid::DeviceInterface::Button)) {
++        return;
++    }
++    ButtonSignalMapper *map = (ButtonSignalMapper*)signalmap[Solid::DeviceInterface::Button];
++    disconnect(button, SIGNAL(pressed(Solid::Button::ButtonType)), map, SLOT(pressed(Solid::Button::ButtonType)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++}
++
++void DeviceSignalMapManager::unmapDevice(Solid::Battery *battery)
++{
++    if(!signalmap.contains(Solid::DeviceInterface::Battery)) {
++        return;
++    }
++    BatterySignalMapper *map = (BatterySignalMapper*)signalmap[Solid::DeviceInterface::Battery];
++    disconnect(battery, SIGNAL(chargePercentChanged(int)), map, SLOT(chargePercentChanged(int)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    disconnect(battery, SIGNAL(chargeStateChanged(int)), map, SLOT(chargeStateChanged(int)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++    disconnect(battery, SIGNAL(plugStateChanged(bool)), map, SLOT(plugStateChanged(bool)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++}
++
++void DeviceSignalMapManager::unmapDevice(Solid::StorageAccess *storageaccess)
++{
++    if(!signalmap.contains(Solid::DeviceInterface::StorageAccess)) {
++        return;
++    }
++    StorageAccessSignalMapper *map = (StorageAccessSignalMapper*)signalmap[Solid::DeviceInterface::StorageAccess];
++    disconnect(storageaccess, SIGNAL(chargePercentChanged(int)), map, SLOT(chargePercentChanged(int)));
++    disconnect(map, SIGNAL(deviceChanged(const QString&, const QString &, QVariant)), user, SLOT(deviceChanged(const QString&, const QString &, QVariant)));
++}
++
++#include "devicesignalmapmanager.moc"
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/devicesignalmapper.h
+@@ -0,0 +1,113 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef DEVICE_SIGNAL_MAPPER_H
++#define DEVICE_SIGNAL_MAPPER_H
++
++#include <QObject>
++#include <QSignalMapper>
++#include <QMap>
++
++#include <KDebug>
++
++#include <solid/devicenotifier.h>
++#include <solid/device.h>
++#include <solid/processor.h>
++#include <solid/block.h>
++#include <solid/storageaccess.h>
++#include <solid/storagedrive.h>
++#include <solid/opticaldrive.h>
++#include <solid/storagevolume.h>
++#include <solid/opticaldisc.h>
++#include <solid/camera.h>
++#include <solid/portablemediaplayer.h>
++#include <solid/networkinterface.h>
++#include <solid/acadapter.h>
++#include <solid/battery.h>
++#include <solid/button.h>
++#include <solid/audiointerface.h>
++#include <solid/dvbinterface.h>
++
++class DeviceSignalMapper : public QSignalMapper
++{
++    Q_OBJECT
++
++    public:
++        DeviceSignalMapper(QObject *parent=0);
++        ~DeviceSignalMapper();
++        
++        void setMapping(QObject* device, const QString &udi);
++
++    Q_SIGNALS:
++        void deviceChanged(const QString& udi, const QString &property, QVariant value);
++        
++    protected:
++        QMap<QObject*, QString> signalmap;
++};
++
++class AcAdapterSignalMapper : public DeviceSignalMapper
++{
++    Q_OBJECT
++
++    public:
++        AcAdapterSignalMapper(QObject *parent=0);
++        ~AcAdapterSignalMapper();
++
++    public Q_SLOTS:
++        void plugStateChanged(bool newState);
++};
++
++class ButtonSignalMapper : public DeviceSignalMapper
++{
++    Q_OBJECT
++
++    public:
++        ButtonSignalMapper(QObject *parent=0);
++        ~ButtonSignalMapper();
++
++    public Q_SLOTS:
++        void pressed(Solid::Button::ButtonType type);
++};
++
++class BatterySignalMapper : public DeviceSignalMapper
++{
++    Q_OBJECT
++
++    public:
++        BatterySignalMapper(QObject *parent=0);
++        ~BatterySignalMapper();
++
++    public Q_SLOTS:
++        void chargePercentChanged(int value);
++        void chargeStateChanged(int newState);
++        void plugStateChanged(bool newState);
++};
++
++class StorageAccessSignalMapper : public DeviceSignalMapper
++{
++    Q_OBJECT
++
++    public:
++        StorageAccessSignalMapper(QObject *parent=0);
++        ~StorageAccessSignalMapper();
++
++    public Q_SLOTS:
++        void accessibilityChanged(bool accessible);
++};
++
++#endif 
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/devicesignalmapmanager.h
+@@ -0,0 +1,50 @@
++/*
++ *   Copyright (C) 2007 Christopher Blauvelt <cblauvelt at gmail.com>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details
++ *
++ *   You should have received a copy of the GNU Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef DEVICE_SIGNALMAP_MANAGER_H
++#define DEVICE_SIGNALMAP_MANAGER_H
++
++#include <KDebug>
++
++#include "devicesignalmapper.h"
++
++class DeviceSignalMapManager : public QObject
++{
++    Q_OBJECT
++
++    public:
++        DeviceSignalMapManager(QObject *parent=0);
++        ~DeviceSignalMapManager();
++
++        void mapDevice(Solid::AcAdapter *ac, const QString &udi);
++        void mapDevice(Solid::Button *button, const QString &udi);
++        void mapDevice(Solid::Battery *battery, const QString &udi);
++        void mapDevice(Solid::StorageAccess *storageaccess, const QString &udi);
++        
++        void unmapDevice(Solid::AcAdapter *ac);
++        void unmapDevice(Solid::Button *button);
++        void unmapDevice(Solid::Battery *battery);
++        void unmapDevice(Solid::StorageAccess *storageaccess);
++        
++    private:
++        QMap<QString, Solid::DeviceInterface*> devicemap;
++        QMap<Solid::DeviceInterface::Type, DeviceSignalMapper*> signalmap;
++        QObject *user;
++};
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/soliddevice/CMakeLists.txt
+@@ -0,0 +1,14 @@
++include_directories(${CMAKE_SOURCE_DIR}/workspace/libs)
++
++set(soliddevice_engine_SRCS
++    soliddeviceengine.cpp
++    devicesignalmapper.cpp
++    devicesignalmapmanager.cpp
++)
++
++kde4_add_plugin(plasma_engine_soliddevice ${soliddevice_engine_SRCS})
++target_link_libraries(plasma_engine_soliddevice ${KDE4_KDECORE_LIBS} ${KDE4_SOLID_LIBS} plasma)
++
++install(TARGETS plasma_engine_soliddevice DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-soliddevice.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- /dev/null
++++ b/plasma/dataengines/CMakeLists.txt
+@@ -0,0 +1,10 @@
++add_subdirectory(dict)
++add_subdirectory(hotplug)
++add_subdirectory(filebrowser)
++add_subdirectory(mouse)
++add_subdirectory(places)
++add_subdirectory(powermanagement)
++add_subdirectory(tasks)
++add_subdirectory(time)
++add_subdirectory(weather)
++add_subdirectory(soliddevice)
+--- /dev/null
++++ b/plasma/dataengines/time/plasma-engine-time.desktop
+@@ -0,0 +1,60 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Time Data Engine
++Name[ar]=محرك بيانات الوقت
++Name[be]=Рухавік дадзеных Time
++Name[de]=Zeitdaten-Treiber
++Name[el]=Μηχανή δεδομένων χρόνου
++Name[es]=Motor de datos horarios
++Name[et]=Aja andmete mootor
++Name[fa]=موتور دادۀ زمان
++Name[ga]=Inneall Sonraí Ama
++Name[he]=מנוע נתוני זמן
++Name[ja]=時間データエンジン
++Name[kk]=Уақыт дерек тетігі
++Name[km]=ម៉ាស៊ីន​ទិន្នន័យ​ពេលវេលា​
++Name[ko]=시간 데이터 엔진
++Name[nb]=Tidsdata-motor
++Name[nds]=Tiet-Hanteerkarn
++Name[ne]=समय डेटा इन्जिन
++Name[nl]=Tijd (gegevensengine)
++Name[nn]=Tidsdatamotor
++Name[pa]=ਸਮਾਂ ਡਾਟਾ ਇੰਜਣ
++Name[pt]=Motor de Dados Horários
++Name[pt_BR]=Mecanismo de Dados de Tempo
++Name[sv]=Datagränssnitt för tid
++Name[vi]=Cơ chế dữ liệu thời gian
++Name[x-test]=xxTime Data Enginexx
++Name[zh_CN]=时间数据引擎
++Name[zh_TW]=時間資料引擎
++Comment=Time data for Plasmoids
++Comment[bg]=Време за Plasmoids
++Comment[de]=Zeitdaten für Plasmoide
++Comment[el]=Δεδομένα χρόνου για πλασμοειδή
++Comment[es]=Datos horarios para los plasmoides
++Comment[et]=Ajaandmed plasmoididele
++Comment[fa]=داده زمان برای Plasmoids
++Comment[ga]=Sonraí ama le haghaidh Plasmoids
++Comment[he]=נתוני זמן עבור פלסמואידים
++Comment[ja]=Plasmoid のための時間データ
++Comment[kk]=Плазмоидтер үшін уақыт деректері
++Comment[km]=ទិន្នន័យ​ពេល​វេលា​សម្រាប់ Plasmoids
++Comment[ko]=Plasmoid를 위한 시간 데이터
++Comment[nb]=Tidsdata for Plasmoids
++Comment[nds]=Tietdaten för Plasmoiden
++Comment[ne]=प्लासमोइड्सका लागि समय डेटा
++Comment[nl]=Tijdgegevens voor Plasmoids
++Comment[nn]=Tidsdata for plasmoidar
++Comment[pa]=ਪਲਾਜਮੋਡੀਸ ਲਈ ਟਾਈਮ ਡਾਟਾ
++Comment[pt]=Dados de data/hora para os Plasmóides
++Comment[pt_BR]=Dados de tempo para os Plasmoids
++Comment[sv]=Tiddata för Plasmoider
++Comment[vi]=Dữ liệu thời gian cho Plasmoids
++Comment[x-test]=xxTime data for Plasmoidsxx
++Comment[zh_CN]=Plasmoids 的时间数据
++Comment[zh_TW]=電漿時鐘的時間資料
++ServiceTypes=Plasma/DataEngine
++Type=Service
++Icon=alarmclock
++X-KDE-Library=plasma_engine_time
++X-EngineName=time
+--- /dev/null
++++ b/plasma/dataengines/time/timeengine.cpp
+@@ -0,0 +1,86 @@
++/*
++ *   Copyright 2007 Aaron Seigo <aseigo at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License as
++ *   published by the Free Software Foundation; either version 2 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "timeengine.h"
++
++#include <QDate>
++#include <QTime>
++#include <QTimer>
++
++#include <KDebug>
++#include <KLocale>
++#include <KSystemTimeZones>
++#include <KDateTime>
++
++#include "plasma/datacontainer.h"
++
++TimeEngine::TimeEngine(QObject* parent, const QVariantList& args)
++    : Plasma::DataEngine(parent)
++{
++    Q_UNUSED(args)
++    setMinimumUpdateInterval(333);
++}
++
++TimeEngine::~TimeEngine()
++{
++}
++
++bool TimeEngine::sourceRequested(const QString &name)
++{
++    //kDebug() << "TimeEngine::sourceRequested " << name;
++    if (name == "Local") {
++        setData(I18N_NOOP("Local"), I18N_NOOP("Time"), QTime::currentTime());
++        setData(I18N_NOOP("Local"), I18N_NOOP("Date"), QDate::currentDate());
++
++        return true;
++    }
++
++    KTimeZone newTz  = KSystemTimeZones::zone(name);
++    if (!newTz.isValid()) {
++        return false;
++    }
++
++    KDateTime dt = KDateTime::currentDateTime(newTz);
++    setData(name, I18N_NOOP("Time"), dt.time());
++    setData(name, I18N_NOOP("Date"), dt.date());
++
++    return true;
++}
++
++bool TimeEngine::updateSource(const QString &tz)
++{
++    //kDebug() << "TimeEngine::updateTime()";
++
++    QDateTime dt = QDateTime::currentDateTime();
++    KTimeZone local = KSystemTimeZones::local();
++    static const QString localName = I18N_NOOP("Local");
++    if (tz == localName) {
++        setData(tz, I18N_NOOP("Time"), dt.time());
++        setData(tz, I18N_NOOP("Date"), dt.date());
++    } else {
++        KTimeZone newTz = KSystemTimeZones::zone(tz);
++        QDateTime localizeDt = local.convert(newTz, dt);
++        setData(tz, I18N_NOOP("Time"), localizeDt.time());
++        setData(tz, I18N_NOOP("Date"), localizeDt.date());
++    }
++
++    return true;
++}
++
++#include "timeengine.moc"
+--- /dev/null
++++ b/plasma/dataengines/time/timeengine.h
+@@ -0,0 +1,45 @@
++/*
++ *   Copyright 2007 Aaron Seigo <aseigo at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License as
++ *   published by the Free Software Foundation; either version 2 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef TIMEENGINE_H
++#define TIMEENGINE_H
++
++#include "plasma/dataengine.h"
++
++class QTimer;
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++class TimeEngine : public Plasma::DataEngine
++{
++    Q_OBJECT
++
++    public:
++        TimeEngine(QObject* parent, const QVariantList& args);
++        ~TimeEngine();
++
++    protected:
++        bool sourceRequested(const QString &name);
++        bool updateSource(const QString& source);
++};
++
++K_EXPORT_PLASMA_DATAENGINE(time, TimeEngine)
++
++#endif
+--- /dev/null
++++ b/plasma/dataengines/time/CMakeLists.txt
+@@ -0,0 +1,10 @@
++set(time_engine_SRCS
++    timeengine.cpp
++)
++
++kde4_add_plugin(plasma_engine_time ${time_engine_SRCS})
++target_link_libraries(plasma_engine_time ${KDE4_KDECORE_LIBS} plasma)
++
++install(TARGETS plasma_engine_time DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-engine-time.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
++
+--- a/plasma/engineexplorer/engineexplorer.ui
++++ b/plasma/engineexplorer/engineexplorer.ui
+@@ -5,23 +5,11 @@
+    <rect>
+     <x>0</x>
+     <y>0</y>
+-    <width>400</width>
++    <width>513</width>
+     <height>300</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" >
+-   <property name="leftMargin" >
+-    <number>0</number>
+-   </property>
+-   <property name="topMargin" >
+-    <number>0</number>
+-   </property>
+-   <property name="rightMargin" >
+-    <number>0</number>
+-   </property>
+-   <property name="bottomMargin" >
+-    <number>0</number>
+-   </property>
+    <item>
+     <widget class="KTitleWidget" name="m_title" >
+      <property name="text" >
+@@ -40,7 +28,7 @@
+         <bool>false</bool>
+        </property>
+        <property name="clickMessage" >
+-        <string>Request a datasource</string>
++        <string>Source name</string>
+        </property>
+        <property name="showClearButton" stdset="0" >
+         <bool>true</bool>
+@@ -48,6 +36,31 @@
+       </widget>
+      </item>
+      <item>
++      <widget class="QSpinBox" name="m_updateInterval" >
++       <property name="enabled" >
++        <bool>false</bool>
++       </property>
++       <property name="suffix" >
++        <string>ms</string>
++       </property>
++       <property name="prefix" >
++        <string>update every </string>
++       </property>
++       <property name="minimum" >
++        <number>0</number>
++       </property>
++       <property name="maximum" >
++        <number>100000</number>
++       </property>
++       <property name="singleStep" >
++        <number>50</number>
++       </property>
++       <property name="value" >
++        <number>50</number>
++       </property>
++      </widget>
++     </item>
++     <item>
+       <widget class="QPushButton" name="m_sourceRequesterButton" >
+        <property name="enabled" >
+         <bool>false</bool>
+@@ -99,8 +112,24 @@
+      <y>92</y>
+     </hint>
+     <hint type="destinationlabel" >
+-     <x>362</x>
+-     <y>90</y>
++     <x>502</x>
++     <y>109</y>
++    </hint>
++   </hints>
++  </connection>
++  <connection>
++   <sender>m_updateInterval</sender>
++   <signal>editingFinished()</signal>
++   <receiver>m_sourceRequesterButton</receiver>
++   <slot>animateClick()</slot>
++   <hints>
++    <hint type="sourcelabel" >
++     <x>375</x>
++     <y>91</y>
++    </hint>
++    <hint type="destinationlabel" >
++     <x>447</x>
++     <y>94</y>
+     </hint>
+    </hints>
+   </connection>
+--- a/plasma/engineexplorer/engineexplorer.cpp
++++ b/plasma/engineexplorer/engineexplorer.cpp
+@@ -22,6 +22,8 @@
+ #include <QApplication>
+ #include <QStandardItemModel>
+ #include <QVBoxLayout>
++#include <QHBoxLayout>
++#include <QSpinBox>
+ 
+ #include <KAction>
+ #include <KIconLoader>
+@@ -35,8 +37,6 @@
+       m_engine(0),
+       m_sourceCount(0)
+ {
+-    setButtons(KDialog::Close);
+-    setDefaultButton(KDialog::NoDefault);
+     setWindowTitle(i18n("Plasma Engine Explorer"));
+     QWidget* mainWidget = new QWidget(this);
+     setMainWidget(mainWidget);
+@@ -82,7 +82,9 @@
+ {
+     m_engines->clear();
+     m_engines->addItem("");
+-    m_engines->addItems(m_engineManager->knownEngines());
++    QStringList engines = m_engineManager->knownEngines();
++    qSort(engines);
++    m_engines->addItems(engines);
+ }
+ 
+ void EngineExplorer::showEngine(const QString& name)
+@@ -124,6 +126,7 @@
+     }
+ 
+     m_sourceRequesterButton->setEnabled(true);
++    m_updateInterval->setEnabled(true);
+     m_sourceRequester->setEnabled(true);
+     m_sourceRequester->setFocus();
+     connect(m_engine, SIGNAL(newSource(QString)), this, SLOT(addSource(QString)));
+@@ -173,7 +176,7 @@
+         return;
+     }
+ 
+-    m_engine->connectSource(source, this);
++    m_engine->connectSource(source, this, (uint)m_updateInterval->value());
+ }
+ 
+ QString EngineExplorer::convertToString(const QVariant &value) const
+--- a/plasma/applets/launcher/plasma-applet-url.desktop
++++ b/plasma/applets/launcher/plasma-applet-url.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Knopf
+ Name[el]=Κουμπί
+ Name[es]=Botón
++Name[et]=Nupp
+ Name[fa]=بوتان
+ Name[ga]=Cnaipe
+ Name[he]=כפתור
+@@ -37,6 +38,7 @@
+ Comment[de]=Ein Start-Knopf
+ Comment[el]=Ένα κουμπί εκκίνησης
+ Comment[es]=Un botón lanzador
++Comment[et]=Käivitamisnupp
+ Comment[fa]=دکمۀ راه‌اندازی
+ Comment[ga]=Cnaipe tosaitheora
+ Comment[he]=כפתור הפעלה
+--- a/plasma/applets/systemtray/systemtraywidget.cpp
++++ b/plasma/applets/systemtray/systemtraywidget.cpp
+@@ -106,6 +106,7 @@
+ 
+ void SystemTrayWidget::embedWindow(WId id)
+ {
++    kDebug() << "trying to add window with id " << id;
+     if (! m_containers.contains(id)) {
+         QX11EmbedContainer *container = new QX11EmbedContainer(this);
+         container->embedClient(id);
+@@ -114,7 +115,7 @@
+         container->show();
+         m_containers[id] = container;
+         connect(container, SIGNAL(clientClosed()), this, SLOT(windowClosed()) );
+-        kDebug() << "SystemTray: Window with id " << id << "added";
++        kDebug() << "SystemTray: Window with id " << id << "added" << container;
+     }
+ }
+ 
+@@ -125,16 +126,17 @@
+ 
+ void SystemTrayWidget::windowClosed()
+ {
++    kDebug() << "Window closed";
+     //by this point the window id is gone, so we have to iterate to find out who's lost theirs
+     ContainersList::iterator i = m_containers.begin();
+     while (i != m_containers.end()) {
+         QX11EmbedContainer *c=i.value();
+         if (c->clientWinId()==0) {
+-            m_containers.erase(i);
++            i=m_containers.erase(i);
+             kDebug() << "deleting container" << c;
+             delete c;
+-            //I assume that there will never be more than one without an id
+-            break;
++            //do NOT assume that there will never be more than one without an id
++            continue;
+         }
+         ++i;
+     }
+--- a/plasma/applets/systemtray/plasma-applet-systemtray.desktop
++++ b/plasma/applets/systemtray/plasma-applet-systemtray.desktop
+@@ -1,24 +1,61 @@
+ [Desktop Entry]
+ 
+-Name=System tray
++Name=System Tray
++Name[af]=Stelsel Laai
+ Name[be]=Сістэмны трэй
+ Name[bg]=Системен панел
++Name[br]=Barlenn ar reizhiad
++Name[ca]=Safata del sistema
++Name[cs]=Systémová část panelu
++Name[csb]=Systemòwi zabiérnik
++Name[cy]=Bar Tasgau
++Name[da]=Statusfelt
+ Name[de]=Systemabschnitt der Kontrollleiste
+ Name[el]=Πλαίσιο συστήματος
+-Name[ga]=Tráidire an chórais
++Name[eo]=Sistempleto
++Name[es]=Bandeja del sistema
++Name[et]=Süsteemne dokk
++Name[eu]=Sistemaren azpila
++Name[fa]=سینی سیستم
++Name[fi]=Ilmoitusalue
++Name[fr]=Boîte à miniatures
++Name[fy]=Systeemfak
++Name[ga]=Tráidire an Chórais
++Name[gl]=Bandexa do Sistema
++Name[he]=מגש מערכת
++Name[hr]=Sistemska traka
++Name[hu]=Rendszertálca
++Name[is]=Smáforritabakki
+ Name[it]=Vassoio di sistema
+ Name[ja]=システムトレイ
+-Name[kk]=Жүйелік сөре
+-Name[km]=ថាស​ប្រព័ន្ធ
++Name[ka]=სისტემური პანელი
+ Name[ko]=시스템 트레이
++Name[lt]=Sistemos dėklas
++Name[lv]=Sistēmas Tekne
++Name[mk]=Системска лента
++Name[ms]=Dulang Sistem
+ Name[nb]=Systemkurv
+-Name[nds]=Systeemafsnitt vun't Paneel
+-Name[nl]=Systeemvak
++Name[nds]=Paneel-Systeemafsnitt
++Name[ne]=प्रणाली ट्रे
+ Name[nn]=Systemtrau
+-Name[pt]=Bandeja do sistema
+-Name[pt_BR]=Bandeja do sistema
++Name[pa]=ਸਿਸਟਮ ਟਰੇ
++Name[pl]=Tacka systemowa
++Name[pt_BR]=Área de Notificação
++Name[ro]=Tavă de sistem
++Name[ru]=Системный лоток
++Name[se]=Vuogádatgárcu
++Name[sl]=Sistemska vrstica
++Name[sr]=Системска касета
++Name[sr at latin]=Системска касета
+ Name[sv]=Systembricka
+-Name[x-test]=xxSystem trayxx
++Name[ta]=சாதன தட்டு
++Name[te]=వ్యవస్థ ట్రె
++Name[tg]=Сафҳаи идоракунии система
++Name[th]=ถาดระบบ
++Name[tr]=Sistem Çekmecesi
++Name[uk]=Системний лоток
++Name[vi]=Khay hệ thống
++Name[xh]=Itreyi Yendlela yokusebenza
+ Name[zh_CN]=系统托盘
+ Name[zh_TW]=系統匣
+ Type=Service
+@@ -31,7 +68,7 @@
+ X-KDE-PluginInfo-Version=pre0.1
+ X-KDE-PluginInfo-Website=http://plasma.kde.org
+ X-KDE-PluginInfo-Category=Windows and Tasks
+-X-KDE-PluginInfo-Depeneds=
++X-KDE-PluginInfo-Depends=
+ X-KDE-PluginInfo-License=GPL v2+
+ X-KDE-PluginInfo-EnabledByDefault=true
+ 
+--- a/plasma/applets/tasks/tasks.cpp
++++ b/plasma/applets/tasks/tasks.cpp
+@@ -35,10 +35,12 @@
+ #include <QtDebug>
+ 
+ // KDE
++#include <KAuthorized>
+ #include <KColorScheme>
+ #include <KGlobalSettings>
+ #include <KIcon>
+ #include <KIconLoader>
++#include <taskmanager/taskrmbmenu.h>
+ 
+ // Plasma
+ #include <plasma/widgets/boxlayout.h>
+@@ -66,7 +68,6 @@
+         _rootTaskGroup->layout()->setAnimator(animator);
+ 
+     layout->addItem(_rootTaskGroup);
+-    setLayout(layout);
+ 
+     // testing
+         _rootTaskGroup->setBorderStyle(TaskGroupItem::NoBorder);
+@@ -400,7 +401,7 @@
+ {
+     setAcceptDrops(true);
+ 
+-   setLayout(new Plasma::BoxLayout(Plasma::BoxLayout::LeftToRight, this));
++   new Plasma::BoxLayout(Plasma::BoxLayout::LeftToRight, this);
+    layout()->setMargin(0);
+    layout()->setSpacing(5);
+ }
+@@ -690,5 +691,15 @@
+     return _task;
+ }
+ 
++void WindowTaskItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *e)
++{
++    if(!KAuthorized::authorizeKAction("kwin_rmb") )
++    {
++        return;
++    }
++    e->accept();
++    TaskRMBMenu menu( windowTask() );
++    menu.exec( e->screenPos() );
++}
+ #include "tasks.moc"
+ 
+--- a/plasma/applets/tasks/plasma-tasks-default.desktop
++++ b/plasma/applets/tasks/plasma-tasks-default.desktop
+@@ -4,6 +4,7 @@
+ Name[bg]=Мениджър на задачи
+ Name[de]=Prozessverwaltung<
+ Name[el]=Διαχειριστής εργασιών
++Name[et]=Tegumihaldur
+ Name[ga]=Bainisteoir na dTascanna
+ Name[ja]=タスクマネージャ
+ Name[kk]=Тапсырмалар менеджері
+--- a/plasma/applets/tasks/tasks.h
++++ b/plasma/applets/tasks/tasks.h
+@@ -273,6 +273,9 @@
+     virtual void activate();
+     virtual void close();
+ 
++protected:
++    virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
++
+ private slots:
+     void updateTask();
+ 
+--- a/plasma/applets/digital-clock/clock.h
++++ b/plasma/applets/digital-clock/clock.h
+@@ -64,7 +64,7 @@
+     private:
+         void animateUpdate();
+ 
+-        QSizeF m_defaultElementSize;
++        QSize m_defaultElementSize;
+ 
+         // temporary, sort out a correct way for applets to be notified
+         // when their content size changes and then rather than tracking
+--- a/plasma/applets/digital-clock/plasma-clock-digital.desktop
++++ b/plasma/applets/digital-clock/plasma-clock-digital.desktop
+@@ -1,8 +1,30 @@
+ [Desktop Entry]
+ Encoding=UTF-8
+ Name=Digital Clock
++Name[et]=Digikell
++Name[ga]=Clog Digiteach
++Name[ja]=デジタル時計
++Name[km]=នាឡិកា​ឌីជីថល
++Name[nb]=Digital klokke
++Name[nds]=Digitaal Klock
++Name[nl]=Digitale klok
++Name[pt]=Relógio Digital
++Name[pt_BR]=Relógio Digital
++Name[sv]=Digitalklocka
++Name[zh_TW]=數位時鐘
+ 
+ Comment=An SVG themable digital clock
++Comment[et]=SVG teemaga digikell
++Comment[ga]=Clog digiteach le téamaí SVG
++Comment[ja]=SVG テーマを使ったデジタル時計
++Comment[km]=នាឡិកាឌីជីថល​​ដែល​អាច​ប្ដូរ​ស្បែក​បាន SVG
++Comment[nb]=En SVG-klokke med drakter
++Comment[nds]=En Digitaalklock mit SVG-Mustern
++Comment[nl]=Een klok met SVG-themamogelijkheden
++Comment[pt]=Um relógio digital com temas em SVG
++Comment[pt_BR]=Um relógio digital com temas em SVG
++Comment[sv]=En SVG-temabaserad digitalklocka
++Comment[zh_TW]=SVG 可調整外觀數位時鐘
+ 
+ Icon=chronometer
+ Type=Service
+--- a/plasma/applets/digital-clock/clock.cpp
++++ b/plasma/applets/digital-clock/clock.cpp
+@@ -78,7 +78,8 @@
+         formFactor() == Plasma::MediaCenter) {
+         m_sizeHint = QSize(200, 90);
+     } else {
+-        m_sizeHint = QSize(56, 22); // this is ((el_width+el_hor_space)*4 , el_height*2+el_ver_space)
++        kDebug() << "####################################### Small FormFactor";
++        m_sizeHint = QSize(100, 48);
+     }
+     update();
+ }
+@@ -190,13 +191,13 @@
+     
+     const qreal margin = 4;
+     
+-    const qreal elHorizontalSpacing = 2;
+-    const qreal elVerticalSpacing = 1;
+-    qreal elWidth = contentsRect.width() / 4.0 - elHorizontalSpacing - margin*2;
+-    qreal elHeight = contentsRect.height() / 2.0 - elVerticalSpacing - margin*2;
++    const int elHorizontalSpacing = 2;
++    const int elVerticalSpacing = 2;
++    int elWidth = qRound((contentsRect.width() - elHorizontalSpacing - margin*2) / 4.0);
++    int elHeight = qRound((contentsRect.height() - elVerticalSpacing - margin*2) / 2.0);
+ 
+     // enforce natural aspect ratio for elements
+-    QSizeF elSize = m_defaultElementSize;
++    QSize elSize = m_defaultElementSize;
+     elSize.scale(elWidth,elHeight,Qt::KeepAspectRatio);
+     elWidth = elSize.width();
+     elHeight = elSize.height(); 
+@@ -208,7 +209,7 @@
+ 
+     // update graphic sizes when the applet's size changes
+     if ( contentsRect.size() != m_contentSize ) {
+-        m_theme->resize((int)elWidth,(int)elHeight);
++        m_theme->resize(elWidth,elHeight);
+         m_contentSize = contentsRect.size();
+     }
+ 
+@@ -257,7 +258,7 @@
+             element = QString('e')+oldMinutes+QString("-p2");
+             m_theme->paint(p, QRectF(99, 41, elWidth, elHeight), element);
+ 
+-            if (m_animationStep < 3) {
++            if (m_animationStep < 3 && m_animationStep > 0) {
+                 element = QString('e')+oldMinutes+QString("-p1");
+                 m_theme->paint(p, QRectF(99, 40-(elHeight/m_animationStep), elWidth, elHeight/m_animationStep), element);
+             } else {
+@@ -274,7 +275,7 @@
+                 element = QString('e')+oldHours+QString("-p2");
+                 m_theme->paint(p, QRectF(59, 41, elWidth, elHeight), element);
+ 
+-                if (m_animationStep < 3) {
++                if (m_animationStep < 3 && m_animationStep > 0) {
+                     element = QString('e')+oldHours+QString("-p1");
+                     m_theme->paint(p, QRectF(59, 40-(elHeight/m_animationStep), elWidth, elHeight/m_animationStep), element);
+                 } else {
+@@ -291,7 +292,7 @@
+                     element = QString('e')+oldHours+QString("-p2");
+                     m_theme->paint(p, QRectF(39, 41, elWidth, elHeight), element);
+ 
+-                    if (m_animationStep < 3) {
++                    if (m_animationStep < 3 && m_animationStep > 0) {
+                         element = QString('e')+oldHours+QString("-p1");
+                         m_theme->paint(p, QRectF(39, 40-(elHeight/m_animationStep), elWidth, elHeight/m_animationStep), element);
+                     } else {
+@@ -306,21 +307,27 @@
+         }
+     }
+ 
+-    // FIXME: this depends on the backgroundcolor of the theme, we'd want a matching contrast
+-    p->setPen(QPen(Qt::white));
++    // Only show the date when there's enough room
++    // We might want this configurable at some point.
++    if (formFactor() == Plasma::Planar ||
++        formFactor() == Plasma::MediaCenter) {
++        m_sizeHint = QSize(200, 90);
++        // FIXME: this depends on the backgroundcolor of the theme, we'd want a matching contrast
++        p->setPen(QPen(Qt::white));
+ 
+-    QString dateString = day + ' ' + month + ' ' + year;
+-    if (m_timezone != "Local")
+-    {
+-        dateString += "\n" + m_timezone;
+-    }
+-    p->drawText( QRectF(margin,
+-                        bottomElementTop+elHeight,
+-                        contentsRect.right()-margin,
+-                        contentsRect.bottom()) ,
+-                 dateString,
+-                 QTextOption(Qt::AlignHCenter)
+-               );
++        QString dateString = day + ' ' + month + ' ' + year;
++        if (m_timezone != "Local")
++        {
++            dateString += "\n" + m_timezone;
++        }
++        p->drawText( QRectF(margin,
++                            bottomElementTop+elHeight,
++                            contentsRect.right()-margin,
++                            contentsRect.bottom()) ,
++                    dateString,
++                    QTextOption(Qt::AlignHCenter)
++                );
++    }
+ }
+ 
+ #include "clock.moc"
+--- a/plasma/applets/battery/plasma-battery-default.desktop
++++ b/plasma/applets/battery/plasma-battery-default.desktop
+@@ -2,6 +2,7 @@
+ Name=Battery Monitor
+ Name[be]=Назіранне за батарэяй
+ Name[el]=Επόπτης συστήματος
++Name[et]=Aku jälgija
+ Name[ja]=バッテリモニタ
+ Name[km]=កម្មវិធី​ត្រួត​​ពិនិត្យ​ថាមពល
+ Name[nb]=Batteriovervåker
+@@ -16,6 +17,7 @@
+ Comment=A battery charge monitor
+ Comment[be]=Назіранне за зарадам батарэй
+ Comment[el]=Ένας επόπτης φόρτισης της μπαταρίας
++Comment[et]=Aku täidetuse jälgija
+ Comment[ja]=バッテリ残量モニタ
+ Comment[km]=កម្មវិធី​ត្រួត​ពិនិត្យ​ការ​បញ្ចូល​ថ្ម
+ Comment[nb]=En overvåker for batterilading
+--- a/plasma/applets/battery/batteryConfig.ui
++++ b/plasma/applets/battery/batteryConfig.ui
+@@ -41,7 +41,7 @@
+      <item>
+       <widget class="QLabel" name="labelSize" >
+        <property name="text" >
+-        <string>Size of the battery</string>
++        <string>Size of the battery:</string>
+        </property>
+       </widget>
+      </item>
+--- a/plasma/applets/clock/clockConfig.ui
++++ b/plasma/applets/clock/clockConfig.ui
+@@ -134,7 +134,7 @@
+        <item>
+         <widget class="QLabel" name="labelSize" >
+          <property name="text" >
+-          <string>Size of the clock</string>
++          <string>Size of the clock:</string>
+          </property>
+         </widget>
+        </item>
+--- a/plasma/applets/clock/plasma-clock-analog.desktop
++++ b/plasma/applets/clock/plasma-clock-analog.desktop
+@@ -8,6 +8,7 @@
+ Name[de]=Analoge Uhr
+ Name[el]=Αναλογικό ρολόι
+ Name[es]=Reloj analógico
++Name[et]=Analoogkell
+ Name[fa]=ساعت قیاسی
+ Name[ga]=Clog Analógach
+ Name[he]=שעון אנלוגי
+@@ -35,12 +36,13 @@
+ Comment[de]=Eine Uhr mit SVG-fähigem Design
+ Comment[el]=Ένα ρολόι με θέματα SVG
+ Comment[es]=Un reloj con temas en formato SVG
++Comment[et]=SVG teemaga kell
+ Comment[fa]=ساعت چهره‌پذیر SVG
+ Comment[he]=שעון SVG הניתן להתאמה על ידי ערכות נושא
+ Comment[it]=Un orologio con temi SVG
+ Comment[ja]=SVG テーマを使った時計
+ Comment[kk]=SVG нақышты сағат
+-Comment[km]=នាឡិកា​ដែល​អាចប្ដូរ​ស្បែក​បាន SVG
++Comment[km]=នាឡិកា​ដែល​អាច​ប្ដូរ​ស្បែក​បាន SVG
+ Comment[ko]=SVG 테마를 사용하는 시계
+ Comment[nb]=En SVG-klokke med drakter
+ Comment[nds]=En Klock mit SVG-Mustern
+--- a/plasma/applets/CMakeLists.txt
++++ b/plasma/applets/CMakeLists.txt
+@@ -1,7 +1,6 @@
++add_subdirectory(battery)
+ add_subdirectory(clock)
+ add_subdirectory(digital-clock)
+-add_subdirectory(tasks)
+-add_subdirectory(systemtray)
+-add_subdirectory(battery)
+ add_subdirectory(pager)
+-add_subdirectory(frame)
++add_subdirectory(systemtray)
++add_subdirectory(tasks)
+--- a/plasma/applets/pager/pager.cpp
++++ b/plasma/applets/pager/pager.cpp
+@@ -75,16 +75,6 @@
+     return m_size;
+ }
+ 
+-QSizeF Pager::minimumSize() const
+-{
+-    return m_size;
+-}
+-
+-QSizeF Pager::maximumSize() const
+-{
+-    return m_size;
+-}
+-
+ void Pager::constraintsUpdated(Plasma::Constraints)
+ {
+     if (formFactor() == Plasma::Vertical ||
+@@ -94,11 +84,15 @@
+         setDrawStandardBackground(true);
+     }
+ 
+-     prepareGeometryChange();
+      recalculateGeometry();
+      recalculateWindowRects();
+ }
+ 
++Qt::Orientations Pager::expandingDirections() const
++{
++    return 0;
++}
++
+ void Pager::showConfigurationInterface()
+ {
+      if (m_dialog == 0) {
+@@ -122,6 +116,7 @@
+ 
+ void Pager::recalculateGeometry()
+ {
++    prepareGeometryChange();
+     m_scaleFactor = qreal(m_itemHeight) / QApplication::desktop()->height();
+     qreal itemWidth = QApplication::desktop()->width() * m_scaleFactor;
+     m_rects.clear();
+@@ -135,7 +130,8 @@
+     }
+     m_size = QSizeF(columns*itemWidth + 2*columns - 1,
+ 		     m_itemHeight*m_rows + 2*m_rows - 1);
+-    resize(sizeHint());
++
++    updateGeometry();
+ }
+ 
+ void Pager::recalculateWindowRects()
+--- a/plasma/applets/pager/pagerConfig.ui
++++ b/plasma/applets/pager/pagerConfig.ui
+@@ -28,7 +28,7 @@
+      <item row="0" column="0" >
+       <widget class="QLabel" name="labelSize" >
+        <property name="text" >
+-        <string>Height</string>
++        <string>Height:</string>
+        </property>
+       </widget>
+      </item>
+@@ -70,7 +70,7 @@
+      <item row="1" column="0" >
+       <widget class="QLabel" name="labelRows" >
+        <property name="text" >
+-        <string>Number of rows</string>
++        <string>Number of rows:</string>
+        </property>
+       </widget>
+      </item>
+--- a/plasma/applets/pager/plasma-pager-default.desktop
++++ b/plasma/applets/pager/plasma-pager-default.desktop
+@@ -1,6 +1,9 @@
+ [Desktop Entry]
+ Name=Pager
++Name[et]=Peiler
+ Name[ga]=Brabhsálaí Leathanach
++Name[ja]=ページャ
++Name[nb]=Sidebytter
+ Name[pt]=Paginador
+ Name[sv]=Skrivbordsvisning
+ Name[zh_TW]=呼叫器
+--- a/plasma/applets/pager/pager.h
++++ b/plasma/applets/pager/pager.h
+@@ -41,9 +41,8 @@
+         void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option,
+                             const QRect &contents);
+         QSizeF contentSizeHint() const;
+-	QSizeF minimumSize() const;
+-	QSizeF maximumSize() const;
+         void constraintsUpdated(Plasma::Constraints);
++	Qt::Orientations expandingDirections() const;
+ 
+     public slots:
+         void showConfigurationInterface();
+--- a/plasma/engines/Mainpage.dox
++++ /dev/null
+@@ -1,10 +0,0 @@
+-/**
+-* @mainpage Engines
+-*
+-* Plasma engines power widgets.
+-*
+-*/
+-
+-// DOXYGEN_SET_PROJECT_NAME = Engines
+-// DOXYGEN_SET_RECURSIVE = YES
+-// vim:ts=4:sw=4:expandtab:filetype=doxygen
+--- a/plasma/engines/CMakeLists.txt
++++ /dev/null
+@@ -1,7 +0,0 @@
+-add_subdirectory(time)
+-add_subdirectory(weather)
+-add_subdirectory(dict)
+-add_subdirectory(filebrowser)
+-add_subdirectory(powermanagement)
+-add_subdirectory(mouse)
+-add_subdirectory(tasks)
+--- a/plasma/desktoptheme/desktoptheme-default.desktop
++++ b/plasma/desktoptheme/desktoptheme-default.desktop
+@@ -3,7 +3,7 @@
+ Name=Oxygen
+ Name[csb]=Krziseń
+ Name[kk]=Оттегі
+-Name[km]=អុកស៊ីសែន
++Name[km]=អុកស៊ីហ្សែន
+ Name[ne]=अक्सिजन
+ Name[nn]=Oksygen
+ Name[pa]=ਆਕਸੀਜਨ
+@@ -15,6 +15,7 @@
+ Comment[de]=Oberflächen-Design im Oxygen-Stil
+ Comment[el]=Το θέμα δημιουργήθηκε στο στυλ Oxygen
+ Comment[es]=Tema realizado con el estilo Oxygen
++Comment[et]=Oxygeni stiilis teema
+ Comment[fa]=چهره در سبک اکسیژن انجام شد
+ Comment[ga]=Téama sa stíl Oxygen
+ Comment[he]=ערכת נושא שמשתמשת בסגנון Oxygen
+--- /dev/null
++++ b/plasma/runners/search/plasma-runner-search.desktop
+@@ -0,0 +1,62 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Search Runner
++Name[be]=Запуск пошуку
++Name[bg]=Търсене
++Name[de]=Suche durchführen
++Name[el]=Εκτελεστής αναζήτησης
++Name[et]=Otsingu jäivitaja
++Name[fa]=اجراکتتدۀ جستجو
++Name[he]=חיפוש
++Name[ja]=検索 Runner
++Name[kk]=Іздеуді жегуші
++Name[km]=ស្វែងរក​​កម្មវិធី​រត់
++Name[nb]=Søk i Runner
++Name[nds]=Söökdreger
++Name[ne]=रनर खोजी गर्नुहोस्
++Name[nl]=Zoekmachine
++Name[nn]=Søk i Runner
++Name[pa]=ਖੋਜ ਰਨਰ
++Name[pt]=Execução da Pesquisa
++Name[pt_BR]=Executor de Busca
++Name[sv]=Söktjänst
++Name[th]=ตัวเรียกการค้นหาทำงาน
++Name[vi]=Chạy Tìm kiếm
++Name[x-test]=xxSearch Runnerxx
++Name[zh_CN]=搜索运行器
++Name[zh_TW]=搜索執行者
++Comment=Search files
++Comment[ar]=ملفات البحث
++Comment[be]=Пошук файлаў
++Comment[bg]=Търсене на файлове
++Comment[csb]=Szëkba lopków
++Comment[de]=Dateien suchen
++Comment[el]=Αναζήτηση αρχείων
++Comment[et]=Failide otsimine
++Comment[fa]=پرونده‌های جستجو
++Comment[ga]=Cuardaigh comhaid
++Comment[he]=חיפוש קבצים
++Comment[ja]=ファイルを検索
++Comment[kk]=Файлдарды табу
++Comment[km]=ស្វែងរក​ឯកសារ​
++Comment[nb]=Søk i filer
++Comment[nds]=Dateien söken
++Comment[ne]=फाइल खोजी गर्नुहोस्
++Comment[nl]=Bestanden zoeken
++Comment[nn]=Søk i filer
++Comment[pa]=ਫਾਇਲਾਂ ਖੋਜ
++Comment[pt]=Procurar ficheiros
++Comment[pt_BR]=Procurar arquivos
++Comment[sl]=Išči datoteke
++Comment[sv]=Sök filer
++Comment[th]=ค้นหาแฟ้ม
++Comment[vi]=Tìm kiếm trong tập tin
++Comment[wa]=Cweri des fitchîs
++Comment[x-test]=xxSearch filesxx
++Comment[zh_CN]=搜索文件
++Comment[zh_TW]=搜索檔案
++ServiceTypes=Plasma/Runner
++Type=Service
++X-KDE-Library=krunner_searchrunner
++X-Krunner-ID=Search Runner
++X-Plasma-RunnerPhase=last
+--- /dev/null
++++ b/plasma/runners/search/searchrunner.cpp
+@@ -0,0 +1,113 @@
++/*
++ *   Copyright (C) 2006 Aaron Seigo <aseigo at kde.org>
++ *                 2007 Jos van den Oever <jos at vandenoever.info>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "searchrunner.h"
++
++#include <QAction>
++#include <KActionCollection>
++#include <KIcon>
++#include <KLocale>
++#include <KRun>
++
++SearchAction::SearchAction(const QString& f, const QString& iconname,
++        const QString& mt, const QString& name, QObject* parent)
++    : QAction(KIcon(iconname), name, parent), file(f), mimetype(mt)
++{
++}
++
++SearchRunner::SearchRunner( QObject* parent, const QVariantList &args )
++    : Plasma::AbstractRunner( parent )
++{
++    Q_UNUSED( args );
++    setObjectName( i18n( "Search" ) );
++}
++
++SearchRunner::~SearchRunner()
++{
++}
++
++QAction* SearchRunner::accepts( const QString& term )
++{
++    // return an action that opens a search GUI with this term
++    QAction* action = new QAction(i18n("search for %1", term), this);
++    connect(action, SIGNAL(triggered()), this, SLOT(launchSearch()));
++    return action;
++}
++
++bool SearchRunner::exec(QAction* action, const QString& command)
++{
++    Q_UNUSED(action)
++    Q_UNUSED(command)
++    return true;
++}
++
++QString formatUri(const QString& uri, const QString& term) {
++    Q_UNUSED( term );
++    QString highlighted;
++    QString path;
++    int l = uri.lastIndexOf("/");
++    if (l >= 0) {
++        highlighted = uri.mid(l+1);
++        path = uri.left(l);
++    } else {
++        highlighted = uri;
++    }
++    // it would be nice to be able to make the matching part of the string
++    // stand out
++    //highlighted.replace(term, "<b>"+term+"</b>");
++    highlighted = highlighted + " ("+path+')';
++    return highlighted;
++}
++
++void SearchRunner::fillMatches( KActionCollection* matches,
++                                const QString& term,
++                                int max, int offset )
++{
++
++    //TODO: in reality, we probably want to make this async and use matchesUpdated
++
++    QString query = "system.file_name:'" + term + "*'";
++    QList<StrigiHit> hits = strigiclient.getHits(query, max, offset);
++    foreach(const StrigiHit& hit, hits) {
++        QString iconname = hit.mimetype;
++        iconname.replace('/', '-');
++        QString formatted  = formatUri(hit.uri, term);
++        QAction* action = new SearchAction(hit.uri, iconname, hit.mimetype,
++            formatted, this);
++        connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
++        matches->addAction(formatted, action);
++    }
++}
++void SearchRunner::launchSearch()
++{
++    // TODO this does not work yet and it be better to open a nicer search
++    // client e.g. kerry or strigi://
++    KRun::runCommand("strigiclient", NULL);
++}
++
++void SearchRunner::openFile()
++{
++    SearchAction* action = qobject_cast<SearchAction*>(sender());
++    qDebug() << "openFile " << action;
++    if (action) {
++        KRun::runUrl(action->file, action->mimetype, NULL);
++    }
++}
++
++#include "searchrunner.moc"
+--- /dev/null
++++ b/plasma/runners/search/searchrunner.h
+@@ -0,0 +1,71 @@
++/*
++ *   Copyright (C) 2006 Aaron Seigo <aseigo at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef SEARCHRUNNER_H
++#define SEARCHRUNNER_H
++
++#include <KGenericFactory>
++
++#include <plasma/abstractrunner.h>
++#include <strigi/qtdbus/strigiclient.h>
++#include <QtGui/QAction>
++
++/**
++ * This class runs the entered text through a search engine and returns the set
++ * of results returned as possible programs, files, actions, etc to launch.
++ */
++class SearchRunner : public Plasma::AbstractRunner
++{
++    Q_OBJECT
++
++    private:
++        StrigiClient strigiclient;
++        QString lastTerm;
++
++    public:
++        SearchRunner( QObject* parent, const QVariantList &args );
++        ~SearchRunner();
++
++        QAction* accepts( const QString& term );
++        bool exec(QAction* action, const QString& command);
++
++    protected:
++        virtual void fillMatches( KActionCollection* matches,
++                                  const QString& term,
++                                  int max, int offset );
++
++    protected slots:
++        // open the search gui
++        void launchSearch();
++        // open the file
++        void openFile();
++};
++
++class SearchAction : public QAction
++{
++    Q_OBJECT
++public:
++    const QString file;
++    const QString mimetype;
++    SearchAction(const QString& file, const QString& iconname,
++        const QString& mimetype, const QString& name, QObject* parent);
++};
++
++K_EXPORT_PLASMA_RUNNER(searchrunner, SearchRunner)
++
++#endif
+--- /dev/null
++++ b/plasma/runners/search/CMakeLists.txt
+@@ -0,0 +1,25 @@
++find_library(STRIGIQTDBUSCLIENT_LIBRARY NAMES strigiqtdbusclient
++  PATHS
++  /usr/lib
++  /usr/local/lib
++  ${LIB_INSTALL_DIR}
++  $ENV{STRIGI_HOME}/lib
++)
++
++macro_log_feature(STRIGIQTDBUSCLIENT_LIBRARY "strigi indexing" "Strigi built with indexing" "http://strigi.sourceforge.net/" FALSE "" "For the search functionality of the Run Command window")
++
++
++if (STRIGIQTDBUSCLIENT_LIBRARY)
++
++  set(krunner_searchrunner_SRCS searchrunner.cpp)
++  kde4_add_plugin(krunner_searchrunner ${krunner_searchrunner_SRCS})
++  include_directories(${STRIGI_INCLUDE_DIR})
++  target_link_libraries(krunner_searchrunner ${KDE4_KDECORE_LIBS} plasma ${STRIGIQTDBUSCLIENT_LIBRARY})
++
++  install(TARGETS krunner_searchrunner DESTINATION ${PLUGIN_INSTALL_DIR} )
++
++  ########### install files ###############
++
++  install(FILES plasma-runner-search.desktop DESTINATION ${SERVICES_INSTALL_DIR})
++
++endif (STRIGIQTDBUSCLIENT_LIBRARY)
+--- /dev/null
++++ b/plasma/runners/calculator/plasma-runner-calculator.desktop
+@@ -0,0 +1,61 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Calculator Runner
++Name[ar]=منفذ الحاسبة
++Name[be]=Калькулятар
++Name[bg]=Калкулатор
++Name[csb]=Kalkùlator
++Name[de]=Rechner-Starter
++Name[el]=Εκτελεστής υπολογισμών
++Name[es]=Ejecución de la calculadora
++Name[et]=Kalkulaatori käivitaja
++Name[fa]=اجراکنندۀ ماشین حساب
++Name[he]=מחשבון
++Name[ja]=計算機 Runner
++Name[kk]=Калькуляторды жегуші
++Name[km]=កម្មវិធី​រត់​ម៉ាស៊ីន​​គិត​លេខ
++Name[nb]=Kalkulator-starter
++Name[nds]=Rekendreger
++Name[ne]=क्याल्कुलेटर रनर
++Name[nl]=Rekenmachine
++Name[nn]=Kalkulatorstartar
++Name[pa]=ਕੈਲਕੂਲੇਟਰ ਰਨਰ
++Name[pt]=Execução da Calculadora
++Name[pt_BR]=Executor de Calculadora
++Name[sv]=Kör miniräknare
++Name[th]=ตัวเรียกเครื่องคิดเลขทำงาน
++Name[vi]=Máy tính
++Name[x-test]=xxCalculator Runnerxx
++Name[zh_CN]=计算机运行器
++Name[zh_TW]=計算機執行者
++Comment=Calculate expressions
++Comment[ar]=تعابير الحاسبة
++Comment[bg]=Калкулатор
++Comment[cs]=Výpočet vzorců
++Comment[de]=Berechnungen durchführen
++Comment[el]=Υπολογισμός εκφράσεων
++Comment[es]=Calcular expresiones
++Comment[et]=Avaldiste arvutamine
++Comment[fa]=محاسبه عبارات
++Comment[he]=חישוב ביטויים
++Comment[it]=Calcola espressione
++Comment[ja]=数式を計算
++Comment[kk]=Өрнектерді есептеу
++Comment[km]=គណនា​កន្សោម​​
++Comment[nb]=Beregn uttrykk
++Comment[nds]=Utdrück utreken
++Comment[ne]=अभिव्यक्ति गणना गर्नुहोस्
++Comment[nl]=Expressies berekenen
++Comment[nn]=Rekn ut mattestykke
++Comment[pt]=Calcular expressões
++Comment[pt_BR]=Calcular expressões
++Comment[sv]=Beräkna uttryck
++Comment[th]=คำนวณนิพจน์
++Comment[vi]=Tính biểu thức
++Comment[x-test]=xxCalculate expressionsxx
++Comment[zh_CN]=计算表达式
++Comment[zh_TW]=計算機表示式
++ServiceTypes=Plasma/Runner
++Type=Service
++X-KDE-Library=krunner_calculatorrunner
++X-Krunner-ID=Calculator Runner
+--- /dev/null
++++ b/plasma/runners/calculator/calculatorrunner.cpp
+@@ -0,0 +1,80 @@
++/*
++ *   Copyright (C) 2007 Barış Metin <baris at pardus.org.tr>
++ *   Copyright (C) 2006 David Faure <faure at kde.org>
++ *   Copyright (C) 2007 Richard Moore <rich at kde.org>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include "calculatorrunner.h"
++
++#include <QAction>
++#include <QHBoxLayout>
++#include <QLabel>
++#include <QWidget>
++#include <QScriptEngine>
++
++#include <KIcon>
++
++CalculatorRunner::CalculatorRunner( QObject* parent, const QVariantList &args )
++    : Plasma::AbstractRunner( parent ),
++      m_options( 0 )
++{
++    Q_UNUSED(args)
++
++    setObjectName( i18n( "Calculator" ) );
++}
++
++CalculatorRunner::~CalculatorRunner()
++{
++    delete m_options;
++}
++
++QAction* CalculatorRunner::accepts( const QString& term )
++{
++    QString cmd = term.trimmed();
++    QAction *action = 0;
++
++    if ( !cmd.isEmpty() && 
++         ( cmd[0].isNumber() || ( cmd[0] == '(') ) &&
++         ( QRegExp("[a-zA-Z\\]\\[]").indexIn(cmd) == -1 ) ) {
++        QString result = calculate(cmd);
++
++        if ( !result.isEmpty() ) {
++            action = new QAction(KIcon("accessories-calculator"),
++                                 QString("%1 = %2").arg(term, result),
++                                 this);
++            action->setEnabled( false );
++        }
++    }
++
++    return action;
++}
++
++bool CalculatorRunner::exec(QAction* action, const QString& term)
++{
++    Q_UNUSED(action)
++    Q_UNUSED(term)
++    return true;
++}
++
++QString CalculatorRunner::calculate( const QString& term )
++{
++    QScriptEngine eng;
++    QScriptValue result = eng.evaluate( term );
++    return result.toString();
++}
++
++#include "calculatorrunner.moc"
+--- /dev/null
++++ b/plasma/runners/calculator/calculatorrunner.h
+@@ -0,0 +1,49 @@
++/*
++ *   Copyright (C) 2007 Barış Metin <baris at pardus.org.tr>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef CALCULATORRUNNER_H
++#define CALCULATORRUNNER_H
++
++#include <KGenericFactory>
++
++#include <plasma/abstractrunner.h>
++
++class QWidget;
++
++/**
++ * This class evaluates the basic expressions given in the interface.
++ */
++class CalculatorRunner : public Plasma::AbstractRunner
++{
++    Q_OBJECT
++
++    public:
++        CalculatorRunner( QObject* parent, const QVariantList &args );
++        ~CalculatorRunner();
++
++        QAction* accepts( const QString& term );
++        bool exec(QAction* action, const QString& term);
++
++    private:
++        QString calculate( const QString& term );
++        QWidget* m_options;
++};
++
++K_EXPORT_PLASMA_RUNNER(calculatorrunner, CalculatorRunner)
++
++#endif
+--- /dev/null
++++ b/plasma/runners/calculator/CMakeLists.txt
+@@ -0,0 +1,17 @@
++
++########### next target ###############
++
++set(krunner_calculatorrunner_SRCS
++    calculatorrunner.cpp
++)
++
++kde4_add_plugin(krunner_calculatorrunner ${krunner_calculatorrunner_SRCS})
++target_link_libraries(krunner_calculatorrunner ${KDE4_KDECORE_LIBS} ${QT_QTSCRIPT_LIBRARY} plasma)
++
++install(TARGETS krunner_calculatorrunner DESTINATION ${PLUGIN_INSTALL_DIR} )
++
++
++########### install files ###############
++
++install(FILES plasma-runner-calculator.desktop DESTINATION ${SERVICES_INSTALL_DIR})
++
+--- /dev/null
++++ b/plasma/runners/webshortcuts/webshortcutrunner.cpp
+@@ -0,0 +1,141 @@
++/*
++ *   Copyright (C) 2007 Teemu Rytilahti <tpr at iki.fi>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include <QAction>
++#include <QStringList>
++#include <QIcon>
++#include <QDBusInterface>
++#include <QDBusReply>
++
++#include <KRun>
++#include <KUrl>
++#include <KLocale>
++#include <KService>
++#include <KSharedPtr>
++#include <KMimeType>
++#include <KIconLoader>
++#include <KStandardDirs>
++
++#include <kservicetypetrader.h>
++
++#include "webshortcutrunner.h"
++
++
++WebshortcutRunner::WebshortcutRunner(QObject *parent, const QVariantList& args)
++    : Plasma::AbstractRunner(parent)
++{
++    Q_UNUSED(args);
++    // set the name shown after the result in krunner window
++    setObjectName(i18n("Web shortcut"));
++    // query ktrader for all available searchproviders and preload the default icon
++    m_offers = KServiceTypeTrader::self()->query("SearchProvider");
++    m_icon = QIcon(KIconLoader::global()->loadIcon("konqueror", KIconLoader::Small));
++}
++
++WebshortcutRunner::~WebshortcutRunner()
++{
++}
++
++QAction *WebshortcutRunner::accepts(const QString& term) {
++    QString searchTerm = term.toLower();
++
++    KUrl url(term);
++    if (!url.protocol().isEmpty() && !url.host().isEmpty()) {
++        QAction *action = new QAction(QString("Open %1").arg(term), this);
++        action->setIcon(m_icon);
++        m_url = url;
++        return action;
++    }
++
++    foreach (KSharedPtr<KService> service, m_offers) {
++        // hmm, how about getting the keys for the localized sites?
++        foreach(QString key, service->property("Keys").toStringList()) {
++            // FIXME? should we look for the used separator from the konqi's settings?
++            key = key.toLower() + ":";
++            if (searchTerm.size() > key.size() &&
++                searchTerm.startsWith(key, Qt::CaseInsensitive)) {
++                m_url = getSearchQuery(service->property("Query").toString(),searchTerm);
++                QString actionText = QString("Search %1 for %2");
++                actionText = actionText.arg(service->name(),
++                                            searchTerm.right(searchTerm.length() - searchTerm.indexOf(':') - 1));
++
++                QAction *action = new QAction(actionText, this);
++
++                // let's try if we can get a proper icon from the favicon cache
++                QIcon icon = getFavicon(m_url);
++                if (icon.isNull()){
++                    action->setIcon(m_icon);
++                } else {
++                    action->setIcon(icon);
++                }
++
++                return action;
++            }
++        }
++    }
++
++    return 0;
++}
++
++KUrl WebshortcutRunner::getSearchQuery(const QString &query, const QString &term) {
++    // FIXME delimiter check like for above?
++    QStringList tempList = term.split(":");
++    if(tempList.count() > 0) {
++        QString searchWord(tempList[1]);
++        QString finalQuery(query);
++        // FIXME? currently only basic searches are supported
++        finalQuery.replace("\\{@}", searchWord);
++        KUrl url(finalQuery);
++        return url;
++    }
++
++    return KUrl();
++}
++
++QIcon WebshortcutRunner::getFavicon(const KUrl &url) {
++    // query the favicons module
++    QDBusInterface favicon("org.kde.kded", "/modules/favicons", "org.kde.FavIcon");
++    QDBusReply<QString> reply = favicon.call("iconForUrl", url.url());
++
++    if (!reply.isValid()) {
++        return QIcon();
++    }
++
++    // locate the favicon
++    QString iconFile = KGlobal::dirs()->findResource("cache",reply.value()+".png");
++    QIcon icon = QIcon(iconFile);
++
++    if (!icon.isNull()) {
++        return icon;
++    }
++
++    return QIcon();
++}
++
++bool WebshortcutRunner::exec(QAction* action, const QString& command) {
++    //TODO: this should probably use the action to store the url rather than
++    //      store it internally in m_url so as to support multiple actions
++    //      in the future
++    Q_UNUSED(action)
++    Q_UNUSED(command)
++//    kDebug() << "command: " << command;
++//    kDebug() << "url: " << m_url.url();
++    return(KRun::runUrl(m_url, "text/html", 0) != false);
++}
++
++#include "webshortcutrunner.moc"
+--- /dev/null
++++ b/plasma/runners/webshortcuts/plasma-runner-webshortcuts.desktop
+@@ -0,0 +1,27 @@
++[Desktop Entry]
++Encoding=UTF-8
++Name=Webshortcut runner
++Name[et]=Veebi kiirkorralduste käivitaja
++Name[ja]=ウェブショートカットランナー
++Name[km]=កម្មវិធី​រត់​ផ្លូវកាត់​បណ្ដាញ
++Name[nb]=Nettsnarvei-følger
++Name[nds]=Söökafkörtendreger
++Name[nl]=Webkoppelingen volgen
++Name[pt]=Execução de atalhos Web
++Name[pt_BR]=Execução de Atalhos da Web
++Name[sv]=Kör webbgenvägar
++Name[zh_TW]=網頁捷徑執行者
++Comment=Webshortcut runner
++Comment[et]=Veebi kiirkorralduste käivitaja
++Comment[ja]=ウェブショートカットランナー
++Comment[km]=កម្មវិធី​រត់​ផ្លូវកាត់​បណ្ដាញ
++Comment[nds]=Söökafkörtendreger
++Comment[nl]=Webkoppelingen volgen
++Comment[pt]=Execução de atalhos Web
++Comment[pt_BR]=Execução de Atalhos da Web
++Comment[sv]=Kör webbgenvägar
++Comment[zh_TW]=網頁捷徑執行者
++ServiceTypes=Plasma/Runner
++Type=Service
++X-KDE-Library=krunner_webshortcuts
++X-Krunner-ID=Webshortcut runner
+--- /dev/null
++++ b/plasma/runners/webshortcuts/webshortcutrunner.h
+@@ -0,0 +1,51 @@
++/*
++ *   Copyright (C) 2007 Teemu Rytilahti <tpr at iki.fi>
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU Library General Public License version 2 as
++ *   published by the Free Software Foundation
++ *
++ *   This 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 Library General Public
++ *   License along with this program; if not, write to the
++ *   Free Software Foundation, Inc.,
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef WEBSHORTCUTRUNNER_H
++#define WEBSHORTCUTRUNNER_H
++
++#include <plasma/abstractrunner.h>
++
++#include <KGenericFactory>
++
++class QAction;
++
++class WebshortcutRunner : public Plasma::AbstractRunner {
++    Q_OBJECT
++
++    public:
++        WebshortcutRunner( QObject *parent, const QVariantList& args );
++        ~WebshortcutRunner();
++
++    protected:
++        QAction* accepts( const QString& term );
++        bool exec(QAction* action, const QString& command);
++
++    private:
++        KUrl getSearchQuery(const QString &query, const QString &searchWord);
++        QIcon getFavicon(const KUrl& url);
++
++    private:
++        KService::List m_offers;
++        KUrl m_url;
++        QIcon m_icon;
++};
++
++K_EXPORT_PLASMA_RUNNER(webshortcuts, WebshortcutRunner)
++
++#endif
+--- /dev/null
++++ b/plasma/runners/webshortcuts/CMakeLists.txt
+@@ -0,0 +1,11 @@
++set(krunner_webshortcuts_SRCS
++    webshortcutrunner.cpp
++)
++
++kde4_add_plugin(krunner_webshortcuts ${krunner_webshortcuts_SRCS})
++target_link_libraries(krunner_webshortcuts ${KDE4_KIO_LIBS} plasma)
++
++install(TARGETS krunner_webshortcuts DESTINATION ${PLUGIN_INSTALL_DIR} )
++
++install(FILES plasma-runner-webshortcuts.desktop DESTINATION ${SERVICES_INSTALL_DIR})
++
+--- /dev/null
++++ b/plasma/runners/CMakeLists.txt
+@@ -0,0 +1,3 @@
++add_subdirectory(calculator)
++add_subdirectory(search)
++add_subdirectory(webshortcuts)
+--- a/plasma/CMakeLists.txt
++++ b/plasma/CMakeLists.txt
+@@ -2,8 +2,9 @@
+ add_subdirectory(animators)
+ add_subdirectory(applets)
+ add_subdirectory(containments)
++add_subdirectory(dataengines)
+ add_subdirectory(desktoptheme)
+-add_subdirectory(engines)
+ add_subdirectory(engineexplorer)
+ add_subdirectory(plasma)
+-add_subdirectory(kickoff)
++add_subdirectory(runners)
++
+--- a/plasma/animators/default/plasma-animator-default.desktop
++++ b/plasma/animators/default/plasma-animator-default.desktop
+@@ -7,6 +7,7 @@
+ Name[de]=Plasma Animations-Treiber
+ Name[el]=Προκαθορισμένη κίνηση Plasma
+ Name[es]=Animador predeterminado de Plasma
++Name[et]=Vaikimisi Plasma animeerija
+ Name[fa]=پویانمای پیش‌فرض پلاسما
+ Name[he]=מנפיש ברירת המחדל של Plasma
+ Name[ja]=デフォルトの Plasma アニメータ
+--- a/plasma/plasma/controlbox.h
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- *   Copyright 2007 by Matt Williams <matt at milliams.com>
+- *
+- *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU Library General Public License version 2 as
+- *   published by the Free Software Foundation
+- *
+- *   This 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 Library General Public
+- *   License along with this program; if not, write to the
+- *   Free Software Foundation, Inc.,
+- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+- */
+-
+-#ifndef CONTROL_BOX_H
+-#define CONTROL_BOX_H
+-
+-#include <QtGui/QWidget>
+-#include <QtGui/QStandardItemModel>
+-
+-#include <plasma/plasma.h>
+-
+-class QLabel;
+-class QPushButton;
+-class QTreeView;
+-class QModelIndex;
+-class QStandardItemModel;
+-class QTimeLine;
+-
+-class KComboBox;
+-
+-class DisplayLabel;
+-class ControlWidget;
+-class PlasmoidListItemModel;
+-
+-/**
+- * @short The Desktop configuration widget
+- * Just add one of these to the Corona and you've got an instant config box.
+- */
+-class ControlBox : public QWidget
+-{
+-    Q_OBJECT
+-
+-    public:
+-        ControlBox(QWidget* parent);
+-        ~ControlBox();
+-        bool eventFilter(QObject *watched, QEvent *event);
+-
+-    Q_SIGNALS:
+-        void zoomIn();
+-        void zoomOut();
+-        void addApplet(const QString&);
+-        void lockInterface(bool);
+-
+-    protected:
+-        //void mousePressEvent (QMouseEvent* event);
+-        void setupBox(); ///<Create contents of the config dialog
+-
+-    protected Q_SLOTS:
+-        void showBox(); ///<Show the config widget
+-        void hideBox(); ///<Hide the config widget
+-        void finishBoxHiding();
+-        void animateBox(int frame); ///<Process the frames to create an animation
+-
+-    private:
+-        ControlWidget* m_box; ///<The configuraion dialog widget
+-        DisplayLabel* m_displayLabel; ///<The 'show config' button
+-        QTimeLine* m_timeLine;
+-        QTimer* m_exitTimer;
+-
+-        bool m_boxIsShown;
+-};
+-
+-/**
+- * @short The widget that contains the actual settings
+- */
+-class ControlWidget : public QWidget
+-{
+-    Q_OBJECT
+-
+-    public:
+-        ControlWidget(QWidget* parent);
+-        ~ControlWidget();
+-        QPushButton* zoomInButton;
+-        QPushButton* zoomOutButton;
+-
+-    protected:
+-        void refreshPlasmoidList();
+-
+-        QLabel* m_label;
+-        QTreeView *m_appletList;
+-        PlasmoidListItemModel* m_appletListModel;
+-
+-    protected Q_SLOTS:
+-        void addApplet(const QModelIndex& plasmoidIndex);
+-
+-    Q_SIGNALS:
+-        void addApplet(const QString&);
+-        void lockInterface(bool);
+-};
+-
+-/**
+- * A custom Item Model so that the correct MIME type can be set and so the name
+- * of the plasmoid can be passed.
+- */
+-class PlasmoidListItemModel : public QStandardItemModel
+-{
+-    public:
+-        enum ItemDataRole {
+-            AppletNameRole = Qt::UserRole
+-        };
+-        PlasmoidListItemModel(QWidget* parent = 0);
+-
+-        QStringList mimeTypes() const;
+-        QMimeData* mimeData(const QModelIndexList &indexes) const;
+-};
+-
+-#endif // multiple inclusion guard
+--- a/plasma/plasma/controlbox.cpp
++++ /dev/null
+@@ -1,337 +0,0 @@
+-/*
+- *   Copyright 2007 by Matt Williams <matt at milliams.com>
+- *
+- *   This program is free software; you can redistribute it and/or modify
+- *   it under the terms of the GNU Library General Public License version 2 as
+- *   published by the Free Software Foundation
+- *
+- *   This 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 Library General Public
+- *   License along with this program; if not, write to the
+- *   Free Software Foundation, Inc.,
+- *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+- */
+-
+-#include "controlbox.h"
+-
+-#include <QApplication>
+-#include <QCheckBox>
+-#include <QHeaderView>
+-#include <QLabel>
+-#include <QLineEdit>
+-#include <QMouseEvent>
+-#include <QPainter>
+-#include <QPushButton>
+-#include <QStandardItemModel>
+-#include <QStringList>
+-#include <QTimeLine>
+-#include <QTimer>
+-#include <QTreeView>
+-#include <QVBoxLayout>
+-
+-#include <KComboBox>
+-#include <KLocale>
+-#include <KDebug>
+-#include <KIcon>
+-#include <KLibrary>
+-//#include <KLibLoader>
+-
+-#include "plasma/applet.h"
+-#include "plasma/svg.h"
+-
+-//BEGIN - DisplayLabel
+-
+-class DisplayLabel : public QLabel
+-{
+-    public:
+-        DisplayLabel(const QString& text, QWidget *parent);
+-        //QSize minimumSizeHint();
+-
+-    protected:
+-        void paintEvent(QPaintEvent *event);
+-
+-    private:
+-        Plasma::Svg m_background;
+-};
+-
+-DisplayLabel::DisplayLabel(const QString& text, QWidget *parent)
+-    : QLabel(text, parent),
+-      m_background("widgets/toolbox-button")
+-{
+-    setAlignment(Qt::AlignCenter);
+-    resize(100, 100);
+-    m_background.resize(size());
+-}
+-
+-/*
+-QSize DisplayLabel::minimumSizeHint()
+-{
+-    QSize size = QLabel::minimumSizeHint();
+-    size.setHeight(size.height() * 2);
+-    size.setWidth(size.width() * 5 / 3);
+-    return size;
+-}
+-*/
+-
+-void DisplayLabel::paintEvent(QPaintEvent* event)
+-{
+-    Q_UNUSED(event)
+-
+-    QPainter p(this);
+-    m_background.paint(&p, rect());
+-    QLabel::paintEvent(event);
+-}
+-
+-//BEGIN- PlasmoidListItemModel
+-
+-PlasmoidListItemModel::PlasmoidListItemModel(QWidget* parent)
+-    : QStandardItemModel(parent)
+-{
+-}
+-
+-QStringList PlasmoidListItemModel::mimeTypes() const
+-{
+-    QStringList types;
+-    types << QLatin1String("text/x-plasmoidservicename");
+-    return types;
+-}
+-
+-QMimeData* PlasmoidListItemModel::mimeData(const QModelIndexList &indexes) const
+-{
+-    if (indexes.count() <= 0) {
+-        return 0;
+-    }
+-
+-    QModelIndex parent = indexes[0].parent();
+-    if (!parent.isValid()) {
+-        //tried to grab a category
+-        return 0;
+-    }
+-    QStandardItem* category = item(parent.row(), 0);
+-
+-    QStringList types = mimeTypes();
+-
+-    if (types.isEmpty()) {
+-        return 0;
+-    }
+-
+-    QMimeData *data = new QMimeData();
+-
+-    QString format = types.at(0);
+-
+-    QStandardItem* selectedItem = category->child(indexes[0].row(), 0);
+-    QByteArray appletName(selectedItem->data(AppletNameRole).toByteArray());
+-
+-    data->setData(format, appletName);
+-
+-    return data;
+-}
+-
+-//BEGIN - ControlWidget
+-
+-ControlWidget::ControlWidget(QWidget *parent)
+-    : QWidget(parent)
+-{
+-    QPushButton* hideBoxButton = new QPushButton(i18n("Hide Config Box"), this);
+-    zoomInButton = new QPushButton(i18n("Zoom In"), this);
+-    zoomOutButton = new QPushButton(i18n("Zoom Out"), this);
+-    connect(hideBoxButton, SIGNAL(pressed()), parent, SLOT(hideBox()));
+-
+-    m_appletList = new QTreeView(this);
+-    m_appletList->header()->hide();
+-    m_appletList->setDragEnabled(true);
+-    m_appletListModel = new PlasmoidListItemModel(this);
+-    m_appletList->setModel(m_appletListModel);
+-    m_appletList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+-    connect(m_appletList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(addApplet(QModelIndex)));
+-
+-    m_label = new QLabel("Plasmoids:", this);
+-
+-    //TODO: this should be delayed until (if) the box is actually shown.
+-    refreshPlasmoidList();
+-
+-    QCheckBox* lockApplets = new QCheckBox(i18n("Lock Desktop"), this);
+-    connect(lockApplets, SIGNAL(toggled(bool)), this, SIGNAL(lockInterface(bool)));
+-
+-    //This is all to change of course
+-    QVBoxLayout* boxLayout = new QVBoxLayout(this);
+-    boxLayout->addWidget(hideBoxButton);
+-    boxLayout->addWidget(lockApplets);
+-    boxLayout->addWidget(zoomInButton);
+-    boxLayout->addWidget(zoomOutButton);
+-    boxLayout->addWidget(m_label);
+-    boxLayout->addWidget(m_appletList);
+-    //setLayout(boxLayout);
+-}
+-
+-ControlWidget::~ControlWidget() {}
+-
+-void ControlWidget::refreshPlasmoidList()
+-{
+-    m_appletListModel->clear();
+-    m_appletListModel->setColumnCount(1);
+-
+-    foreach (const QString &category, Plasma::Applet::knownCategories()) {
+-        KPluginInfo::List applets = Plasma::Applet::knownApplets(category);
+-
+-        if (applets.count() < 1) {
+-            continue;
+-        }
+-
+-        QStandardItem* parent = new QStandardItem(category);
+-        m_appletListModel->appendRow(parent);
+-        int rowCount = 0;
+-
+-        foreach (const KPluginInfo &info, applets) {
+-            QString category = Plasma::Applet::category(info);
+-//            QStandardItem *item = new PlasmoidItem(info);
+-            QStandardItem *item = new QStandardItem(info.name());
+-            item->setData(info.pluginName(), PlasmoidListItemModel::AppletNameRole);
+-            parent->setChild(rowCount, 0, item);
+-            ++rowCount;
+-        }
+-    }
+-
+-#ifndef NDEBUG
+-    //kDebug() << "Known categories: " << Plasma::Applet::knownCategories();
+-#endif
+-
+-    m_appletListModel->sort(0);
+-    m_appletList->expandAll();
+-}
+-
+-void ControlWidget::addApplet(const QModelIndex& plasmoidIndex)
+-{
+-    QStandardItem* item = m_appletListModel->itemFromIndex(plasmoidIndex);
+-    if (!item || !item->data(PlasmoidListItemModel::AppletNameRole).isValid()) {
+-        kDebug() << "ControlWidget::addApplet no item at " << plasmoidIndex;
+-        return;
+-    }
+-
+-    emit addApplet(item->data(PlasmoidListItemModel::AppletNameRole).toString());
+-}
+-
+-//BEGIN - ControlBox
+-
+-ControlBox::ControlBox(QWidget* parent)
+-    : QWidget(parent),
+-      m_box(0),
+-      m_boxIsShown(false)
+-{
+-    //The display box label/button
+-    m_displayLabel = new DisplayLabel(i18n("Desktop Toolbox"), this);
+-    m_displayLabel->show();
+-    m_displayLabel->installEventFilter(this);
+-    resize(m_displayLabel->size());
+-
+-    //The hide box timer
+-    m_exitTimer = new QTimer(this);
+-    m_exitTimer->setInterval(300);
+-    m_exitTimer->setSingleShot(true);
+-    connect(m_exitTimer, SIGNAL(timeout()), this, SLOT(hideBox()));
+-
+-    //Set up the animation timeline
+-    m_timeLine = new QTimeLine(300, this);
+-    m_timeLine->setFrameRange(0, 25); //25 step anumation
+-    m_timeLine->setCurveShape(QTimeLine::EaseInOutCurve);
+-    connect(m_timeLine, SIGNAL(frameChanged(int)), this, SLOT(animateBox(int)));
+-    connect(m_timeLine, SIGNAL(finished()), this, SLOT(finishBoxHiding()));
+-}
+-
+-ControlBox::~ControlBox()
+-{
+-}
+-
+-bool ControlBox::eventFilter(QObject *watched, QEvent *event)
+-{
+-    if (watched == m_displayLabel) {
+-        if (event->type() == QEvent::Enter) {
+-            showBox();
+-        }
+-    } else if (watched == m_box) {
+-        if (event->type() == QEvent::Leave) {
+-            QWidget* widget = qApp->activePopupWidget();
+-
+-            if (!widget) {
+-                m_exitTimer->start();
+-            }
+-        } else if (event->type() == QEvent::Enter) {
+-            m_exitTimer->stop(); //If not a leave event, stop the box from closing
+-        }
+-    }
+-
+-    return QWidget::eventFilter(watched, event);
+-}
+-
+-void ControlBox::showBox()
+-{
+-    if (m_boxIsShown) {
+-        return;
+-    }
+-
+-    // set up the actual widget here on first show
+-    if (!m_box) {
+-        m_box = new ControlWidget(this);
+-        m_box->installEventFilter(this);
+-        //m_box->hide();
+-        connect(m_box, SIGNAL(addApplet(const QString&)), this, SIGNAL(addApplet(const QString&)));
+-        connect(m_box, SIGNAL(lockInterface(bool)), this, SIGNAL(lockInterface(bool)));
+-        connect(m_box->zoomInButton, SIGNAL(clicked()), this, SIGNAL(zoomIn()));
+-        connect(m_box->zoomOutButton, SIGNAL(clicked()), this, SIGNAL(zoomOut()));
+-    }
+-
+-    m_boxIsShown = true;
+-    m_box->move(-m_box->size().width(),-m_box->size().height());
+-    resize(m_box->sizeHint()); //resize this widget so the full contents of m_box can be seen.
+-    m_box->show();
+-    m_timeLine->setDirection(QTimeLine::Forward);
+-    m_timeLine->start();
+-}
+-
+-void ControlBox::hideBox()
+-{
+-    if (!m_boxIsShown) {
+-        return;
+-    }
+-
+-    m_boxIsShown = false;
+-    m_timeLine->setDirection(QTimeLine::Backward);
+-    m_timeLine->start();
+-}
+-
+-void ControlBox::animateBox(int frame)
+-{
+-    //Display the config box
+-    qreal boxWidth = m_box->size().width();
+-    qreal boxHeight = m_box->size().height();
+-    qreal boxStep = ((qreal(frame)/25) - 1.0);
+-    m_box->move(static_cast<int>(boxWidth*boxStep),static_cast<int>(boxHeight*boxStep));
+-
+-    //And hide the label
+-    qreal labelWidth = m_displayLabel->size().width();
+-    qreal labelHeight = m_displayLabel->size().height();
+-    qreal labelStep = (-qreal(frame)/25);
+-    m_displayLabel->move(static_cast<int>(labelWidth*labelStep),static_cast<int>(labelHeight*labelStep));
+-}
+-
+-void ControlBox::finishBoxHiding()
+-{
+-    if (m_timeLine->direction() == QTimeLine::Backward) {
+-        resize(m_displayLabel->size()); //resize this widget so it's only the size of the label
+-        m_box->hide();
+-    }
+-}
+-
+-/*void ControlBox::mousePressEvent(QMouseEvent* event)
+-{
+-    QWidget::mousePressEvent(event);
+-    if (event->button() == Qt::LeftButton) {
+-        showBox();
+-    }
+-}*/
+-
+-#include "controlbox.moc"
+--- a/plasma/plasma/plasmaapp.cpp
++++ b/plasma/plasma/plasmaapp.cpp
+@@ -156,8 +156,9 @@
+                  << "| screen:" << containment->screen()
+                  << "| geometry:" << containment->geometry()
+                  << "| zValue:" << containment->zValue();
+-        if (containment->name() == "Panel") {
+-            Plasma::PanelView *panelView = new Plasma::PanelView(containment);
++        if (containment->type() == Plasma::Containment::PanelContainment) {
++            kDebug() << "we have a panel!";
++            PanelView *panelView = new PanelView(containment);
+             m_panels << panelView;
+             panelView->show();
+         }
+--- a/plasma/plasma/panelview.h
++++ b/plasma/plasma/panelview.h
+@@ -28,10 +28,10 @@
+ 
+ namespace Plasma
+ {
+-
+-class Containment;
+-class Corona;
+-class Svg;
++    class Containment;
++    class Corona;
++    class Svg;
++}
+ 
+ class PanelView : public QGraphicsView
+ {
+@@ -79,6 +79,5 @@
+     Plasma::Svg *m_background;
+ };
+ 
+-} // Namespace
+ #endif
+ 
+--- a/plasma/plasma/plasmaapp.h
++++ b/plasma/plasma/plasmaapp.h
+@@ -28,7 +28,6 @@
+ {
+     class Corona;
+     class Containment;
+-    class PanelView;
+ } // namespace Plasma
+ 
+ class RootWidget;
+@@ -59,7 +58,7 @@
+ 
+     RootWidget *m_root;
+     Plasma::Corona *m_corona;
+-    QList<Plasma::PanelView*> m_panels;
++    QList<PanelView*> m_panels;
+ };
+ 
+ #endif // multiple inclusion guard
+--- a/plasma/plasma/rootwidget.cpp
++++ b/plasma/plasma/rootwidget.cpp
+@@ -29,7 +29,6 @@
+ #include "plasma/plasma.h"
+ #include "plasma/svg.h"
+ 
+-#include "controlbox.h"
+ #include "desktopview.h"
+ #include "plasmaapp.h"
+ 
+@@ -46,14 +45,8 @@
+         m_desktop = new DesktopView(this, i);
+         m_desktop->setGeometry(desktop.screenGeometry(i));
+     }
+-    Plasma::Corona* corona = PlasmaApp::self()->corona();
+ 
+-    m_controlBox = new ControlBox(this);
+-
+-    connect(m_controlBox, SIGNAL(zoomIn()), m_desktop, SLOT(zoomIn()));
+-    connect(m_controlBox, SIGNAL(zoomOut()), m_desktop, SLOT(zoomOut()));
+-    connect(m_controlBox, SIGNAL(addApplet(const QString&)), corona, SLOT(addApplet(const QString&)));
+-    connect(m_controlBox, SIGNAL(lockInterface(bool)), corona, SLOT(setImmutable(bool)));
++    PlasmaApp::self()->corona();
+ }
+ 
+ void RootWidget::setAsDesktop(bool setAsDesktop)
+--- a/plasma/plasma/panelview.cpp
++++ b/plasma/plasma/panelview.cpp
+@@ -32,16 +32,11 @@
+ #include <plasma/plasma.h>
+ #include <plasma/svg.h>
+ 
+-namespace Plasma
+-{
+-
+-
+-
+ PanelView::PanelView(Plasma::Containment *panel, QWidget *parent)
+     : QGraphicsView(parent),
+       m_containment(panel)
+ {
+-    Q_ASSERT(qobject_cast<Corona*>(m_containment->scene()));
++    Q_ASSERT(qobject_cast<Plasma::Corona*>(m_containment->scene()));
+     setScene(m_containment->scene());
+     updatePanelGeometry();
+     kDebug() << "Panel geometry is" << m_containment->geometry();
+@@ -60,9 +55,7 @@
+     // KWin setup
+     KWindowSystem::setType(winId(), NET::Dock);
+     KWindowSystem::setState(winId(), NET::Sticky | NET::KeepAbove);
+-
+-    // Highly questionable behavior used in kicker..
+-    // KWindowSystem::setOnAllDesktops(winId(), true);	
++    KWindowSystem::setOnAllDesktops(winId(), true);
+ 
+     updateStruts();
+ }
+@@ -86,17 +79,19 @@
+ 
+ Plasma::Corona *PanelView::corona() const
+ {
+-    return qobject_cast<Corona*>(scene());
++    return qobject_cast<Plasma::Corona*>(scene());
+ }
+ 
+ void PanelView::updatePanelGeometry()
+ {
+     kDebug() << "New panel geometry is" << m_containment->geometry();
+-    QPoint pos = m_containment->scenePos().toPoint();
++    QPoint pos = m_containment->pos().toPoint();
+     QSize size = m_containment->size().toSize();
+     QRect geom(pos, size);
+-    kDebug() << "I think the panel is at " << geom;
+     setGeometry(geom);
++    pos = m_containment->scenePos().toPoint();
++    geom.moveTopLeft(pos);
++    kDebug() << "I think the panel is at " << geom;
+     setSceneRect(geom);
+ }
+ 
+@@ -159,5 +154,3 @@
+     updateStruts();
+ }
+ 
+-
+-} // Namespace
+--- a/plasma/plasma/CMakeLists.txt
++++ b/plasma/plasma/CMakeLists.txt
+@@ -1,7 +1,6 @@
+ include_directories(${KDEBASE_WORKSPACE_SOURCE_DIR}/libs)
+ 
+ set(plasma_SRCS
+-    controlbox.cpp
+     desktopview.cpp
+     main.cpp
+     plasmaapp.cpp
+--- a/plasma/plasma/rootwidget.h
++++ b/plasma/plasma/rootwidget.h
+@@ -23,7 +23,6 @@
+ #include <QWidget>
+ 
+ class DesktopView;
+-class ControlBox;
+ 
+ /**
+  * @short The base widget that contains the desktop
+@@ -60,7 +59,6 @@
+ 
+     private:
+         DesktopView* m_desktop;
+-        ControlBox* m_controlBox;
+ };
+ 
+ #endif

Deleted: branches/kde4/packages/kdebase-workspace/debian/patches/01_pull_r726655_r725907_r725662_r725652_r725648_r725642.diff




More information about the pkg-kde-commits mailing list