/* * Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic * * 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 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 "LancelotWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define sectionsWidth \ (m_mainConfig.readEntry("collapseSections", false) ? 64 : 128) #define windowHeightDefault 500 #define mainWidthDefault 422 #define HIDE_TIMER_INTERVAL 1500 #define SEARCH_TIMER_INTERVAL 300 LancelotWindow::LancelotWindow() : m_root(NULL), m_corona(NULL), m_hovered(false), m_showingFull(true), m_sectionsSignalMapper(NULL), m_config("lancelotrc"), m_mainConfig(&m_config, "Main"), m_configWidget(NULL), m_resizeDirection(None), m_mainSize(mainWidthDefault, windowHeightDefault), m_skipEvent(false), menuSystemButton(NULL), menuLancelotContext(NULL), m_cachedOpenPosition(-1, -1), m_cachedWindowSize(-1, -1), m_cachedFlip(0), m_cachedOpenPositionCentered(false), m_cachedShowingFull(false), m_firstOpen(true) { setFocusPolicy(Qt::WheelFocus); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);// | Qt::Popup); setFrameStyle(QFrame::NoFrame); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::KeepAbove | NET::Sticky); connect(& m_hideTimer, SIGNAL(timeout()), this, SLOT(hideImmediate())); m_hideTimer.setInterval(HIDE_TIMER_INTERVAL); m_hideTimer.setSingleShot(true); m_corona = new Plasma::Corona(this); setMinimumSize(400, 300); setScene(m_corona); m_root = new Lancelot::ResizeBordersPanel(); installEventFilter(this); m_root->setGroupByName("RootPanel"); m_corona->addItem(m_root); setupUi(m_root); m_root->setLayoutItem(layoutMain); setupModels(); /* TODO: Convert this to PUCK generated code */ editSearch = new Plasma::LineEdit(); editSearch->setParentItem(m_root); editSearch->nativeWidget()->setClearButtonShown(true); editSearch->nativeWidget()->setClickMessage(i18nc("Enter the text to search for", "Search...")); editSearch->nativeWidget()->setContextMenuPolicy(Qt::NoContextMenu); editSearch->show(); layoutSearch->addItem(editSearch, Lancelot::NodeLayout::NodeCoordinate(0.0, 0.5, 0, 0), Lancelot::NodeLayout::NodeCoordinate(1.0, 0.5, 0, QREAL_INFINITY) ); editSearch->nativeWidget()->installEventFilter(this); editSearch->setFocusPolicy(Qt::WheelFocus); editSearch->nativeWidget()->setFocusPolicy(Qt::WheelFocus); m_completion = new KCompletion(); editSearch->nativeWidget()->setCompletionObject(m_completion); editSearch->nativeWidget()->setCompletionMode( KGlobalSettings::CompletionMan); m_completion->insertItems(m_configUi.searchHistory()); passagewayApplications->setEntranceTitle(i18n("Favorites")); passagewayApplications->setEntranceIcon(KIcon("favorites")); passagewayApplications->setAtlasTitle(i18n("Applications")); passagewayApplications->setAtlasIcon(KIcon("applications-other")); tabbarSections->installEventFilter(this); tabbarSections->setTabsGroupName("SectionButtons"); tabbarSections->addTab("documents", KIcon("applications-office"), i18n("&Documents"), "text/x-lancelotpart", "model=NewDocuments&type=list&version=1.0\nmodel=OpenDocuments&type=list&version=1.0\nmodel=RecentDocuments&type=list&version=1.0"); tabbarSections->addTab("contacts", KIcon("kontact"), i18n("&Contacts"), "text/x-lancelotpart", "model=Messages&type=list&version=1.0\nmodel=Contacts&type=list&version=1.0"); tabbarSections->addTab("computer", KIcon("computer-laptop"), i18n("Co&mputer"), "text/x-lancelotpart", "model=Places&type=list&version=1.0\nmodel=System&type=list&version=1.0\nmodel=Devices%2FRemovable&type=list&version=1.0\nmodel=Devices%2FFixed&type=list&version=1.0"); tabbarSections->addTab("applications", KIcon("applications-other"), i18n("&Applications"), "text/x-lancelotpart", "model=FavoriteApplications&type=list&version=1.0\nmodel=Folder%20applications%3A%2F&type=list&version=1.0"); tabbarSections->setOrientation(Qt::Vertical); tabbarSections->setTextDirection(Qt::Vertical); /* End TODO */ connect(tabbarSections, SIGNAL(currentTabChanged(QString)), layoutCenter, SLOT(showCard(QString))); m_sectionsSignalMapper = new QSignalMapper(this); connect (m_sectionsSignalMapper, SIGNAL(mapped(QString)), this, SLOT(sectionActivated(QString)) ); connect(buttonSystem1, SIGNAL(activated()), this, SLOT(systemButtonClicked())); connect(buttonSystem2, SIGNAL(activated()), this, SLOT(systemButtonClicked())); connect(buttonSystem3, SIGNAL(activated()), this, SLOT(systemButtonClicked())); connect(buttonLancelotContext, SIGNAL(activated()), this, SLOT(lancelotContext())); connect(editSearch->widget(), SIGNAL(textChanged(QString)), this, SLOT(search(QString)) ); loadConfig(); setupActions(); connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(focusChanged(QWidget*,QWidget*))); setStyleSheet("LancelotWindow { background: black }"); } void LancelotWindow::drawBackground(QPainter * painter, const QRectF & rect) { painter->setCompositionMode(QPainter::CompositionMode_Clear); painter->fillRect( QRectF(rect.x() - 2, rect.y() - 2, rect.width() + 2, rect.height() + 2).toRect(), Qt::transparent); painter->setCompositionMode(QPainter::CompositionMode_Source); } void LancelotWindow::focusChanged(QWidget * old, QWidget * now) { Q_UNUSED(old); // We have to return the focus to the QGraphicsView // since it handles the keyboard, the universe // and everything if (now == this) { editSearch->nativeWidget()->setFocus(); editSearch->setFocus(); } } void LancelotWindow::toggleCollapsedSections() { updateCollapsedSections(true); } void LancelotWindow::updateCollapsedSections(bool toggle) { bool collapseSections = m_mainConfig.readEntry("collapseSections", false); if (toggle) { collapseSections = !collapseSections; m_mainConfig.writeEntry("collapseSections", collapseSections); m_mainConfig.sync(); } layoutMain->setSize((m_showingFull ? sectionsWidth : 0), Lancelot::FullBorderLayout::LeftBorder); if (collapseSections) { tabbarSections->setTabIconSize(QSize(32, 32)); tabbarSections->setTextDirection(Qt::Horizontal); } else { tabbarSections->setTabIconSize(QSize(48, 48)); tabbarSections->setTextDirection(Qt::Vertical); } updateWindowSize(); } LancelotWindow::~LancelotWindow() { m_configUi.setSearchHistory(m_completion->items()); delete m_configWidget; } void LancelotWindow::lancelotShow(int x, int y) { m_showingFull = true; showWindow(x, y); } void LancelotWindow::lancelotToggleCentered() { if (isVisible()) { hide(); } else lancelotShowCentered(); } void LancelotWindow::lancelotShowCentered() { m_showingFull = true; showWindow(0, 0, true); } void LancelotWindow::lancelotShowItem(int x, int y, const QString & name) { sectionActivated(name); m_showingFull = false; showWindow(x, y); } void LancelotWindow::lancelotHide(bool immediate) { if (immediate) { QTimer::singleShot(100, editSearch->nativeWidget(), SLOT(clear())); // editSearch->setText(QString()); if (m_configUi.appbrowserReset()) { passagewayApplications->reset(); } hide(); return; } if (m_hovered) return; m_hideTimer.start(); } void LancelotWindow::showWindow(int x, int y, bool centered) { kDebug() << "=== showing the window"; if (m_firstOpen || m_cachedShowingFull == m_showingFull) { m_cachedShowingFull = m_showingFull; kDebug() << "cache for m_showingFull not used"; tabbarSections->setVisible(m_showingFull); layoutMain->setSize((m_showingFull ? sectionsWidth : 0), Lancelot::FullBorderLayout::LeftBorder); // in this case, we should really update everything... m_firstOpen = true; } updateCollapsedSections(); m_resizeDirection = None; m_hideTimer.stop(); if (isVisible()) { // We are exiting because we do not want to move already opened window // because most probably it is just invoked from the same applet and // needs to show only another category updateWindowSize(); return; } if (centered) { x = QCursor::pos().x(); y = QCursor::pos().y(); } QRect screenRect = QApplication::desktop()->screenGeometry(QPoint(x, y)); updateWindowSize(); if (m_firstOpen || (m_cachedOpenPosition != QPoint(x, y) || m_cachedOpenPositionCentered != centered)) { kDebug() << "cache for position not used"; m_cachedOpenPosition = QPoint(x, y); m_cachedOpenPositionCentered = centered; Plasma::Flip flip; if (!centered) { flip = Plasma::VerticalFlip; if (x < screenRect.left()) { x = screenRect.left(); } if (y < screenRect.top()) { y = screenRect.top(); } if (x + width() > screenRect.right()) { x = x - width(); flip |= Plasma::HorizontalFlip; } if (y + height() > screenRect.bottom()) { y = y - height(); flip &= ~Plasma::VerticalFlip; } if (m_showingFull) { if (flip & Plasma::HorizontalFlip) { x += sectionsWidth / 2; } else { x -= sectionsWidth / 2; } } } else { flip = Plasma::NoFlip; x = screenRect.left() + (screenRect.width() - width()) / 2; y = screenRect.top() + (screenRect.height() - height()) / 2; } move(x, y); if (m_firstOpen || m_cachedFlip != flip) { kDebug() << "cache for flip not used"; m_cachedFlip = flip; kDebug() << "Flip:" << flip; layoutMain->setFlip(flip); tabbarSections->setFlip(flip); if (m_configUi.activationMethod() == LancelotConfig::NoClick) { Lancelot::Global::self()->group("SystemButtons")->setProperty("extenderPosition", QVariant( (flip & Plasma::VerticalFlip)?(Lancelot::TopExtender):(Lancelot::BottomExtender) )); Lancelot::Global::self()->group("SystemButtons") ->setProperty("activationMethod", Lancelot::ExtenderActivate); } else { Lancelot::Global::self()->group("SystemButtons") ->setProperty("extenderPosition", QVariant(Lancelot::NoExtender)); Lancelot::Global::self()->group("SystemButtons") ->setProperty("activationMethod", Lancelot::ClickActivate); } Lancelot::Global::self()->group("LancelotContext")->setProperty("extenderPosition", Lancelot::Global::self()->group("SystemButtons")->property("extenderPosition")); Lancelot::Global::self()->group("LancelotContext")->setProperty("activationMethod", Lancelot::Global::self()->group("SystemButtons")->property("activationMethod")); Lancelot::Global::self()->group("SystemButtons")->notifyUpdated(); Lancelot::Global::self()->group("LancelotContext")->notifyUpdated(); } } if (m_showingFull) { sectionActivated("applications"); } if (KWindowSystem::compositingActive()) { if (m_cachedFlip & Plasma::VerticalFlip) { Plasma::WindowEffects::slideWindow(this, Plasma::TopEdge); } else { Plasma::WindowEffects::slideWindow(this, Plasma::BottomEdge); } } show(); KWindowSystem::setState( winId(), NET::SkipTaskbar | NET::SkipPager | NET::KeepAbove ); KWindowSystem::forceActiveWindow(winId()); //editSearch->clearFocus(); editSearch->nativeWidget()->setFocus(); editSearch->setFocus(); m_firstOpen = false; } bool LancelotWindow::updateWindowSize() { QSize newSize = m_mainSize; if (m_showingFull) { newSize.rwidth() += sectionsWidth; } if (!m_firstOpen && newSize == m_cachedWindowSize) { return false; } kDebug() << "cache for size not used" << newSize << m_cachedWindowSize; m_cachedWindowSize = newSize; resize(newSize); m_corona-> setSceneRect(QRectF(QPointF(), newSize)); m_root-> setGeometry(QRect(QPoint(), newSize)); resize(newSize); m_root->group()->backgroundSvg()->resizeFrame(newSize); const QRegion & mask = m_root->group()->backgroundSvg()->mask(); // setMask(mask); Plasma::WindowEffects::enableBlurBehind(winId(), true, mask); Plasma::WindowEffects::overrideShadow(winId(), true); return true; } QStringList LancelotWindow::sectionIDs() { QStringList res; res << "applications" << "computer" << "contacts" << "documents"; return res; } QStringList LancelotWindow::sectionNames() { QStringList res; res << i18n("Applications") << i18n("Computer") << i18n("Contacts") << i18n("Documents"); return res; } QStringList LancelotWindow::sectionIcons() { QStringList res; res << "kde" << "computer-laptop" << "kontact" << "applications-office"; // res << "applications-other" << "computer-laptop" << "kontact" << "applications-office"; return res; } QString LancelotWindow::currentSection() { if (isHidden()) { return QString(); } return tabbarSections->currentTab(); } void LancelotWindow::sectionActivated(const QString & item) { kDebug() << item; tabbarSections->setCurrentTab(item); // TODO: m_activeSection should be examined // - since we have a tabbarSections, it is not really // used and it is not representing the active section if (item == m_activeSection) { return; } m_activeSection = item; if (m_focusIndex >= 0 && m_focusIndex < m_focusList.count()) { if (m_focusList.at(m_focusIndex) != passagewayApplications) { ((Lancelot::ActionListView *) m_focusList.at(m_focusIndex))->clearSelection(); } else { ((Lancelot::PassagewayView *) m_focusList.at(m_focusIndex))->clearSelection(); } } m_focusList.clear(); m_focusIndex = 0; if (item == "search") { m_focusList << listSearchLeft; } else if (item == "applications") { m_focusList << passagewayApplications; } else if (item == "computer") { m_focusList << listComputerLeft; m_focusList << listComputerRight; } else if (item == "contacts") { m_focusList << listContactsLeft; m_focusList << listContactsRight; } else if (item == "documents") { m_focusList << listDocumentsLeft; m_focusList << listDocumentsRight; } layoutCenter->showCard(item); } void LancelotWindow::search(const QString & string) { if (editSearch->text() != string) { editSearch->setText(string); } m_searchString = string; ((Lancelot::Models::Runner *) m_models["Runner"])->setSearchString(m_searchString); if (m_searchString.isEmpty()) { sectionActivated("applications"); } else { sectionActivated("search"); } } void LancelotWindow::systemButtonClicked() { Lancelot::ExtenderButton * button = static_cast < Lancelot::ExtenderButton * > (sender()); Lancelot::ActionTreeModel * model = Lancelot::Models::SystemActions::self()->action(systemButtonActions[button]); if (!model) return; if (!menuSystemButton) { menuSystemButton = new Lancelot::PopupList(); menuSystemButton->resize(200, 200); Lancelot::Models::ApplicationConnector * ac = Lancelot::Models::ApplicationConnector::self(); connect( ac, SIGNAL(doHide(bool)), menuSystemButton, SLOT(close()) ); } menuSystemButton->setModel(model); menuSystemButton->updateSize(); QRect g = button->geometry().toRect(); g.moveTopLeft(g.topLeft() + geometry().topLeft()); if (layoutMain->flip() & Plasma::VerticalFlip) { menuSystemButton->move(g.bottomLeft()); } else { menuSystemButton->move(g.topLeft() - QPoint(0, menuSystemButton->geometry().height())); } menuSystemButton->exec(menuSystemButton->pos()); } void LancelotWindow::setupModels() { // Models: m_models["Places"] = new Lancelot::Models::Places(); m_models["SystemServices"] = new Lancelot::Models::SystemServices(); m_models["Devices/Removable"] = new Lancelot::Models::Devices(Lancelot::Models::Devices::Removable); m_models["Devices/Fixed"] = new Lancelot::Models::Devices(Lancelot::Models::Devices::Fixed); m_models["NewDocuments"] = new Lancelot::Models::NewDocuments(); m_models["RecentDocuments"] = new Lancelot::Models::RecentDocuments(); m_models["OpenDocuments"] = new Lancelot::Models::OpenDocuments(); m_models["Runner"] = new Lancelot::Models::Runner(); //allowedRunners); // Groups: m_modelGroups["ComputerLeft"] = new Lancelot::Models::BaseMergedModel(); m_modelGroups["DocumentsLeft"] = new Lancelot::Models::BaseMergedModel(); m_modelGroups["ContactsLeft"] = new Lancelot::Models::BaseMergedModel(); m_modelGroups["ComputerRight"] = new Lancelot::Models::BaseMergedModel(); m_modelGroups["DocumentsRight"] = new Lancelot::Models::BaseMergedModel(); m_modelGroups["ContactsRight"] = new Lancelot::Models::BaseMergedModel(); // Assignments: Model - Group: #define MergedAddModel(MergedModel, ModelID, Model, Title) \ ((Lancelot::Models::BaseMergedModel *)(MergedModel)) \ ->addModel((ModelID), QIcon(), Title, Model); MergedAddModel(m_modelGroups["ComputerLeft"], "Places", m_models["Places"], i18n("Places")); MergedAddModel(m_modelGroups["ComputerLeft"], "System", m_models["SystemServices"], i18n("System")); MergedAddModel(m_modelGroups["ComputerRight"], "Devices/Removable", m_models["Devices/Removable"], i18nc("@title Removable devices", "Removable")); MergedAddModel(m_modelGroups["ComputerRight"], "Devices/Fixed", m_models["Devices/Fixed"], i18nc("@title Fixed devices", "Fixed")); MergedAddModel(m_modelGroups["DocumentsLeft"], "NewDocuments", m_models["NewDocuments"], i18nc("@title New documents", "New")); MergedAddModel(m_modelGroups["DocumentsRight"], "OpenDocuments", m_models["OpenDocuments"], i18nc("@title List of open documents", "Open")); MergedAddModel(m_modelGroups["DocumentsRight"], "RecentDocuments", m_models["RecentDocuments"], i18nc("@title Recent documents", "Recent")); QString plugins; // Contacts Mail plugins = m_mainConfig.readEntry("mailPlugins", QString()); if (plugins.isEmpty()) { m_models["Messages"] = new Lancelot::Models::MessagesKmail(); MergedAddModel(m_modelGroups["ContactsLeft"], "Messages", m_models["Messages"], i18n("Unread messages")); } else if (plugins != "disabled") { Lancelot::ActionListModel * model; foreach (const QString &plugin, plugins.split(',')) { model = new Lancelot::PlasmaServiceListModel(plugin); MergedAddModel(m_modelGroups["ContactsLeft"], model->selfTitle(), model, i18n("Unread messages")); } } // Contacts IM plugins = m_mainConfig.readEntry("imPlugins", QString()); if (plugins.isEmpty()) { m_models["Contacts"] = new Lancelot::Models::ContactsKopete(); MergedAddModel(m_modelGroups["ContactsRight"], "Contacts", m_models["Contacts"], i18n("Online contacts")); } else if (plugins != "disabled") { Lancelot::ActionListModel * model; foreach (const QString &plugin, plugins.split(',')) { model = new Lancelot::PlasmaServiceListModel(plugin); MergedAddModel(m_modelGroups["ContactsRight"], model->selfTitle(), model, i18n("Online contacts")); } } m_modelGroups["SearchLeft"] = m_models["Runner"]; // Assignments: ListView - Group listComputerLeft->setModel(m_modelGroups["ComputerLeft"]); listDocumentsLeft->setModel(m_modelGroups["DocumentsLeft"]); listContactsLeft->setModel(m_modelGroups["ContactsLeft"]); listSearchLeft->setModel(m_modelGroups["SearchLeft"]); listComputerRight->setModel(m_modelGroups["ComputerRight"]); listDocumentsRight->setModel(m_modelGroups["DocumentsRight"]); listContactsRight->setModel(m_modelGroups["ContactsRight"]); //listSearchRight->setModel(m_modelGroups["SearchRight"]); // Applications passageview passagewayApplications->setEntranceModel( new Lancelot::Models::FavoriteApplications::PassagewayViewProxy() ); passagewayApplications->setAtlasModel(new Lancelot::Models::Applications()); #undef MergedAddModel } // Resizing: void LancelotWindow::mousePressEvent(QMouseEvent * e) { m_resizeDirection = None; if (e->x() >= width() - m_root->borderSize(Plasma::RightMargin)) m_resizeDirection |= Right; else if (e->x() <= m_root->borderSize(Plasma::LeftMargin)) m_resizeDirection |= Left; if (e->y() >= height() - m_root->borderSize(Plasma::BottomMargin)) m_resizeDirection |= Down; else if (e->y() <= m_root->borderSize(Plasma::TopMargin)) m_resizeDirection |= Up; if (m_resizeDirection != None) { m_originalMousePosition = e->globalPos(); m_originalWindowPosition = pos(); m_originalMainSize = m_mainSize; } QGraphicsView::mousePressEvent(e); } void LancelotWindow::mouseReleaseEvent(QMouseEvent * e) { if (m_resizeDirection != None) { m_mainConfig.writeEntry("width", m_mainSize.width()); m_mainConfig.writeEntry("height", m_mainSize.height()); m_mainConfig.sync(); m_resizeDirection = None; } QGraphicsView::mouseReleaseEvent(e); } void LancelotWindow::mouseMoveEvent(QMouseEvent * e) { if (m_resizeDirection != None) { m_mainSize = m_originalMainSize; QPoint newWindowPosition = m_originalWindowPosition; QPoint diff = e->globalPos() - m_originalMousePosition; if (m_resizeDirection & Right) { m_mainSize.rwidth() += diff.x(); } else if (m_resizeDirection & Left) { m_mainSize.rwidth() -= diff.x(); newWindowPosition.rx() += diff.x(); } if (m_resizeDirection & Down) { m_mainSize.rheight() += diff.y(); } else if (m_resizeDirection & Up) { m_mainSize.rheight() -= diff.y(); newWindowPosition.ry() += diff.y(); } QSize newSize = m_mainSize; if (m_showingFull) { newSize.rwidth() += sectionsWidth; } newSize = newSize.expandedTo(minimumSize()); setGeometry(QRect(newWindowPosition, newSize)); const QRegion & mask = m_root->group()->backgroundSvg()->mask(); // setMask(mask); Plasma::WindowEffects::enableBlurBehind(winId(), true, mask); Plasma::WindowEffects::overrideShadow(winId(), true); } QGraphicsView::mouseMoveEvent(e); } void LancelotWindow::sendKeyEvent(QKeyEvent * event) { // We get this twice for every keypress... ??? m_skipEvent = !m_skipEvent; if (!m_skipEvent) { return; } if (passagewayApplications == m_focusList.at(m_focusIndex)) { ((Lancelot::PassagewayView *) m_focusList.at(m_focusIndex))->keyPressEvent(event); } else { ((Lancelot::ActionListView *) m_focusList.at(m_focusIndex))->keyPressEvent(event); } } bool LancelotWindow::eventFilter(QObject * object, QEvent * event) { // Right-click the tabbarSections if (event->type() == QEvent::GraphicsSceneMousePress && object == tabbarSections) { QGraphicsSceneMouseEvent * mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { Lancelot::PopupMenu * menu = new Lancelot::PopupMenu(this); QString text; if (m_mainConfig.readEntry("collapseSections", false)) { text = i18n("Make buttons wider"); } else { text = i18n("Make buttons narrower"); } connect( menu->addAction(KIcon(), text), SIGNAL(triggered(bool)), this, SLOT(toggleCollapsedSections()) ); menu->exec(QCursor::pos()); } } // Catching key presses because no item has explicit // focus if (event->type() == QEvent::KeyPress) { bool pass = false; int oindex = m_focusIndex; QKeyEvent * keyEvent = static_cast(event); switch (keyEvent->key()) { case Qt::Key_Escape: lancelotHide(true); break; case Qt::Key_Tab: { QKeyEvent * endKeyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_End, Qt::NoModifier); QCoreApplication::sendEvent(editSearch->nativeWidget(), endKeyEvent); endKeyEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_End, Qt::NoModifier); QCoreApplication::sendEvent(editSearch->nativeWidget(), endKeyEvent); return true; } case Qt::Key_Return: case Qt::Key_Enter: if (m_activeSection == "search") { if (listSearchLeft->selectedIndex() == -1) { listSearchLeft->initialSelection(); } if (!editSearch->text().isEmpty()) { m_completion->addItem(editSearch->text()); m_configUi.setSearchHistory(m_completion->items()); } } sendKeyEvent(keyEvent); break; case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_Menu: sendKeyEvent(keyEvent); break; case Qt::Key_Left: m_focusIndex--; break; case Qt::Key_Right: m_focusIndex++; break; case Qt::Key_PageUp: nextSection(-1); return true; case Qt::Key_PageDown: nextSection(1); return true; default: pass = true; } if (m_focusIndex < 0) { m_focusIndex = 0; pass = true; } else if (m_focusIndex >= m_focusList.size()) { m_focusIndex = m_focusList.size() - 1; pass = true; } if (oindex != m_focusIndex) { if (m_focusList.at(oindex) != passagewayApplications) { ((Lancelot::ActionListView *) m_focusList.at(oindex))->clearSelection(); } if (m_focusList.at(m_focusIndex) != passagewayApplications) { ((Lancelot::ActionListView *) m_focusList.at(m_focusIndex))->initialSelection(); } } if (pass) { sendKeyEvent(keyEvent); } editSearch->nativeWidget()->setFocus(); editSearch->setFocus(); } return QWidget::eventFilter(object, event); } void LancelotWindow::setupActions() { m_actionCollection = new KActionCollection(this); KAction * a = 0; if (KAuthorized::authorizeKAction("show_lancelot")) { a = m_actionCollection->addAction(i18n("Lancelot"), this); a->setText(i18n("Open Lancelot menu")); a->setGlobalShortcut(KShortcut(Qt::ALT + Qt::Key_F5)); a->setIcon(KIcon("lancelot")); connect( a, SIGNAL(triggered(bool)), this, SLOT(lancelotToggleCentered()) ); } QStringList sIDs = sectionIDs(); QStringList sNames = sectionNames(); QStringList sIcons = sectionIcons(); for (int i = 0; i < sIDs.size(); i++) { a = m_actionCollection->addAction(sIDs.at(i), this); a->setText(sNames.at(i)); a->setIcon(KIcon(sIcons.at(i))); a->setShortcut(Qt::ALT + Qt::Key_1 + i); connect( a, SIGNAL(triggered(bool)), m_sectionsSignalMapper, SLOT(map()) ); m_sectionsSignalMapper->setMapping(a, sIDs.at(i)); } m_actionCollection->readSettings(); m_actionCollection->associateWidget(this); } void LancelotWindow::configureShortcuts() { lancelotHide(true); KShortcutsDialog::configure(m_actionCollection); } void LancelotWindow::configurationChanged() { loadConfig(); } void LancelotWindow::nextSection(int increment) { kDebug() << increment; if (! (layoutMain->flip() & Plasma::VerticalFlip)) { increment = - increment; } int currentIndex = sectionIDs().indexOf(m_activeSection); currentIndex += increment; if (currentIndex >= sectionIDs().size()) { currentIndex = 0; } else if (currentIndex < 0) { currentIndex = sectionIDs().size() - 1; } sectionActivated(sectionIDs()[currentIndex]); } void LancelotWindow::loadConfig() { // Non configurable options m_mainSize = QSize( m_mainConfig.readEntry("width", mainWidthDefault), m_mainConfig.readEntry("height", windowHeightDefault) ); // Creating the config widget if (m_configWidget == NULL) { m_configWidget = new QWidget(); m_configUi.setupUi(m_configWidget); } m_configUi.loadConfig(); // Loading activation method for groups bool sectionNoClick = true; bool listsNoClick = true; bool systemNoClick = true; switch (m_configUi.activationMethod()) { case LancelotConfig::Click: sectionNoClick = false; listsNoClick = false; systemNoClick = false; break; case LancelotConfig::Classic: listsNoClick = false; systemNoClick = false; break; case LancelotConfig::NoClick: break; } if (systemNoClick) { Lancelot::Global::self()->group("SystemButtons")->setProperty("extenderPosition", (layoutMain->flip() & Plasma::VerticalFlip) ? (Lancelot::TopExtender) : (Lancelot::BottomExtender) ); Lancelot::Global::self()->group("SystemButtons") ->setProperty("activationMethod", Lancelot::ExtenderActivate); } else { Lancelot::Global::self()->group("SystemButtons") ->setProperty("extenderPosition", QVariant(Lancelot::NoExtender)); Lancelot::Global::self()->group("SystemButtons") ->setProperty("activationMethod", Lancelot::ClickActivate); } Lancelot::Global::self()->group("LancelotContext")->setProperty("extenderPosition", Lancelot::Global::self()->group("SystemButtons")->property("extenderPosition")); Lancelot::Global::self()->group("LancelotContext")->setProperty("activationMethod", Lancelot::Global::self()->group("SystemButtons")->property("activationMethod")); Lancelot::Global::self()->group("SystemButtons")->notifyUpdated(); Lancelot::Global::self()->group("LancelotContext")->notifyUpdated(); if (sectionNoClick) { Lancelot::Global::self()->group("SectionButtons") ->setProperty("activationMethod", Lancelot::HoverActivate); } else { Lancelot::Global::self()->group("SectionButtons") ->setProperty("activationMethod", Lancelot::ClickActivate); } Lancelot::Global::self()->group("SectionButtons")->notifyUpdated(); if (listsNoClick) { Lancelot::Global::self()->group("ActionListView-Left") ->setProperty("extenderPosition", Lancelot::LeftExtender); Lancelot::Global::self()->group("ActionListView-Right") ->setProperty("extenderPosition", Lancelot::RightExtender); Lancelot::Global::self()->group("PassagewayView") ->setProperty("activationMethod", Lancelot::ExtenderActivate); Lancelot::Global::self()->group("PopupList") ->setProperty("extenderPosition", Lancelot::RightExtender); } else { Lancelot::Global::self()->group("ActionListView-Left") ->setProperty("extenderPosition", Lancelot::NoExtender); Lancelot::Global::self()->group("ActionListView-Right") ->setProperty("extenderPosition", Lancelot::NoExtender); Lancelot::Global::self()->group("PassagewayView") ->setProperty("activationMethod", Lancelot::ClickActivate); Lancelot::Global::self()->group("PopupList") ->setProperty("extenderPosition", Lancelot::NoExtender); } Lancelot::Global::self()->group("ActionListView-Left")->notifyUpdated(); Lancelot::Global::self()->group("ActionListView-Right")->notifyUpdated(); Lancelot::Global::self()->group("PassagewayView")->notifyUpdated(); // PassagewayView settings if (m_configUi.appbrowserPopupSubmenus()) { passagewayApplications->setColumnLimit(-1); } else if (m_configUi.appbrowserColumnLimitted()) { passagewayApplications->setColumnLimit(2); } else { passagewayApplications->setColumnLimit(22); // TODO: Temp } // Loading system buttons actions systemButtonActions[buttonSystem1] = m_configUi.systemButtonActions[m_configUi.buttonSystem1]; systemButtonActions[buttonSystem2] = m_configUi.systemButtonActions[m_configUi.buttonSystem2]; systemButtonActions[buttonSystem3] = m_configUi.systemButtonActions[m_configUi.buttonSystem3]; QHashIterator < Lancelot::ExtenderButton *, QString > i(systemButtonActions); while (i.hasNext()) { i.next(); i.key()->setTitle(Lancelot::Models::SystemActions::self()->actionTitle( i.value())); i.key()->setIcon(Lancelot::Models::SystemActions::self()->actionIcon( i.value())); } // Logging Lancelot::Models::Logger::self()->setEnabled(m_configUi.enableUsageStatistics()); // Keep open Lancelot::Models::ApplicationConnector::self()->setAutohideEnabled(!m_configUi.checkKeepOpen->isChecked()); // Runners ((Lancelot::Models::Runner *) m_models["Runner"])->reloadConfiguration(); } void LancelotWindow::lancelotContext() { if (!menuLancelotContext) { menuLancelotContext = new Lancelot::PopupMenu(); connect( menuLancelotContext->addAction(KIcon("kmenuedit"), i18n("Menu Editor")), SIGNAL(triggered(bool)), this, SLOT(showMenuEditor())); connect( menuLancelotContext->addAction(KIcon("configure-shortcuts"), i18n("Configure Shortcuts...")), SIGNAL(triggered(bool)), this, SLOT(configureShortcuts())); connect( menuLancelotContext->addAction(KIcon("configure"), i18n("Configure Lancelot menu...")), SIGNAL(triggered(bool)), this, SLOT(configureMenu())); connect( menuLancelotContext->addAction(KIcon("lancelot"), i18n("About Lancelot")), SIGNAL(triggered(bool)), this, SLOT(showAboutDialog())); } // menuLancelotContext->show(); // menuLancelotContext->exec(QCursor::pos()); menuLancelotContext->updateSize(); QRect g = buttonLancelotContext->geometry().toRect(); g.moveTopLeft(g.topLeft() + geometry().topLeft()); if (layoutMain->flip() & Plasma::VerticalFlip) { menuLancelotContext->move(g.bottomLeft()); } else { menuLancelotContext->move(g.topLeft() - QPoint(0, menuLancelotContext->geometry().height())); } menuLancelotContext->exec(menuLancelotContext->pos()); } void LancelotWindow::configureMenu() { lancelotHide(true); const QString dialogID = "LancelotMenuConfigurationDialog"; KConfigDialog * dialog; if ((dialog = KConfigDialog::exists(dialogID))) { KWindowSystem::setOnDesktop(dialog->winId(), KWindowSystem::currentDesktop()); dialog->show(); KWindowSystem::activateWindow(dialog->winId()); return; } KConfigSkeleton * nullManager = new KConfigSkeleton(0); dialog = new KConfigDialog(this, dialogID, nullManager); dialog->setFaceType(KPageDialog::Auto); dialog->setWindowTitle(i18n("Configure Lancelot menu")); dialog->setAttribute(Qt::WA_DeleteOnClose, false); dialog->addPage(m_configWidget, i18n("Configure Lancelot menu"), "lancelot"); dialog->showButton(KDialog::Apply, false); // To follow the current Plasma applet style dialog->show(); connect(dialog, SIGNAL(applyClicked()), this, SLOT(saveConfig())); connect(dialog, SIGNAL(okClicked()), this, SLOT(saveConfig())); } void LancelotWindow::saveConfig() { m_configUi.saveConfig(); loadConfig(); } void LancelotWindow::showAboutDialog() { lancelotHide(true); KAboutApplicationDialog * about = new KAboutApplicationDialog( KCmdLineArgs::aboutData() ); about->setAttribute(Qt::WA_DeleteOnClose, true); about->show(); } void LancelotWindow::showMenuEditor() { KProcess::execute("kmenuedit"); } void LancelotWindow::hideImmediate() { lancelotHide(true); } void LancelotWindow::resizeEvent(QResizeEvent * event) { QWidget::resizeEvent(event); if (updateWindowSize()) { // m_corona-> // setSceneRect(QRectF(QPointF(), event->size())); // m_root-> // setGeometry(QRect(QPoint(), event->size())); } } #include "LancelotWindow.moc"