Refactoring, initial complete version of dynamic shortcuts

This commit is contained in:
Martin Rotter 2013-06-30 15:22:44 +02:00
parent 7ade5c4315
commit b3e1f43db2
25 changed files with 341 additions and 34 deletions

View File

@ -165,6 +165,8 @@ set(APP_SOURCES
src/gui/formwelcome.cpp
src/gui/formabout.cpp
src/gui/shortcutcatcher.cpp
src/gui/shortcutbutton.cpp
src/gui/dynamicshortcutswidget.cpp
# CORE sources.
src/core/debugging.cpp
@ -172,7 +174,7 @@ set(APP_SOURCES
src/core/systemfactory.cpp
src/core/datetime.cpp
src/core/localization.cpp
src/gui/shortcutbutton.cpp
src/core/dynamicshortcuts.cpp
# Basic application sources.
src/main.cpp
@ -195,6 +197,7 @@ set(APP_HEADERS
src/gui/formabout.h
src/gui/shortcutcatcher.h
src/gui/shortcutbutton.h
src/gui/dynamicshortcutswidget.h
# CORE headers.
)

View File

@ -5,6 +5,9 @@
#include "core/datetime.h"
DateTime::DateTime() {
}
QDateTime DateTime::fromString(const QString &date_time) {
QString date = date_time.simplified();
QDateTime dt;

View File

@ -5,6 +5,9 @@
class DateTime {
private:
DateTime();
public:
// Returns QDatetime instance from input QString.
// If parsing fails, then invalid QDateTime is returned.

View File

@ -17,6 +17,9 @@
#endif
Debugging::Debugging() {
}
void Debugging::debugHandler(QtMsgType type,
const QMessageLogContext &placement,
const QString &message) {

View File

@ -5,6 +5,9 @@
class Debugging {
private:
Debugging();
public:
// Specifies format of output console messages.
// Macros:

View File

@ -17,6 +17,7 @@
#define APP_CFG_PATH "data/config/config.ini"
#define APP_CFG_GUI "gui"
#define APP_CFG_GEN "main"
#define APP_CFG_CUTS "keyboard"
#define APP_DB_PATH "data/storage/database.db"
#define APP_PREFIX "@CMAKE_INSTALL_PREFIX@"

View File

@ -0,0 +1,27 @@
#include <QAction>
#include "core/dynamicshortcuts.h"
#include "core/settings.h"
#include "core/defs.h"
DynamicShortcuts::DynamicShortcuts() {
}
void DynamicShortcuts::save(const QList<QAction *> actions) {
foreach (QAction *action, actions) {
Settings::getInstance()->setValue(APP_CFG_CUTS,
action->objectName(),
action->shortcut().toString(QKeySequence::NativeText));
}
}
void DynamicShortcuts::load(const QList<QAction *> actions) {
foreach (QAction *action, actions) {
QString shortcut_for_action = Settings::getInstance()->value(APP_CFG_CUTS,
action->objectName(),
action->shortcut().toString(QKeySequence::NativeText)).toString();
action->setShortcut(QKeySequence::fromString(shortcut_for_action,
QKeySequence::NativeText));
}
}

View File

@ -0,0 +1,22 @@
#ifndef DYNAMICSHORTCUTS_H
#define DYNAMICSHORTCUTS_H
#include <QList>
class QAction;
class DynamicShortcuts {
private:
DynamicShortcuts();
public:
// Checks the application settings and then initializes shortcut of
// each action from actions from the settings.
static void load(const QList<QAction*> actions);
// Stores shortcut of each action from actions into the application
// settings.
static void save(const QList<QAction*> actions);
};
#endif // DYNAMICSHORTCUTS_H

View File

@ -41,12 +41,11 @@ void Localization::load() {
"en").toString();
QTranslator qt_translator, app_translator;
// Load localizations and setup locales.
// Load localizations.
if (app_translator.load(QString("rssguard_%1.qm").arg(locale_name),
APP_LANG_PATH)) {
qDebug("Application localization %s loaded successfully. Setting up locale.",
qPrintable(locale_name));
QLocale::setDefault(QLocale(locale_name));
}
else {
qDebug("Application localization %s was not loaded.", qPrintable(locale_name));
@ -56,9 +55,11 @@ void Localization::load() {
APP_LANG_PATH)) {
qDebug("Qt localization %s loaded successfully. Setting up locale.",
qPrintable(locale_name));
QLocale::setDefault(QLocale(locale_name));
}
else {
qDebug("Qt localization %s was not loaded.", qPrintable(locale_name));
}
// Setup locale.
QLocale::setDefault(QLocale(locale_name));
}

View File

@ -13,7 +13,6 @@ struct Language {
};
class Localization {
// TODO: Finish implementation of this class.
private:
Localization();

View File

@ -16,9 +16,9 @@ SystemFactory::SystemFactory() {
SystemFactory::AutoStartStatus SystemFactory::getAutoStartStatus() {
// User registry way to auto-start the application on Windows.
#if defined(Q_OS_WIN)
QSettings registr_key("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings registry_key("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat);
bool autostart_enabled = registr_key.value(APP_LOW_NAME,
bool autostart_enabled = registry_key.value(APP_LOW_NAME,
"").toString().replace('\\',
'/') ==
QtSingleApplication::applicationFilePath();

View File

@ -7,6 +7,7 @@ class SystemFactory {
SystemFactory();
public:
// Specifies possible states of auto-start functionality.
enum AutoStartStatus {
Enabled,
Disabled,

View File

@ -0,0 +1,45 @@
#include <QFormLayout>
#include <QAction>
#include "gui/dynamicshortcutswidget.h"
#include "gui/shortcutcatcher.h"
DynamicShortcutsWidget::DynamicShortcutsWidget(QWidget *parent) : QWidget(parent) {
// Create layout for this control and set is as active.
m_layout = new QFormLayout(this);
m_layout->setMargin(0);
setLayout(m_layout);
}
DynamicShortcutsWidget::~DynamicShortcutsWidget() {
delete m_layout;
}
void DynamicShortcutsWidget::updateShortcuts() {
foreach (ActionBinding binding, m_actionBindings) {
binding.first->setShortcut(binding.second->keySequence());
}
}
void DynamicShortcutsWidget::populate(const QList<QAction *> actions) {
m_actionBindings.clear();
foreach (QAction *action, actions) {
// Create shortcut catcher for this action and set default shortcut.
ShortcutCatcher *catcher = new ShortcutCatcher(this);
catcher->setKeySequence(action->shortcut());
// Store information for re-initialization of shortcuts
// of actions when widget gets "confirmed".
QPair<QAction*,ShortcutCatcher*> new_binding;
new_binding.first = action;
new_binding.second = catcher;
m_actionBindings << new_binding;
// Add new catcher to our control.
m_layout->addRow(action->text(), catcher);
}
}

View File

@ -0,0 +1,35 @@
#ifndef DYNAMICSHORTCUTSOVERVIEW_H
#define DYNAMICSHORTCUTSOVERVIEW_H
#include <QWidget>
class QFormLayout;
class ShortcutCatcher;
typedef QPair<QAction*, ShortcutCatcher*> ActionBinding;
class DynamicShortcutsWidget : public QWidget {
Q_OBJECT
public:
explicit DynamicShortcutsWidget(QWidget *parent = 0);
virtual ~DynamicShortcutsWidget();
// Updates shortcuts of all actions according to changes.
// NOTE: No access to settings is done here.
// Shortcuts are fetched from settings when applications starts
// and stored back to settings when application quits.
void updateShortcuts();
// Populates this widget with shortcut widgets for given actions.
// NOTE: This gets initial shortcut for each action from its properties, NOT from
// the application settings.
void populate(const QList<QAction*> actions);
private:
QFormLayout *m_layout;
QList<ActionBinding> m_actionBindings;
};
#endif // DYNAMICSHORTCUTSOVERVIEW_H

View File

@ -42,6 +42,13 @@ QMenu *FormMain::getTrayMenu() {
return m_trayMenu;
}
QList<QAction*> FormMain::getActions() {
QList<QAction*> actions;
actions << m_ui->m_actionImport << m_ui->m_actionExport <<
m_ui->m_actionSettings << m_ui->m_actionQuit;
return actions;
}
void FormMain::prepareMenus() {
// Setup menu for tray icon.
if (SystemTrayIcon::isSystemTrayAvailable()) {
@ -101,6 +108,7 @@ bool FormMain::event(QEvent *event) {
if (event->type() == ThemeFactoryEvent::type()) {
// Handle the change of icon theme.
setupIcons();
event->accept();
return true;
}

View File

@ -17,6 +17,10 @@ class FormMain : public QMainWindow {
// Returns menu for the tray icon.
QMenu *getTrayMenu();
// Returns list of all globally available actions.
// NOTE: This is used for setting dynamic shortcuts for given actions.
QList<QAction*> getActions();
static FormMain *getInstance();
protected:

View File

@ -206,16 +206,6 @@
</size>
</property>
</widget>
<widget class="ShortcutCatcher" name="widget" native="true">
<property name="geometry">
<rect>
<x>320</x>
<y>90</y>
<width>211</width>
<height>80</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="m_menuBar">
<property name="geometry">
@ -241,7 +231,7 @@
</property>
<addaction name="m_actionAboutGuard"/>
</widget>
<widget class="QMenu" name="menu_View">
<widget class="QMenu" name="m_menuView">
<property name="title">
<string>&amp;View</string>
</property>
@ -253,7 +243,7 @@
<addaction name="m_actionSettings"/>
</widget>
<addaction name="m_menuFile"/>
<addaction name="menu_View"/>
<addaction name="m_menuView"/>
<addaction name="m_menuTools"/>
<addaction name="m_menuHelp"/>
</widget>
@ -262,21 +252,33 @@
<property name="text">
<string>&amp;Import</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+I</string>
</property>
</action>
<action name="m_actionExport">
<property name="text">
<string>E&amp;xport</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+E</string>
</property>
</action>
<action name="m_actionQuit">
<property name="text">
<string>&amp;Quit</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+Q</string>
</property>
</action>
<action name="m_actionSettings">
<property name="text">
<string>&amp;Settings</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="m_actionAboutGuard">
<property name="text">
@ -284,14 +286,6 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>ShortcutCatcher</class>
<extends>QWidget</extends>
<header>shortcutcatcher.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -9,6 +9,7 @@
#include "core/defs.h"
#include "core/localization.h"
#include "core/systemfactory.h"
#include "core/dynamicshortcuts.h"
FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormSettings) {
@ -38,6 +39,7 @@ FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_ui(new Ui::Form
// Load all settings.
loadGeneral();
loadShortcuts();
loadInterface();
loadLanguage();
}
@ -49,6 +51,7 @@ FormSettings::~FormSettings() {
void FormSettings::saveSettings() {
// Save all settings.
saveGeneral();
saveShortcuts();
saveInterface();
saveLanguage();
}
@ -111,6 +114,18 @@ void FormSettings::saveLanguage() {
}
}
void FormSettings::loadShortcuts() {
m_ui->m_shortcuts->populate(FormMain::getInstance()->getActions());
}
void FormSettings::saveShortcuts() {
// Update the actual shortcuts of some actions.
m_ui->m_shortcuts->updateShortcuts();
// Save new shortcuts to the settings.
DynamicShortcuts::save(FormMain::getInstance()->getActions());
}
void FormSettings::loadGeneral() {
// Load auto-start status.
SystemFactory::AutoStartStatus autostart_status = SystemFactory::getAutoStartStatus();

View File

@ -30,6 +30,9 @@ class FormSettings : public QDialog {
void loadLanguage();
void saveLanguage();
void loadShortcuts();
void saveShortcuts();
private:
Ui::FormSettings *m_ui;

View File

@ -30,6 +30,11 @@
<string>General</string>
</property>
</item>
<item>
<property name="text">
<string>Keyboard shortcuts</string>
</property>
</item>
<item>
<property name="text">
<string>User interface</string>
@ -45,7 +50,7 @@
<item row="0" column="1">
<widget class="QStackedWidget" name="m_stackedSettings">
<property name="currentIndex">
<number>2</number>
<number>1</number>
</property>
<widget class="QWidget" name="m_pageGeneral">
<layout class="QFormLayout" name="formLayout_5">
@ -70,6 +75,59 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="m_pageShortcuts">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<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="QScrollArea" name="m_scrollShortcuts">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="m_scrollShortcutsContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>506</width>
<height>368</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<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="DynamicShortcutsWidget" name="m_shortcuts" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="m_pageUi">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
@ -90,7 +148,7 @@
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="m_tabIconSkin">
<attribute name="title">
@ -254,6 +312,14 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>DynamicShortcutsWidget</class>
<extends>QWidget</extends>
<header>dynamicshortcutswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

View File

@ -1,3 +1,31 @@
/******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef SHORTCUTBUTTON_H
#define SHORTCUTBUTTON_H

View File

@ -34,9 +34,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "gui/themefactory.h"
ShortcutCatcher::ShortcutCatcher(QWidget *parent) : QWidget(parent) {
ShortcutCatcher::ShortcutCatcher(QWidget *parent)
: QWidget(parent) {
// Setup layout of the control
m_layout = new QHBoxLayout(this);
m_layout->setMargin(0);
m_layout->setSpacing(1);
// Create clear button.
@ -83,6 +85,8 @@ void ShortcutCatcher::doneRecording() {
m_sequenceButton->setDown(false);
updateDisplayShortcut();
emit keySequenceChanged(m_currentSequence);
}
void ShortcutCatcher::controlModifierlessTimout() {

View File

@ -1,3 +1,31 @@
/******************************************************************************
Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef KEYSEQUENCECATCHER_H
#define KEYSEQUENCECATCHER_H
@ -29,6 +57,9 @@ class ShortcutCatcher : public QWidget {
void setKeySequence(const QKeySequence& key);
void clearKeySequence();
signals:
void keySequenceChanged(QKeySequence seguence);
private:
QToolButton *m_clearButton;
ShortcutButton *m_sequenceButton;

View File

@ -43,9 +43,6 @@ void ThemeFactory::setupSearchPaths() {
qPrintable(QIcon::themeSearchPaths().join(", ")));
}
// TODO: Load currently selected "real" icon theme name instead of
// Qt default "", which stands for currently active system icon theme name on
// linux. On Windows, tiny "oxygen" version will be used as default icon theme.
QString ThemeFactory::getSystemIconTheme() {
#if defined(Q_OS_LINUX)
// Empty string forces Qt to use icon theme from operating system.

View File

@ -7,6 +7,7 @@
#include "core/debugging.h"
#include "core/localization.h"
#include "core/settings.h"
#include "core/dynamicshortcuts.h"
#include "gui/themefactory.h"
#include "gui/formmain.h"
#include "gui/formwelcome.h"
@ -14,6 +15,13 @@
#include "qtsingleapplication/qtsingleapplication.h"
// TODO: Check if extra UNIX signalling is needed.
// Use <csignal> header for it - signal function and catch SIGHUP
// void my_terminate (int param) {
// qApp->quit();
// }
int main(int argc, char *argv[]) {
//: Name of language, e.g. English.
QObject::tr("LANG_NAME");
@ -58,7 +66,7 @@ int main(int argc, char *argv[]) {
// Add an extra path for non-system icon themes.
ThemeFactory::setupSearchPaths();
// Load localization and setup locale.
// Load localization and setup locale before any widget is constructed.
Localization::load();
// These settings needs to be set before any QSettings object.
@ -74,6 +82,9 @@ int main(int argc, char *argv[]) {
// Set correct information for main window.
window.setWindowTitle(APP_LONG_NAME);
// Now is a good time to initialize dynamic keyboard shortcuts.
DynamicShortcuts::load(FormMain::getInstance()->getActions());
// Display welcome dialog if application is launched for the first time.
if (Settings::getInstance()->value(APP_CFG_GEN, "first_start", true).toBool()) {
Settings::getInstance()->setValue(APP_CFG_GEN, "first_start", false);