summaryrefslogtreecommitdiffstats
path: root/kicker/kicker/core/containerarea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kicker/kicker/core/containerarea.cpp')
-rw-r--r--kicker/kicker/core/containerarea.cpp1939
1 files changed, 1939 insertions, 0 deletions
diff --git a/kicker/kicker/core/containerarea.cpp b/kicker/kicker/core/containerarea.cpp
new file mode 100644
index 000000000..23732e684
--- /dev/null
+++ b/kicker/kicker/core/containerarea.cpp
@@ -0,0 +1,1939 @@
+/*****************************************************************
+
+Copyright (c) 1996-2004 the kicker authors. See file AUTHORS.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qwmatrix.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+#include <kprocess.h>
+#include <krootpixmap.h>
+#include <kpixmap.h>
+#include <klocale.h>
+#include <kio/netaccess.h>
+#include <kservice.h>
+#include <kurldrag.h>
+
+#include "addapplet.h"
+#include "browser_dlg.h"
+#include "container_applet.h"
+#include "container_button.h"
+#include "containerarealayout.h"
+#include "dirdrop_mnu.h"
+#include "exe_dlg.h"
+#include "extensionmanager.h"
+#include "kicker.h"
+#include "kickerSettings.h"
+#include "kickertip.h"
+#include "paneldrag.h"
+#include "pluginmanager.h"
+
+#include "containerarea.h"
+
+// for multihead
+extern int kicker_screen_number;
+
+ContainerArea::ContainerArea(KConfig* _c,
+ QWidget* parent,
+ QPopupMenu* opMenu,
+ const char* name)
+ : Panner(parent, name),
+ _moveAC(0),
+ _pos(KPanelExtension::Left),
+ _config(_c),
+ _dragIndicator(0),
+ _dragMoveAC(0),
+ _dragMoveOffset(QPoint(0,0)),
+ m_opMenu(opMenu),
+ _rootPixmap(0),
+ _useBgTheme(false),
+ _bgSet(false),
+ m_canAddContainers(true),
+ m_immutable(_c->isImmutable()),
+ m_updateBackgroundsCalled(false),
+ m_layout(0),
+ m_addAppletDialog(0)
+{
+ setBackgroundOrigin( WidgetOrigin );
+
+ m_contents = viewport();
+
+ m_layout = new ContainerAreaLayout(m_contents);
+
+ // Install an event filter to propagate layout hints coming from m_contents.
+ m_contents->installEventFilter(this);
+
+ setBackground();
+
+ connect(&_autoScrollTimer, SIGNAL(timeout()), SLOT(autoScroll()));
+ connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(setBackground()));
+ connect(Kicker::the(), SIGNAL(immutabilityChanged(bool)),
+ SLOT(immutabilityChanged(bool)));
+ connect(this, SIGNAL(contentsMoving(int, int)), SLOT(setBackground()));
+}
+
+ContainerArea::~ContainerArea()
+{
+ // don't emit signals from destructor
+ blockSignals( true );
+ // clear applets
+ removeAllContainers();
+}
+
+void ContainerArea::initialize(bool useDefaultConfig)
+{
+ // do we really need to do this?
+ removeAllContainers();
+
+ // restore applet layout or load a default panel layout
+ _config->setGroup("General");
+ if (_config->hasKey("Applets2"))
+ {
+ if (_config->groupIsImmutable("General"))
+ {
+ m_immutable = true;
+ }
+
+ m_canAddContainers = !m_immutable &&
+ !_config->entryIsImmutable("Applets2");
+ loadContainers(_config->readListEntry("Applets2"));
+ }
+ else if (useDefaultConfig)
+ {
+ defaultContainerConfig();
+ }
+
+ setAcceptDrops(!isImmutable());
+ QTimer::singleShot(0, this, SLOT(resizeContents()));
+}
+
+void ContainerArea::defaultContainerConfig()
+{
+ //FIXME: make this use a file template so it isn't hardcoded anymore
+ BaseContainer::List containers;
+
+ containers.append(new KMenuButtonContainer(m_opMenu, m_contents));
+
+ int dsize;
+ if (orientation() == Qt::Horizontal)
+ {
+ dsize = width();
+ }
+ else
+ {
+ dsize = height();
+ }
+
+ dsize -= 560;
+ QStringList buttons;
+
+ QFile f(locate("data", "kicker/default-apps"));
+ if (f.open(IO_ReadOnly))
+ {
+ QTextStream is(&f);
+
+ while (!is.eof())
+ buttons << is.readLine();
+
+ f.close();
+ }
+ else
+ {
+ buttons << "kde-Home.desktop"
+ << "kde-konqbrowser.desktop";
+ }
+
+ //int size = dsize;
+ for (QStringList::ConstIterator it = buttons.begin(); it != buttons.end(); ++it)
+ {
+ /*size -= 42;
+ if (size <= 0)
+ break;*/
+
+ BaseContainer *button = 0;
+ KService::Ptr service = KService::serviceByStorageId(*it);
+ if (!service)
+ {
+ // look for a special button
+ QString s = locate("appdata", *it);
+ if (s.isEmpty()) continue;
+ QString itExt = (*it).section('/', 1);
+ button = new ExtensionButtonContainer(itExt, m_opMenu, m_contents);
+ }
+ else
+ {
+ button = new ServiceButtonContainer(service, m_opMenu, m_contents);
+ }
+
+ if (button->isValid())
+ {
+ containers.append(button);
+ }
+ else
+ {
+ delete button;
+ }
+ }
+
+ PluginManager* manager = PluginManager::the();
+
+ // pager applet
+ AppletContainer* a = manager->createAppletContainer(
+ "minipagerapplet.desktop",
+ true,
+ QString::null,
+ m_opMenu,
+ m_contents);
+ if (a)
+ {
+ a->setFreeSpace(0.09);
+ containers.append(a);
+ }
+
+ // taskbar applet
+ a = manager->createAppletContainer(
+ "taskbarapplet.desktop",
+ true,
+ QString::null,
+ m_opMenu,
+ m_contents);
+ if (a)
+ {
+ a->setFreeSpace(0.09);
+ containers.append(a);
+ }
+
+ // system tray applet
+ a = manager->createAppletContainer(
+ "systemtrayapplet.desktop",
+ true,
+ QString::null,
+ m_opMenu,
+ m_contents );
+ if (a)
+ {
+ a->setFreeSpace(1);
+ containers.append(a);
+ }
+
+ // clock applet
+ a = manager->createAppletContainer(
+ "clockapplet.desktop",
+ true,
+ QString::null,
+ m_opMenu,
+ m_contents );
+ if (a)
+ {
+ a->setFreeSpace(1);
+ containers.append(a);
+ }
+
+ for (BaseContainer::Iterator it = containers.begin();
+ it != containers.end();
+ ++it)
+ {
+ addContainer(*it);
+ }
+
+ saveContainerConfig();
+}
+
+void ContainerArea::loadContainers(const QStringList& containers)
+{
+ // read applet list
+ bool badApplets = false;
+
+ // now restore the applets
+ QStringList::const_iterator it = containers.constBegin();
+ QStringList::const_iterator itEnd = containers.constEnd();
+ for (; it != itEnd; ++it)
+ {
+ QString appletId(*it);
+
+ // is there a config group for this applet?
+ if (!_config->hasGroup(appletId))
+ {
+ continue;
+ }
+
+ KConfigGroup group(_config, appletId.latin1());
+
+ BaseContainer* a = 0;
+
+ int sep = appletId.findRev('_');
+ Q_ASSERT(sep != -1);
+ QString appletType = appletId.left(sep);
+
+ // create a matching applet container
+ if (appletType == "KMenuButton")
+ a = new KMenuButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "DesktopButton")
+ a = new DesktopButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "WindowListButton")
+ a = new WindowListButtonContainer(group, m_opMenu, m_contents);
+ else if ((appletType == "BookmarksButton") && kapp->authorizeKAction("bookmarks"))
+ a = new BookmarksButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "ServiceButton")
+ a = new ServiceButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "URLButton")
+ a = new URLButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "BrowserButton")
+ a = new BrowserButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "ServiceMenuButton")
+ a = new ServiceMenuButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "ExecButton")
+ a = new NonKDEAppButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "ExtensionButton")
+ a = new ExtensionButtonContainer(group, m_opMenu, m_contents);
+ else if (appletType == "Applet")
+ {
+ bool immutable = Kicker::the()->isImmutable() ||
+ group.groupIsImmutable() ||
+ group.entryIsImmutable("ConfigFile");
+ a = PluginManager::the()->createAppletContainer(
+ group.readPathEntry("DesktopFile"),
+ true, // isStartup
+ group.readPathEntry("ConfigFile"),
+ m_opMenu,
+ m_contents,
+ immutable);
+ }
+
+ if (a && a->isValid())
+ {
+ a->setAppletId(appletId);
+ a->loadConfiguration(group);
+ addContainer(a);
+ }
+ else
+ {
+ badApplets = true;
+ delete a;
+ }
+ }
+
+ if (badApplets)
+ {
+ // since we may have had Bad Applets in our list
+ // let's save it again, just in case
+ saveContainerConfig();
+ }
+
+ // while this is also called in addContainer (well, resizeContents()),
+ // it gets executed too soon. we need to wait until the containers are
+ // actually resized, but we enter the event loop prior to that happening
+ // above.
+ QTimer::singleShot(0, this, SLOT(updateContainersBackground()));
+}
+
+void ContainerArea::saveContainerConfig(bool layoutOnly)
+{
+ if (!canAddContainers())
+ {
+ return;
+ }
+
+ // Save the applet list
+ QStringList alist;
+ QLayoutIterator it2 = m_layout->iterator();
+ for (; it2.current(); ++it2)
+ {
+ BaseContainer* a = dynamic_cast<BaseContainer*>(it2.current()->widget());
+ if (a)
+ {
+ KConfigGroup group(_config, a->appletId().latin1());
+ a->saveConfiguration(group, layoutOnly);
+ alist.append(a->appletId());
+ }
+ }
+
+ KConfigGroup group( _config, "General" );
+ group.writeEntry("Applets2", alist);
+
+ _config->sync();
+}
+
+void ContainerArea::removeAllContainers()
+{
+ for (BaseContainer::List::const_iterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ delete *it;
+ }
+ m_containers.clear();
+}
+
+void ContainerArea::configure()
+{
+ setBackground();
+
+ for (BaseContainer::Iterator it = m_containers.begin();
+ it != m_containers.end();
+ ++it)
+ {
+ (*it)->configure();
+ }
+
+ resizeContents();
+}
+
+const QWidget* ContainerArea::addButton(const AppletInfo& info)
+{
+ QString buttonType = info.library();
+
+ if (buttonType == "BookmarksButton")
+ {
+ if (kapp->authorizeKAction("bookmarks"))
+ {
+ return addBookmarksButton();
+ }
+ }
+ else if (buttonType == "BrowserButton")
+ {
+ return addBrowserButton();
+ }
+ else if (buttonType == "DesktopButton")
+ {
+ return addDesktopButton();
+ }
+ else if (buttonType == "ExecButton")
+ {
+ return addNonKDEAppButton();
+ }
+ else if (buttonType == "KMenuButton")
+ {
+ return addKMenuButton();
+ }
+ else if (buttonType == "WindowListButton")
+ {
+ return addWindowListButton();
+ }
+ else // ExtensionButton
+ {
+ return addExtensionButton(info.desktopFile());
+ }
+
+ return 0;
+}
+
+const QWidget* ContainerArea::addKMenuButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new KMenuButtonContainer(m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addDesktopButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new DesktopButtonContainer(m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addWindowListButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new WindowListButtonContainer(m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addBookmarksButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new BookmarksButtonContainer(m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addServiceButton(const QString& desktopFile)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new ServiceButtonContainer(desktopFile,m_opMenu,
+ m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addURLButton(const QString &url)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new URLButtonContainer(url, m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addBrowserButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ PanelBrowserDialog *dlg = new PanelBrowserDialog(QDir::home().path(),
+ "kdisknav");
+
+ if (dlg->exec() == QDialog::Accepted)
+ {
+ return addBrowserButton(dlg->path(), dlg->icon());
+ }
+
+ return 0;
+}
+
+const QWidget* ContainerArea::addBrowserButton(const QString &startDir,
+ const QString& icon)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new BrowserButtonContainer(startDir, m_opMenu,
+ icon, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addServiceMenuButton(const QString& relPath)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new ServiceMenuButtonContainer(relPath, m_opMenu,
+ m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addNonKDEAppButton()
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ PanelExeDialog dlg(QString::null, QString::null, QString::null,
+ QString::null, QString::null, false, 0);
+
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ return addNonKDEAppButton(dlg.title(), dlg.description(),
+ dlg.command(), dlg.iconPath(),
+ dlg.commandLine(),
+ dlg.useTerminal());
+ }
+
+ return 0;
+}
+
+const QWidget* ContainerArea::addNonKDEAppButton(const QString &name,
+ const QString &description,
+ const QString& filePath,
+ const QString &icon,
+ const QString &cmdLine,
+ bool inTerm)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer *b = new NonKDEAppButtonContainer(name,
+ description,
+ filePath, icon,
+ cmdLine, inTerm,
+ m_opMenu, m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+const QWidget* ContainerArea::addExtensionButton(const QString& df)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ BaseContainer* b = new ExtensionButtonContainer(df,
+ m_opMenu,
+ m_contents);
+ completeContainerAddition(b);
+ return b;
+}
+
+void ContainerArea::completeContainerAddition(BaseContainer* container,
+ int index)
+{
+ //FIXME: the original comment was:
+ // Set freespace to one since the container will be added at the end.
+ // yet this is not always true =/
+ container->setFreeSpace(1);
+ addContainer(container, true, index);
+ scrollTo(container);
+ saveContainerConfig();
+}
+
+AppletContainer* ContainerArea::addApplet(const AppletInfo& info,
+ bool isImmutable,
+ int insertionIndex)
+{
+ if (!canAddContainers())
+ {
+ return 0;
+ }
+
+ AppletContainer* a = PluginManager::the()->createAppletContainer(
+ info.desktopFile(),
+ false, // not startup
+ QString::null, // no config
+ m_opMenu,
+ m_contents,
+ isImmutable);
+
+ if (!a || !a->isValid())
+ {
+ delete a;
+ return 0;
+ }
+
+ completeContainerAddition(a, insertionIndex);
+ return a;
+}
+
+void ContainerArea::addContainer(BaseContainer* a, bool arrange, int index)
+{
+ if (!a)
+ {
+ return;
+ }
+
+ if (a->appletId().isNull())
+ {
+ a->setAppletId(createUniqueId(a->appletType()));
+ }
+
+ m_containers.append(a);
+
+ if (arrange)
+ {
+ QWidget* w = m_layout->widgetAt(index);
+ QPoint oldInsertionPoint = Kicker::the()->insertionPoint();
+ if (w)
+ {
+ // let's set the insertion point to where the widget asked to be
+ // put in front of is
+ Kicker::the()->setInsertionPoint(w->geometry().topLeft());
+ }
+
+ if (Kicker::the()->insertionPoint().isNull())
+ {
+ m_layout->insertIntoFreeSpace(a, QPoint());
+ }
+ else
+ {
+ m_layout->insertIntoFreeSpace(a, mapFromGlobal(Kicker::the()->insertionPoint()));
+ }
+
+ if (w)
+ {
+ Kicker::the()->setInsertionPoint(oldInsertionPoint);
+ }
+ }
+ else
+ {
+ m_layout->add(a);
+ }
+
+ connect(a, SIGNAL(moveme(BaseContainer*)),
+ SLOT(startContainerMove(BaseContainer*)));
+ connect(a, SIGNAL(removeme(BaseContainer*)),
+ SLOT(removeContainer(BaseContainer*)));
+ connect(a, SIGNAL(takeme(BaseContainer*)),
+ SLOT(takeContainer(BaseContainer*)));
+ connect(a, SIGNAL(requestSave()),
+ SLOT(slotSaveContainerConfig()));
+ connect(a, SIGNAL(maintainFocus(bool)),
+ this, SIGNAL(maintainFocus(bool)));
+
+ if (dynamic_cast<AppletContainer*>(a))
+ {
+ connect(a, SIGNAL(updateLayout()), SLOT(resizeContents()));
+ }
+
+ a->configure(orientation(), popupDirection());
+ a->show();
+ resizeContents();
+}
+
+bool ContainerArea::removeContainer(BaseContainer *a)
+{
+ if (!a || isImmutable() || a->isImmutable())
+ {
+ return false;
+ }
+
+ a->slotRemoved(_config);
+ m_containers.remove(a);
+ m_layout->remove(a);
+ a->deleteLater();
+ saveContainerConfig(true);
+ resizeContents();
+ return true;
+}
+
+bool ContainerArea::removeContainer(int index)
+{
+ if (isImmutable())
+ {
+ return false;
+ }
+
+ BaseContainer* a = dynamic_cast<BaseContainer*>(m_layout->widgetAt(index));
+ if (!a || a->isImmutable())
+ {
+ return false;
+ }
+
+ a->slotRemoved(_config);
+ m_containers.remove(a);
+ m_layout->remove(a);
+ a->deleteLater();
+ saveContainerConfig(true);
+ resizeContents();
+ return true;
+}
+
+void ContainerArea::removeContainers(BaseContainer::List containers)
+{
+ if (isImmutable())
+ {
+ return;
+ }
+
+ m_layout->setEnabled(false);
+
+ for (BaseContainer::List::const_iterator it = containers.constBegin();
+ it != containers.constEnd();
+ ++it)
+ {
+ BaseContainer* a = *it;
+ if (a->isImmutable())
+ {
+ continue;
+ }
+
+ a->slotRemoved(_config);
+ m_containers.remove(a);
+ m_layout->remove(a);
+ a->deleteLater();
+ }
+
+ m_layout->setEnabled(true);
+ saveContainerConfig(true);
+ resizeContents();
+}
+
+void ContainerArea::takeContainer(BaseContainer* a)
+{
+ if (!a)
+ {
+ return;
+ }
+
+ disconnect(a, SIGNAL(moveme(BaseContainer*)),
+ this, SLOT(startContainerMove(BaseContainer*)));
+ disconnect(a, SIGNAL(removeme(BaseContainer*)),
+ this, SLOT(removeContainer(BaseContainer*)));
+ disconnect(a, SIGNAL(takeme(BaseContainer*)),
+ this, SLOT(takeContainer(BaseContainer*)));
+ disconnect(a, SIGNAL(requestSave()),
+ this, SLOT(slotSaveContainerConfig()));
+ disconnect(a, SIGNAL(maintainFocus(bool)),
+ this, SIGNAL(maintainFocus(bool)));
+
+ // Just remove the group from our own config file. Leave separate config
+ // files untouched.
+ _config->deleteGroup(a->appletId().latin1());
+ _config->sync();
+ m_containers.remove(a);
+ m_layout->remove(a);
+ saveContainerConfig(true);
+ resizeContents();
+}
+
+void ContainerArea::resizeContents()
+{
+ int w = width();
+ int h = height();
+
+ if (orientation() == Qt::Horizontal)
+ {
+ int newWidth = m_layout->widthForHeight(h);
+ if (newWidth > w)
+ {
+ resizeContents(newWidth, h);
+ }
+ else
+ {
+ resizeContents(w, h);
+ }
+ }
+ else
+ {
+ int newHeight = m_layout->heightForWidth(w);
+
+ if (newHeight > h)
+ {
+ resizeContents(w, newHeight);
+ }
+ else
+ {
+ resizeContents(w, h);
+ }
+ }
+}
+
+QString ContainerArea::createUniqueId(const QString& appletType) const
+{
+ QString idBase = appletType + "_%1";
+ QString newId;
+ int i = 0;
+ bool unique = false;
+
+ while (!unique)
+ {
+ i++;
+ newId = idBase.arg(i);
+
+ unique = true;
+ for (BaseContainer::ConstIterator it = m_containers.begin();
+ it != m_containers.end();
+ ++it)
+ {
+ BaseContainer* b = *it;
+ if (b->appletId() == newId)
+ {
+ unique = false;
+ break;
+ }
+ }
+ }
+
+ return newId;
+}
+
+bool ContainerArea::canAddContainers() const
+{
+ return m_canAddContainers && Kicker::the()->canAddContainers();
+}
+
+void ContainerArea::startContainerMove(BaseContainer *a)
+{
+ if (!a || isImmutable())
+ {
+ return;
+ }
+
+ _moveAC = a;
+
+ KickerTip::enableTipping(false);
+ emit maintainFocus(true);
+ setMouseTracking(true);
+ grabMouse(sizeAllCursor);
+
+ m_layout->setStretchEnabled(false);
+ a->raise();
+}
+
+void ContainerArea::mouseReleaseEvent(QMouseEvent *)
+{
+ if (!_moveAC)
+ {
+ return;
+ }
+
+ // start container move was caled successfuly
+ // so we need to complete the move here
+ _autoScrollTimer.stop();
+ releaseMouse();
+ setCursor(arrowCursor);
+ setMouseTracking(false);
+
+ _moveAC->completeMoveOperation();
+ KickerTip::enableTipping(true);
+
+ _moveAC = 0;
+
+ emit maintainFocus(false);
+ m_layout->setStretchEnabled(true);
+ updateContainersBackground();
+ saveContainerConfig(true);
+}
+
+void ContainerArea::mouseMoveEvent(QMouseEvent *ev)
+{
+ if (!_moveAC)
+ {
+ Panner::mouseMoveEvent(ev);
+ return;
+ }
+
+ if (ev->state() == LeftButton && !rect().contains(ev->pos()))
+ {
+ // leaveEvent() doesn't work, while grabbing the mouse
+ _autoScrollTimer.stop();
+ releaseMouse();
+ setCursor(arrowCursor);
+ setMouseTracking(false);
+
+ _moveAC->completeMoveOperation();
+ KickerTip::enableTipping(true);
+
+ emit maintainFocus(false);
+ m_layout->setStretchEnabled(true);
+ updateContainersBackground();
+ saveContainerConfig(true);
+
+ PanelDrag *dd = new PanelDrag(_moveAC, this);
+ dd->setPixmap(kapp->iconLoader()->loadIcon(_moveAC->icon(), KIcon::Small));
+ grabKeyboard();
+ dd->drag();
+ releaseKeyboard();
+ return;
+ }
+
+ if (orientation() == Horizontal)
+ {
+ int oldX = _moveAC->x() + _moveAC->moveOffset().x();
+ int x = ev->pos().x() + contentsX();
+ if (ev->state() & ShiftButton)
+ {
+ m_layout->moveContainerPush(_moveAC, x - oldX);
+ }
+ else
+ {
+ m_layout->moveContainerSwitch(_moveAC, x - oldX);
+ /* FIXME: Scrolling when the container moves out of the viewport
+ bool scroll = false;
+ if (rtl)
+ if (newPos - 80 <= 0)
+ scroll = true;
+ else
+ if (newPos + 80 >= (horizontal ? geometry().width() - moving->geometry().width()
+ : geometry().height() - moving->geometry().height()))
+ scroll = true;
+ [...]
+ if (scroll) {
+ if (!_autoScrollTimer.isActive())
+ _autoScrollTimer.start(50);
+
+ if (horizontal)
+ scrollBy(dir*10, 0);
+ else
+ scrollBy(0, dir*10);
+ }
+ */
+ }
+ }
+ else
+ {
+ int oldY = _moveAC->y() + _moveAC->moveOffset().y();
+ int y = ev->pos().y() + contentsY();
+ if (ev->state() & ShiftButton)
+ {
+ m_layout->moveContainerPush(_moveAC, y - oldY);
+ }
+ else
+ {
+ m_layout->moveContainerSwitch(_moveAC, y - oldY);
+ // TODO: Scrolling
+ }
+ }
+
+ ensureVisible(ev->pos().x() + contentsX(), ev->pos().y() + contentsY());
+ updateContainersBackground();
+}
+
+int ContainerArea::position() const
+{
+ return static_cast<int>(_pos);
+}
+
+KPanelApplet::Direction ContainerArea::popupDirection() const
+{
+ return KickerLib::positionToDirection(_pos);
+}
+
+bool ContainerArea::isImmutable() const
+{
+ return m_immutable || Kicker::the()->isImmutable();
+}
+
+void ContainerArea::dragEnterEvent(QDragEnterEvent *ev)
+{
+ bool canAccept = !isImmutable() &&
+ (PanelDrag::canDecode(ev) ||
+ AppletInfoDrag::canDecode(ev) ||
+ KURLDrag::canDecode(ev));
+ ev->accept(canAccept);
+
+ if (!canAccept)
+ {
+ return;
+ }
+
+ m_layout->setStretchEnabled(false);
+
+ if (!_dragIndicator)
+ {
+ _dragIndicator = new DragIndicator(m_contents);
+ }
+
+ BaseContainer *draggedContainer = 0;
+ int preferedWidth = height();
+ int preferedHeight = width();
+ if (PanelDrag::decode(ev, &draggedContainer))
+ {
+ preferedWidth = draggedContainer->widthForHeight(height());
+ preferedHeight = draggedContainer->heightForWidth(width());
+ }
+
+ if (orientation() == Horizontal)
+ {
+ _dragIndicator->setPreferredSize(QSize(preferedWidth, height()));
+ }
+ else
+ {
+ _dragIndicator->setPreferredSize(QSize(width(), preferedHeight));
+ }
+ _dragMoveOffset = QPoint(_dragIndicator->width()/2,
+ _dragIndicator->height()/2);
+
+ // Find the container before the position of the dragindicator.
+ BaseContainer::Iterator it = m_containers.end();
+
+ if (it != m_containers.begin())
+ {
+ do
+ {
+ --it;
+ BaseContainer* a = *it;
+
+ if ((orientation() == Horizontal &&
+ a->x() < (ev->pos().x() + contentsX()) - _dragMoveOffset.x()) ||
+ (orientation() == Vertical &&
+ a->y() < (ev->pos().y() + contentsY()) - _dragMoveOffset.y()))
+ {
+ _dragMoveAC = a;
+ break;
+ }
+ } while (it != m_containers.begin());
+ }
+
+ if (orientation() == Horizontal)
+ {
+ moveDragIndicator(ev->pos().x() + contentsX() - _dragMoveOffset.x());
+ }
+ else
+ {
+ moveDragIndicator(ev->pos().y() + contentsY() - _dragMoveOffset.y());
+ }
+
+ _dragIndicator->show();
+}
+
+void ContainerArea::dragMoveEvent(QDragMoveEvent* ev)
+{
+ if (ev->source() == this)
+ {
+ // Abort the drag and go back to container sliding.
+ // Actually, this should be placed in dragEnterEvent(), but
+ // then it does work only on every second event.
+
+ // Cancel the drag by faking an Escape keystroke.
+ QKeyEvent fakedKeyPress(QEvent::KeyPress, Key_Escape, 0, 0);
+ QKeyEvent fakedKeyRelease(QEvent::KeyRelease, Key_Escape, 0, 0);
+ QApplication::sendEvent(this, &fakedKeyPress);
+ QApplication::sendEvent(this, &fakedKeyRelease);
+ qApp->processEvents();
+ startContainerMove(_moveAC);
+
+ // Align the container to the mouse position.
+ if (orientation() == Horizontal)
+ {
+ m_layout->moveContainerSwitch(_moveAC, ev->pos().x() + contentsX() - _moveAC->x());
+ }
+ else
+ {
+ m_layout->moveContainerSwitch(_moveAC, ev->pos().y() + contentsY() - _moveAC->y());
+ }
+ return;
+ }
+
+ if (!_dragIndicator)
+ {
+ return;
+ }
+
+ if (orientation() == Horizontal)
+ {
+ moveDragIndicator(ev->pos().x() + contentsX() - _dragMoveOffset.x());
+ }
+ else
+ {
+ moveDragIndicator(ev->pos().y() + contentsY() - _dragMoveOffset.y());
+ }
+}
+
+void ContainerArea::dragLeaveEvent(QDragLeaveEvent*)
+{
+ if (_dragIndicator)
+ {
+ _dragIndicator->hide();
+ }
+ m_layout->setStretchEnabled(true);
+ _dragMoveAC = 0;
+}
+
+void ContainerArea::dropEvent(QDropEvent *ev)
+{
+ if (!_dragIndicator)
+ {
+ // we assume that this is the result of a successful drag enter
+ // which means we'll have a _dragIndicator. if for
+ // some reason we don't, let's not go down this code path
+ return;
+ }
+
+ BaseContainer *a = 0;
+ if (PanelDrag::decode(ev, &a))
+ {
+ if (!a)
+ {
+ _dragMoveAC = 0;
+ _dragIndicator->hide();
+ m_layout->setStretchEnabled(true);
+ return;
+ }
+
+ QObject *parent = ev->source() ? ev->source()->parent() : 0;
+ while (parent && (parent != this))
+ {
+ parent = parent->parent();
+ }
+
+ if (parent)
+ {
+ // Move container a
+ if (orientation() == Horizontal)
+ {
+ int oldX = a->x();
+ int x = _dragIndicator->x();
+ m_layout->moveContainerSwitch(a, x - oldX);
+ }
+ else if (orientation() == Vertical)
+ {
+ int oldY = a->y();
+ int y = _dragIndicator->y();
+ m_layout->moveContainerSwitch(a, y - oldY);
+ }
+
+ _dragMoveAC = 0;
+ _dragIndicator->hide();
+ m_layout->setEnabled(true);
+ m_layout->setStretchEnabled(true);
+ saveContainerConfig(true);
+ return;
+ }
+
+ // it came from another panel
+ Kicker::the()->setInsertionPoint(_dragIndicator->pos());
+ a->reparent(m_contents, 0, _dragIndicator->pos(), true);
+ a->setAppletId(createUniqueId(a->appletType()));
+ addContainer(a, true);
+ Kicker::the()->setInsertionPoint(QPoint());
+ m_layout->updateFreeSpaceValues();
+ _dragMoveAC = 0;
+ _dragIndicator->hide();
+ m_layout->setStretchEnabled(true);
+ saveContainerConfig();
+ return;
+ }
+
+ // is it an applet info?
+ AppletInfo info;
+ if (AppletInfoDrag::decode(ev, info))
+ {
+ Kicker::the()->setInsertionPoint(_dragIndicator->pos());
+ _dragIndicator->hide();
+ m_layout->setStretchEnabled(true);
+
+ if (info.type() & AppletInfo::Button)
+ {
+ addButton(info);
+ }
+ else if (info.type() == AppletInfo::Applet)
+ {
+ addApplet(info);
+ }
+
+ Kicker::the()->setInsertionPoint(QPoint());
+ return;
+ }
+
+ // ok, let's try a KURL drag
+ KURL::List uriList;
+ if (!KURLDrag::decode(ev, uriList))
+ {
+ _dragMoveAC = 0;
+ _dragIndicator->hide();
+ m_layout->setStretchEnabled(true);
+ return;
+ }
+
+ Kicker::the()->setInsertionPoint(_dragIndicator->pos());
+
+ KURL::List::ConstIterator it(uriList.begin());
+ for (; it != uriList.end(); ++it)
+ {
+ const KURL &url = *it;
+
+ // Create a new PanelButton for this URL.
+
+ // see if it's a executable or directory
+ if (url.protocol() == "programs")
+ {
+ QString relPath = url.path();
+ if (relPath[0] == '/')
+ {
+ relPath = relPath.right(relPath.length() - 1);
+ }
+ a = new ServiceMenuButtonContainer(relPath, m_opMenu, m_contents);
+ }
+ else if (url.isLocalFile())
+ {
+ QFileInfo fi(url.path());
+ if (fi.isDir())
+ { // directory
+ switch (PanelDirDropMenu().exec(mapToGlobal(ev->pos())))
+ {
+ case PanelDirDropMenu::Browser:
+ a = new BrowserButtonContainer(url.path(), m_opMenu,
+ KMimeType::iconForURL(url), m_contents);
+ break;
+ case PanelDirDropMenu::Url:
+ a = new URLButtonContainer(url.url(), m_opMenu, m_contents);
+ break;
+ default: ;
+ }
+ }
+ else if ( KMimeType::findByURL(url)->name() == "application/x-desktop" )
+ {
+ // a local desktop file being dragged from an external program.
+ // Make a copy first.
+ KDesktopFile df(url.path());
+ KURL newUrl;
+ newUrl.setPath(KickerLib::copyDesktopFile(url));
+ if (df.readType() == "Link")
+ a = new URLButtonContainer(newUrl.url(), m_opMenu, m_contents);
+ else
+ a = new ServiceButtonContainer(newUrl.path(), m_opMenu, m_contents);
+ }
+ else if (fi.isExecutable())
+ {
+ // non-KDE executable
+ QString pixmapFile;
+ KMimeType::pixmapForURL(url, 0, KIcon::Panel, 0,
+ KIcon::DefaultState, &pixmapFile);
+ PanelExeDialog dlg(QString::null, QString::null, url.path(),
+ pixmapFile, QString::null, false, 0);
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ // KIconloader returns a full path, we only want the name
+ QFileInfo iconfi(dlg.iconPath());
+ a = new NonKDEAppButtonContainer(dlg.title(),
+ dlg.description(),
+ dlg.command(),
+ iconfi.fileName(),
+ dlg.commandLine(),
+ dlg.useTerminal(),
+ m_opMenu,
+ m_contents);
+ }
+ }
+ else // some unknown local file
+ {
+ a = new URLButtonContainer(url.url(), m_opMenu, m_contents);
+ }
+ }
+ else // a internet URL
+ {
+ a = new URLButtonContainer(url.url(), m_opMenu, m_contents);
+ }
+
+ if (!a)
+ {
+ _dragIndicator->hide();
+ Kicker::the()->setInsertionPoint(QPoint());
+ m_layout->setStretchEnabled(true);
+ return;
+ }
+
+ addContainer(a, true);
+ m_layout->updateFreeSpaceValues();
+ }
+
+ saveContainerConfig();
+ _dragMoveAC = 0;
+ _dragIndicator->hide();
+ Kicker::the()->setInsertionPoint(QPoint());
+ m_layout->setStretchEnabled(true);
+}
+
+bool ContainerArea::eventFilter(QObject* o, QEvent* e)
+{
+ // Propagate the layout hints which m_contents receives. This way widgets
+ // which contain a ContainerArea can react to layout changes of its
+ // contents. For example: If an applets grows, the top level widget may
+ // want to grow as well.
+ if (o == m_contents)
+ {
+ if (e->type() == QEvent::LayoutHint)
+ {
+ updateGeometry(); // Posts a new layout hint to our parent.
+ }
+ return false;
+ }
+
+ return Panner::eventFilter(o, e);
+}
+
+void ContainerArea::resizeEvent(QResizeEvent *ev)
+{
+ Panner::resizeEvent(ev);
+ setBackground();
+}
+
+void ContainerArea::viewportResizeEvent(QResizeEvent* ev)
+{
+ Panner::viewportResizeEvent(ev);
+ if (orientation() == Horizontal)
+ {
+ m_contents->resize(kMax(widthForHeight(ev->size().height()),
+ ev->size().width()),
+ ev->size().height());
+ }
+ else
+ {
+ m_contents->resize(ev->size().width(),
+ kMax(heightForWidth(ev->size().width()),
+ ev->size().height()));
+ }
+ resizeContents(m_contents->width(), m_contents->height());
+}
+
+void ContainerArea::setBackground()
+{
+ _bgSet = false;
+ m_cachedGeometry.clear();
+
+ if (KickerSettings::transparent() &&
+ (KickerSettings::menubarPanelTransparent() ||
+ !ExtensionManager::the()->isMenuBar(topLevelWidget())))
+ {
+ if (!_rootPixmap)
+ {
+ _rootPixmap = new KRootPixmap(this);
+ _rootPixmap->setCustomPainting(true);
+ connect(_rootPixmap, SIGNAL(backgroundUpdated(const QPixmap&)),
+ SLOT(updateBackground(const QPixmap&)));
+ }
+ else
+ {
+ _rootPixmap->repaint(true);
+ }
+
+ double tint = double(KickerSettings::tintValue()) / 100;
+ _rootPixmap->setFadeEffect(tint, KickerSettings::tintColor());
+ _rootPixmap->start();
+ _bgSet = true;
+ return;
+ }
+ else if (_rootPixmap)
+ {
+ delete _rootPixmap;
+ _rootPixmap = 0;
+ }
+
+ unsetPalette();
+
+ if (KickerSettings::useBackgroundTheme())
+ {
+ // by keeping the src image static, we can share it among panels and only
+ // reload from disk when it actually changes in the config, not every time we
+ // get a resize or configure event
+ static QString bgStr;
+ static QImage srcImage;
+ QString newBgStr = locate("appdata", KickerSettings::backgroundTheme());
+
+ if (bgStr != newBgStr)
+ {
+ bgStr = newBgStr;
+ srcImage.load(bgStr);
+ }
+
+ if (srcImage.isNull())
+ {
+ KickerSettings::setUseBackgroundTheme(false);
+ }
+ else
+ {
+ QImage bgImage = srcImage;
+
+ if (orientation() == Vertical)
+ {
+ if (KickerSettings::rotateBackground())
+ {
+ QWMatrix matrix;
+ matrix.rotate(position() == KPanelExtension::Left ? 90: 270);
+ bgImage = bgImage.xForm(matrix);
+ }
+
+ bgImage = bgImage.scaleWidth( size().width() );
+ }
+ else
+ {
+ if (position() == KPanelExtension::Top &&
+ KickerSettings::rotateBackground())
+ {
+ QWMatrix matrix;
+ matrix.rotate(180);
+ bgImage = bgImage.xForm(matrix);
+ }
+
+ bgImage = bgImage.scaleHeight( size().height() );
+ }
+
+ if (KickerSettings::colorizeBackground())
+ {
+ KickerLib::colorize(bgImage);
+ }
+ setPaletteBackgroundPixmap(QPixmap(bgImage));
+ QTimer::singleShot(0, this, SLOT(updateContainersBackground()));
+ }
+ }
+
+ _bgSet = true;
+}
+
+void ContainerArea::immutabilityChanged(bool immutable)
+{
+ // we set all the child container's immutability here instead of connecting
+ // the immutabilityChanged signal up everywhere so that we can control the
+ // order of immutability changing and the background being updated. since
+ // immutability implies applet handle visibility, those things must happen
+ // first before updating our background.
+ for (BaseContainer::ConstIterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ (*it)->setImmutable(immutable);
+ }
+
+ setAcceptDrops(!isImmutable());
+ QTimer::singleShot(0, this, SLOT(setBackground()));
+}
+
+QRect ContainerArea::availableSpaceFollowing(BaseContainer* a)
+{
+ QRect availableSpace = rect();
+ BaseContainer* b = 0;
+
+ if (a)
+ {
+ BaseContainer::Iterator it = m_containers.find(a);
+ if (it != m_containers.end() &&
+ ++it != m_containers.end())
+ {
+ b = (*it);
+ }
+ }
+
+ if (!b)
+ {
+ BaseContainer::Iterator it = m_containers.begin();
+ if (it != m_containers.end())
+ {
+ b = (*it);
+ }
+ }
+
+ if (orientation() == Horizontal)
+ {
+ if (a)
+ {
+ availableSpace.setLeft(a->x() + a->width());
+ }
+
+ if (b)
+ {
+ availableSpace.setRight(b->x() - 1);
+ }
+ }
+ else
+ {
+ if (a)
+ {
+ availableSpace.setTop(a->y() + a->height());
+ }
+
+ if (b)
+ {
+ availableSpace.setBottom(b->y() - 1);
+ }
+ }
+
+ return availableSpace;
+}
+
+void ContainerArea::moveDragIndicator(int pos)
+{
+ QRect availableSpace = availableSpaceFollowing(_dragMoveAC);
+
+ // Move _dragIndicator to position pos, restricted by availableSpace.
+ // Resize _dragIndicator if necessary.
+ if (orientation() == Horizontal)
+ {
+ if (availableSpace.size().width() <
+ _dragIndicator->preferredSize().width())
+ {
+ _dragIndicator->resize(availableSpace.size());
+ _dragIndicator->move(availableSpace.topLeft());
+ }
+ else
+ {
+ int newX = pos;
+ _dragIndicator->resize(_dragIndicator->preferredSize());
+ newX = QMAX(newX, availableSpace.left());
+ newX = QMIN(newX,
+ availableSpace.right() + 1 - _dragIndicator->width() );
+ _dragIndicator->move(newX, availableSpace.top());
+ }
+ }
+ else
+ {
+ if (availableSpace.size().height() <
+ _dragIndicator->preferredSize().height())
+ {
+ _dragIndicator->resize(availableSpace.size());
+ _dragIndicator->move(availableSpace.topLeft());
+ }
+ else
+ {
+ int newY = pos;
+ _dragIndicator->resize(_dragIndicator->preferredSize());
+ newY = QMAX(newY, availableSpace.top());
+ newY = QMIN(newY,
+ availableSpace.bottom() + 1 - _dragIndicator->height() );
+ _dragIndicator->move(availableSpace.left(), newY);
+ }
+ }
+}
+
+void ContainerArea::updateBackground( const QPixmap& pm )
+{
+ QBrush bgBrush(colorGroup().background(), pm);
+ QPalette pal = kapp->palette();
+ pal.setBrush(QColorGroup::Background, bgBrush);
+ setPalette(pal);
+
+ // because the Pixmap can be smaller as the containerarea
+ // we construct a pixmap the same size as we are that every
+ // applet or button can use to cut out its background
+ _completeBg.resize(width(), height());
+ _completeBg.fill(this, 0, 0);
+
+ m_cachedGeometry.clear();
+ updateContainersBackground();
+}
+
+void ContainerArea::resizeContents(int w, int h)
+{
+ // this looks silly but is required otherwise (some?) c++ compilers can't see
+ // Panner::resizeContents(int, int) due to the overloaded ContainerArea::resizeContents()
+ Panner::resizeContents(w, h);
+
+ if (!m_updateBackgroundsCalled)
+ {
+ m_updateBackgroundsCalled = true;
+ QTimer::singleShot(0, this, SLOT(updateContainersBackground()));
+ }
+}
+
+void ContainerArea::slotSaveContainerConfig()
+{
+ saveContainerConfig();
+}
+
+void ContainerArea::setPosition(KPanelExtension::Position p)
+{
+ if (_pos == p)
+ {
+ return;
+ }
+
+ _pos = p;
+ Qt::Orientation o = (p == KPanelExtension::Top ||
+ p == KPanelExtension::Bottom) ?
+ Qt::Horizontal : Qt::Vertical;
+ bool orientationChanged = (orientation() != o);
+ m_layout->setEnabled(false);
+
+ if (orientationChanged)
+ {
+ setOrientation(o);
+ m_layout->setOrientation(o);
+
+ // when we change orientation, we will resize the "width"
+ // component down to 0, forcing a resize in resizeContents()
+ // when that gets called AFTER we've been moved
+ // it's not always safe to do the resize here, as scroll buttons
+ // from the panner may get in our way. =/
+ if (o == Horizontal)
+ {
+ resizeContents(0, height());
+ }
+ else
+ {
+ resizeContents(width(), 0);
+ }
+ }
+
+ for (BaseContainer::ConstIterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ if (orientationChanged)
+ {
+ (*it)->setOrientation(o);
+ }
+
+ (*it)->setPopupDirection( popupDirection() );
+ }
+
+ m_layout->setEnabled(true);
+
+ setContentsPos(0, 0);
+ m_contents->move(0, 0);
+ setBackground();
+
+ // container extension repaints for us!
+ //repaint();
+}
+
+void ContainerArea::setAlignment(KPanelExtension::Alignment a)
+{
+ for (BaseContainer::ConstIterator it = m_containers.begin();
+ it != m_containers.end();
+ ++it)
+ {
+ (*it)->setAlignment(a);
+ }
+}
+
+void ContainerArea::autoScroll()
+{
+ if(!_moveAC) return;
+
+ if(orientation() == Horizontal) {
+ if(_moveAC->pos().x() <= 80)
+ scrollBy(-10, 0);
+ else if(_moveAC->pos().x() >= width() - _moveAC->width() - 80)
+ scrollBy(10, 0);
+ }
+ else {
+ if(_moveAC->pos().y() <= 80)
+ scrollBy(0, -10);
+ else if(_moveAC->pos().y() >= height() - _moveAC->height() - 80)
+ scrollBy(0, 10);
+ }
+}
+
+void ContainerArea::scrollTo(BaseContainer* b)
+{
+ if (!b)
+ {
+ return;
+ }
+
+ int x, y;
+ viewportToContents(b->pos().x(), b->pos().y(), x, y);
+ ensureVisible(x, y);
+}
+
+void ContainerArea::updateContainersBackground()
+{
+ m_updateBackgroundsCalled = false;
+
+ if (!_bgSet)
+ {
+ return;
+ }
+
+ for (BaseContainer::ConstIterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ // A rather ugly hack. The code calls updateContainersBackground() all over
+ // the place even when nothing in fact has changed. Updating the background
+ // on every single unrelated change however means that e.g. the systray
+ // flickers when a new window is opened/closed (because the taskbar is relayouted,
+ // which triggers updateContainersBackground() even though the geometry
+ // of the taskbar does not change in fact. I'm apparently unable to fix this
+ // properly, so just cache the geometry and update background only when
+ // the geometry changes or when the background really changes (in which
+ // case the cached is cleared).
+ if( !m_cachedGeometry.contains( *it ))
+ {
+ m_cachedGeometry[ *it ] = QRect();
+ connect( *it, SIGNAL( destroyed()), SLOT( destroyCachedGeometry()));
+ }
+ if( m_cachedGeometry[ *it ] != (*it)->geometry())
+ {
+ (*it)->setBackground();
+ m_cachedGeometry[ *it ] = (*it)->geometry();
+ }
+ }
+}
+
+void ContainerArea::destroyCachedGeometry()
+{
+ m_cachedGeometry.remove(const_cast<QWidget*>(static_cast<const QWidget*>(sender())));
+}
+
+BaseContainer::List ContainerArea::containers(const QString& type) const
+{
+ if (type.isEmpty() || type == "All")
+ {
+ return m_containers;
+ }
+
+ BaseContainer::List list;
+
+ if (type == "Special Button")
+ {
+ for (BaseContainer::ConstIterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ QString type = (*it)->appletType();
+ if (type == "KMenuButton" ||
+ type == "WindowListButton" ||
+ type == "BookmarksButton" ||
+ type == "DesktopButton" ||
+ type == "BrowserButton" ||
+ type == "ExecButton" ||
+ type == "ExtensionButton")
+ {
+ list.append(*it);
+ }
+ }
+
+ return list;
+ }
+
+ for (BaseContainer::ConstIterator it = m_containers.constBegin();
+ it != m_containers.constEnd();
+ ++it)
+ {
+ if ((*it)->appletType() == type)
+ {
+ list.append(*it);
+ }
+ }
+
+ return list;
+}
+
+int ContainerArea::containerCount(const QString& type) const
+{
+ if (type.isEmpty() || type == "All")
+ {
+ return m_containers.count();
+ }
+
+ int count = 0;
+ if (type == "Special Button")
+ {
+ for (BaseContainer::ConstIterator it = m_containers.begin();
+ it != m_containers.end();
+ ++it)
+ {
+ QString type = (*it)->appletType();
+ if (type == "KMenuButton" ||
+ type == "WindowListButton" ||
+ type == "BookmarksButton" ||
+ type == "DesktopButton" ||
+ type == "BrowserButton" ||
+ type == "ExecButton" ||
+ type == "ExtensionButton")
+ {
+ ++count;
+ }
+ }
+
+ return count;
+ }
+
+ for (BaseContainer::ConstIterator it = m_containers.begin();
+ it != m_containers.end();
+ ++it)
+ {
+ if ((*it)->appletType() == type)
+ {
+ ++count;
+ }
+ }
+
+ return count;
+}
+
+QStringList ContainerArea::listContainers() const
+{
+ return m_layout->listItems();
+}
+
+void ContainerArea::repaint()
+{
+ Panner::repaint();
+}
+
+void ContainerArea::showAddAppletDialog()
+{
+ if (!m_addAppletDialog)
+ {
+ m_addAppletDialog = new AddAppletDialog(this, this, 0);
+ connect(m_addAppletDialog, SIGNAL(finished()), this, SLOT(addAppletDialogDone()));
+ }
+ else
+ {
+ // this ensures that if we get shown again via the menu
+ // that the dialog picks up
+ // the new place to insert things
+ m_addAppletDialog->updateInsertionPoint();
+ }
+
+ KWin::setOnDesktop(m_addAppletDialog->winId(), KWin::currentDesktop());
+ m_addAppletDialog->show();
+ m_addAppletDialog->raise();
+}
+
+void ContainerArea::addAppletDialogDone()
+{
+ m_addAppletDialog->deleteLater();
+ m_addAppletDialog = 0;
+}
+
+const QPixmap* ContainerArea::completeBackgroundPixmap() const
+{
+ return &_completeBg;
+}
+
+int ContainerArea::widthForHeight(int h) const
+{
+ return m_layout->widthForHeight(h);
+}
+
+int ContainerArea::heightForWidth(int w) const
+{
+ return m_layout->heightForWidth(w);
+}
+
+
+DragIndicator::DragIndicator(QWidget* parent, const char* name)
+ : QWidget(parent, name)
+{
+ setBackgroundOrigin(AncestorOrigin);
+}
+
+
+void DragIndicator::paintEvent(QPaintEvent*)
+{
+ QPainter painter(this);
+ QRect rect(0, 0, width(), height());
+ style().drawPrimitive( QStyle::PE_FocusRect, &painter, rect, colorGroup(),
+ QStyle::Style_Default, colorGroup().base() );
+}
+
+void DragIndicator::mousePressEvent(QMouseEvent*)
+{
+ hide();
+}
+
+#include "containerarea.moc"