You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lxqt-runner-packaging/dialog.cpp

491 lines
14 KiB

/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXDE-Qt - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
* Petr Vanek <petr@scribus.info>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "dialog.h"
#include "ui_dialog.h"
#include "widgets.h"
#include "commanditemmodel.h"
#include "configuredialog/configuredialog.h"
#include <LXQt/Settings>
#include <LXQt/HtmlDelegate>
#include <XdgIcon>
#include <LXQt/PowerManager>
#include <LXQt/ScreenSaver>
#include <LXQtGlobalKeys/Action>
#include <LXQtGlobalKeys/Client>
#include <QDebug>
#include <QCloseEvent>
#include <QDesktopWidget>
#include <QProcess>
#include <QLineEdit>
#include <QAction>
#include <QMessageBox>
#include <QApplication>
#include <QMenu>
#include <QWindow>
#include <QScrollBar>
#include <KWindowSystem/KWindowSystem>
#define DEFAULT_SHORTCUT "Alt+F2"
/************************************************
************************************************/
Dialog::Dialog(QWidget *parent) :
QDialog(parent, Qt::Dialog | Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint),
ui(new Ui::Dialog),
mSettings(new LXQt::Settings("lxqt-runner", this)),
mGlobalShortcut(0),
mLockCascadeChanges(false),
mDesktopChanged(false),
mConfigureDialog(0)
{
ui->setupUi(this);
setWindowTitle("LXQt Runner");
setAttribute(Qt::WA_TranslucentBackground);
connect(LXQt::Settings::globalSettings(), SIGNAL(iconThemeChanged()), this, SLOT(update()));
connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(hide()));
connect(mSettings, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
ui->commandEd->installEventFilter(this);
connect(ui->commandEd, SIGNAL(textChanged(QString)), this, SLOT(setFilter(QString)));
connect(ui->commandEd, SIGNAL(returnPressed()), this, SLOT(runCommand()));
mCommandItemModel = new CommandItemModel(this);
ui->commandList->installEventFilter(this);
ui->commandList->setModel(mCommandItemModel);
ui->commandList->setEditTriggers(QAbstractItemView::NoEditTriggers);
connect(ui->commandList, SIGNAL(clicked(QModelIndex)), this, SLOT(runCommand()));
setFilter(QString());
dataChanged();
ui->commandList->setItemDelegate(new LXQt::HtmlDelegate(QSize(32, 32), ui->commandList));
// Popup menu ...............................
QAction *a = new QAction(XdgIcon::fromTheme("configure"), tr("Configure"), this);
connect(a, SIGNAL(triggered()), this, SLOT(showConfigDialog()));
addAction(a);
a = new QAction(XdgIcon::fromTheme("edit-clear-history"), tr("Clear History"), this);
connect(a, SIGNAL(triggered()), mCommandItemModel, SLOT(clearHistory()));
addAction(a);
mPowerManager = new LXQt::PowerManager(this);
addActions(mPowerManager->availableActions());
mScreenSaver = new LXQt::ScreenSaver(this);
addActions(mScreenSaver->availableActions());
setContextMenuPolicy(Qt::ActionsContextMenu);
QMenu *menu = new QMenu(this);
menu->addActions(actions());
ui->actionButton->setMenu(menu);
// End of popup menu ........................
applySettings();
connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), SLOT(realign()));
connect(QApplication::desktop(), SIGNAL(workAreaResized(int)), SLOT(realign()));
connect(mGlobalShortcut, SIGNAL(activated()), this, SLOT(showHide()));
connect(mGlobalShortcut, SIGNAL(shortcutChanged(QString,QString)), this, SLOT(shortcutChanged(QString,QString)));
connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(onActiveWindowChanged(WId)));
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &Dialog::onCurrentDesktopChanged);
resize(mSettings->value("dialog/width", 400).toInt(), size().height());
// TEST
connect(mCommandItemModel, SIGNAL(layoutChanged()), this, SLOT(dataChanged()));
}
/************************************************
************************************************/
Dialog::~Dialog()
{
delete ui;
}
/************************************************
************************************************/
void Dialog::closeEvent(QCloseEvent *event)
{
hide();
event->accept();
}
/************************************************
************************************************/
QSize Dialog::sizeHint() const
{
QSize size = QDialog::sizeHint();
size.setWidth(this->size().width());
return size;
}
/************************************************
************************************************/
void Dialog::resizeEvent(QResizeEvent *event)
{
mSettings->setValue("dialog/width", size().width());
}
/************************************************
************************************************/
bool Dialog::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (object == ui->commandEd)
return editKeyPressEvent(keyEvent);
if (object == ui->commandList)
return listKeyPressEvent(keyEvent);
}
return QDialog::eventFilter(object, event);
}
/************************************************
eventFilter for ui->commandEd
************************************************/
bool Dialog::editKeyPressEvent(QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_N:
if (event->modifiers().testFlag(Qt::ControlModifier))
{
QKeyEvent ev(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
editKeyPressEvent(&ev);
return true;
}
return false;
case Qt::Key_P:
if (event->modifiers().testFlag(Qt::ControlModifier))
{
QKeyEvent ev(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
editKeyPressEvent(&ev);
return true;
}
return false;
case Qt::Key_Up:
case Qt::Key_PageUp:
if (ui->commandEd->text().isEmpty() &&
ui->commandList->isVisible() &&
ui->commandList->currentIndex().row() == 0
)
{
setFilter(QString(), false);
return true;
}
qApp->sendEvent(ui->commandList, event);
return true;
case Qt::Key_Down:
case Qt::Key_PageDown:
if (ui->commandEd->text().isEmpty() &&
ui->commandList->isHidden()
)
{
setFilter(QString(), true);
// set focus to the list so that it highlights the first item correctly,
// and then set it back to the textfield, where it belongs
ui->commandList->setFocus();
ui->commandEd->setFocus();
return true;
}
qApp->sendEvent(ui->commandList, event);
return true;
case Qt::Key_Tab:
const CommandProviderItem *command = mCommandItemModel->command(ui->commandList->currentIndex());
if (command)
ui->commandEd->setText(command->title());
return true;
}
return QDialog::eventFilter(ui->commandList, event);
}
/************************************************
eventFilter for ui->commandList
************************************************/
bool Dialog::listKeyPressEvent(QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_Up:
case Qt::Key_PageUp:
if (ui->commandList->currentIndex().row() == 0)
{
ui->commandEd->setFocus();
return true;
}
break;
case Qt::Key_Left:
case Qt::Key_Right:
ui->commandEd->setFocus();
qApp->sendEvent(ui->commandEd, event);
return true;
default:
// Alphabetical or number key ...........
if (!event->text().isEmpty())
{
ui->commandEd->setFocus();
qApp->sendEvent(ui->commandEd, event);
return true;
}
}
return QDialog::eventFilter(ui->commandEd, event);
}
/************************************************
************************************************/
void Dialog::showHide()
{
// Using KWindowSystem to detect the active window since
// QWidget::isActiveWindow is not working reliably.
if (isVisible() && (KWindowSystem::activeWindow() == winId()))
{
hide();
}
else
{
realign();
show();
KWindowSystem::forceActiveWindow(winId());
ui->commandEd->setFocus();
}
}
/************************************************
************************************************/
void Dialog::realign()
{
QRect desktop;
int screen = mMonitor;
if (mMonitor < 0 || mMonitor > QApplication::desktop()->screenCount() - 1)
screen = QApplication::desktop()->screenNumber(QCursor::pos());
desktop = QApplication::desktop()->availableGeometry(screen).intersected(KWindowSystem::workArea(screen));
QRect rect = this->geometry();
rect.moveCenter(desktop.center());
if (mShowOnTop)
rect.moveTop(desktop.top());
else
rect.moveTop(desktop.center().y() - ui->panel->sizeHint().height());
setGeometry(rect);
}
/************************************************
************************************************/
void Dialog::applySettings()
{
if (mLockCascadeChanges)
return;
// Shortcut .................................
QString shortcut = mSettings->value("dialog/shortcut", DEFAULT_SHORTCUT).toString();
if (shortcut.isEmpty())
shortcut = DEFAULT_SHORTCUT;
if (!mGlobalShortcut)
mGlobalShortcut = GlobalKeyShortcut::Client::instance()->addAction(shortcut, "/runner/show_hide_dialog", tr("Show/hide runner dialog"), this);
else if (mGlobalShortcut->shortcut() != shortcut)
mGlobalShortcut->changeShortcut(shortcut);
mShowOnTop = mSettings->value("dialog/show_on_top", true).toBool();
mMonitor = mSettings->value("dialog/monitor", -1).toInt();
mCommandItemModel->showHistoryFirst(mSettings->value("dialog/history_first", true).toBool());
realign();
mSettings->sync();
}
/************************************************
************************************************/
void Dialog::shortcutChanged(const QString &/*oldShortcut*/, const QString &newShortcut)
{
if (!newShortcut.isEmpty())
{
mLockCascadeChanges = true;
mSettings->setValue("dialog/shortcut", newShortcut);
mSettings->sync();
mLockCascadeChanges = false;
}
}
/************************************************
************************************************/
void Dialog::onActiveWindowChanged(WId id)
{
if (isVisible() && 0 != id && id != winId())
{
if (mDesktopChanged)
{
mDesktopChanged = false;
KWindowSystem::forceActiveWindow(winId());
} else
{
hide();
}
}
}
/************************************************
************************************************/
void Dialog::onCurrentDesktopChanged(int screen)
{
if (isVisible())
{
KWindowSystem::setOnDesktop(winId(), screen);
KWindowSystem::forceActiveWindow(winId());
//Note: workaround for changing desktop while runner is shown
// The KWindowSystem::forceActiveWindow may fail to correctly activate runner if there
// are any other windows on the new desktop (probably because of the sequence while WM
// changes the virtual desktop (change desktop and activate any of the windows on it))
mDesktopChanged = true;
}
}
/************************************************
************************************************/
void Dialog::setFilter(const QString &text, bool onlyHistory)
{
if (mCommandItemModel->isOutDated())
mCommandItemModel->rebuild();
QString trimmedText = text.simplified();
mCommandItemModel->setCommand(trimmedText);
mCommandItemModel->showOnlyHistory(onlyHistory);
mCommandItemModel->setFilterRegExp(trimmedText);
mCommandItemModel->invalidate();
// tidy up layout and select first item
ui->commandList->doItemsLayout();
ui->commandList->setCurrentIndex(mCommandItemModel->index(0, 0));
}
/************************************************
************************************************/
void Dialog::dataChanged()
{
if (mCommandItemModel->rowCount())
{
ui->commandList->setCurrentIndex(mCommandItemModel->appropriateItem(mCommandItemModel->command()));
ui->commandList->scrollTo(ui->commandList->currentIndex());
ui->commandList->show();
}
else
{
ui->commandList->hide();
}
adjustSize();
}
/************************************************
************************************************/
void Dialog::runCommand()
{
bool res =false;
const CommandProviderItem *command = mCommandItemModel->command(ui->commandList->currentIndex());
if (command)
res = command->run();
if (res)
{
hide();
ui->commandEd->clear();
}
}
/************************************************
************************************************/
void Dialog::showConfigDialog()
{
if (!mConfigureDialog)
mConfigureDialog = new ConfigureDialog(mSettings, DEFAULT_SHORTCUT, this);
mConfigureDialog->exec();
}
#undef DEFAULT_SHORTCUT