First commit
This commit is contained in:
commit
26748b4923
|
@ -0,0 +1,89 @@
|
|||
#include "aboutdialog.h"
|
||||
#include "ui_aboutdialog.h"
|
||||
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QStyle>
|
||||
#include <QMessageBox>
|
||||
|
||||
/*!
|
||||
\namespace Dialogs
|
||||
\brief Provides common dialogs such as AboutDialog, EnterPasswordDialog and SettingsDialog.
|
||||
*/
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::AboutDialog
|
||||
* \brief The AboutDialog class provides a simple about dialog.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an about dialog with the provided information.
|
||||
* \param parent Specifies the parent widget.
|
||||
* \param applicationName Specifies the name of the application. If empty, QApplication::applicationName() will be used.
|
||||
* \param creator Specifies the creator of the application. If empty, QApplication::organizationName() will be used.
|
||||
* \param version Specifies the version of the application. If empty, QApplication::applicationVersion() will be used.
|
||||
* \param description Specifies a short description about the application.
|
||||
* \param website Specifies the URL to the website of the application. If empty, QApplication::organizationDomain() will be used.
|
||||
* \param image Specifies the application icon. If the image is null, the standard information icon will be used.
|
||||
*/
|
||||
AboutDialog::AboutDialog(QWidget *parent, const QString &applicationName, const QString &creator, const QString &version, const QString &website, const QString &description, const QImage &image) :
|
||||
QDialog(parent),
|
||||
m_ui(new Ui::AboutDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
#ifdef Q_OS_WIN32
|
||||
setStyleSheet(QStringLiteral("* { font: 9pt \"Segoe UI\"; } #mainWidget { color: black; background-color: white; border: none; } #productNameLabel { font-size: 12pt; color: #003399; }"));
|
||||
#else
|
||||
setStyleSheet(QStringLiteral("#productNameLabel { font-weight: bold; }"));
|
||||
#endif
|
||||
setWindowFlags(Qt::Tool);
|
||||
if(!applicationName.isEmpty()) {
|
||||
m_ui->productNameLabel->setText(applicationName);
|
||||
} else if(!QApplication::applicationDisplayName().isEmpty()) {
|
||||
m_ui->productNameLabel->setText(QApplication::applicationDisplayName());
|
||||
} else {
|
||||
m_ui->productNameLabel->setText(QApplication::applicationName());
|
||||
}
|
||||
if(!creator.isEmpty()) {
|
||||
m_ui->creatorLabel->setText(creator);
|
||||
} else {
|
||||
m_ui->creatorLabel->setText(QApplication::organizationName());
|
||||
}
|
||||
if(!version.isEmpty()) {
|
||||
m_ui->versionLabel->setText(version);
|
||||
} else {
|
||||
m_ui->versionLabel->setText(QApplication::applicationVersion());
|
||||
}
|
||||
m_ui->descLabel->setText(description);
|
||||
if(!website.isEmpty()) {
|
||||
m_ui->websiteLabel->setText(tr("<a href=\"%1\">Website</a>").arg(website));
|
||||
} else {
|
||||
m_ui->websiteLabel->setText(tr("<a href=\"%1\">Website</a>").arg(QApplication::organizationDomain()));
|
||||
}
|
||||
m_iconScene = new QGraphicsScene(this);
|
||||
if(!image.isNull()) {
|
||||
m_iconScene->addItem(new QGraphicsPixmapItem(QPixmap::fromImage(image)));
|
||||
} else {
|
||||
m_iconScene->addItem(new QGraphicsPixmapItem(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, this).pixmap(128)));
|
||||
}
|
||||
m_ui->graphicsView->setScene(m_iconScene);
|
||||
setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, size(), parentWidget() ? parentWidget()->geometry() : QApplication::desktop()->availableGeometry()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs an about dialog with the specified \a parent, \a description and \a image.
|
||||
*/
|
||||
AboutDialog::AboutDialog(QWidget *parent, const QString &description, const QImage &image) :
|
||||
AboutDialog(parent, QString(), QString(), QString(), QString(), description, image)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the about dialog.
|
||||
*/
|
||||
AboutDialog::~AboutDialog()
|
||||
{}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef ABOUTDIALOG_H
|
||||
#define ABOUTDIALOG_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QGraphicsScene;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Dialogs
|
||||
{
|
||||
|
||||
namespace Ui {
|
||||
class AboutDialog;
|
||||
}
|
||||
|
||||
class LIB_EXPORT AboutDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AboutDialog(QWidget *parent, const QString &applicationName, const QString &creator, const QString &version, const QString &website = QString(), const QString &description = QString(), const QImage &image = QImage());
|
||||
explicit AboutDialog(QWidget *parent, const QString &description = QString(), const QImage &image = QImage());
|
||||
~AboutDialog();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::AboutDialog> m_ui;
|
||||
QGraphicsScene *m_iconScene;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ABOUTDIALOG_H
|
|
@ -0,0 +1,252 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialogs::AboutDialog</class>
|
||||
<widget class="QDialog" name="Dialogs::AboutDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>43</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="locale">
|
||||
<locale language="English" country="UnitedStates"/>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="mainWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QFrame" name="informationFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: transparent;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="foregroundBrush">
|
||||
<brush brushstyle="NoBrush">
|
||||
<color alpha="0">
|
||||
<red>0</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</property>
|
||||
<property name="interactive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="productNameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-size: 12pt;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>application name</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="versionLabel">
|
||||
<property name="text">
|
||||
<string>version</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="descLabel">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-style: italic;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>description</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="websiteLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">text-decoration: underline;
|
||||
color: palette(link)s;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>website link</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="creatorLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-size: 8pt;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>creators</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,332 @@
|
|||
#include "enterpassworddialog.h"
|
||||
#include "gui/ui_enterpassworddialog.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#ifdef PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
# if defined(Q_OS_WIN32)
|
||||
# include <windows.h>
|
||||
# elif defined(Q_OS_UNIX)
|
||||
# include <X11/XKBlib.h>
|
||||
# undef KeyPress
|
||||
# undef KeyRelease
|
||||
# undef FocusIn
|
||||
# undef FocusOut
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::EnterPasswordDialog
|
||||
* \brief The EnterPasswordDialog class provides a simple dialog to ask the user for a password.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a password dialog.
|
||||
* \param parent Specifies the parent widget.
|
||||
*/
|
||||
EnterPasswordDialog::EnterPasswordDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_ui(new Ui::EnterPasswordDialog)
|
||||
{
|
||||
// setup ui
|
||||
m_ui->setupUi(this);
|
||||
#ifdef Q_OS_WIN32
|
||||
setStyleSheet(QStringLiteral("* { font: 9pt \"Segoe UI\"; } #mainWidget { color: black; background-color: white; border: none; } #bottomWidget { background-color: #F0F0F0; border-top: 1px solid #DFDFDF; } QMessageBox QLabel, QInputDialog QLabel, #instructionLabel {font-size: 12pt; color: #003399; }"));
|
||||
#else
|
||||
setStyleSheet(QStringLiteral("#instructionLabel { font-weight: bold; }"));
|
||||
#endif
|
||||
setDescription();
|
||||
setPromptForUserName(false);
|
||||
setVerificationRequired(false);
|
||||
setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
|
||||
installEventFilter(this);
|
||||
m_ui->userNameLineEdit->installEventFilter(this);
|
||||
m_ui->password1LineEdit->installEventFilter(this);
|
||||
m_ui->password2LineEdit->installEventFilter(this);
|
||||
// capslock key detection
|
||||
#ifdef PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
m_capslockPressed = isCapslockPressed();
|
||||
#else
|
||||
m_capslockPressed = false;
|
||||
#endif
|
||||
m_ui->capslockWarningWidget->setVisible(m_capslockPressed);
|
||||
// draw icon to capslock warning graphics view
|
||||
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, this);
|
||||
QGraphicsScene* scene = new QGraphicsScene();
|
||||
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(icon.pixmap(16, 16));
|
||||
scene->addItem(item);
|
||||
m_ui->capslockWarningGraphicsView->setScene(scene);
|
||||
// connect signals and slots
|
||||
connect(m_ui->showPasswordCheckBox, &QCheckBox::clicked, this, &EnterPasswordDialog::updateShowPassword);
|
||||
connect(m_ui->noPwCheckBox, &QCheckBox::clicked, this, &EnterPasswordDialog::updateShowPassword);
|
||||
connect(m_ui->confirmPushButton, &QPushButton::clicked, this, &EnterPasswordDialog::confirm);
|
||||
connect(m_ui->abortPushButton, &QPushButton::clicked, this, &EnterPasswordDialog::abort);
|
||||
// grab the keyboard
|
||||
grabKeyboard();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the password dialog.
|
||||
*/
|
||||
EnterPasswordDialog::~EnterPasswordDialog()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the description. The description is shown under the instruction text.
|
||||
* \sa setDescription()
|
||||
*/
|
||||
QString EnterPasswordDialog::description() const
|
||||
{
|
||||
return m_ui->descLabel->text();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the description.
|
||||
* \sa description()
|
||||
*/
|
||||
void EnterPasswordDialog::setDescription(const QString &description)
|
||||
{
|
||||
m_ui->descLabel->setText(description);
|
||||
m_ui->descLabel->setHidden(description.isEmpty());
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the dialogs prompts for a user name as well.
|
||||
*
|
||||
* The dialog does not prompt for a user name by default.
|
||||
*
|
||||
* \sa setPromptForUserName()
|
||||
*/
|
||||
bool EnterPasswordDialog::promtForUserName() const
|
||||
{
|
||||
return !m_ui->userNameLineEdit->isHidden();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whethere the dialog prompts for a user name as well.
|
||||
* \sa promptForUserName()
|
||||
*/
|
||||
void EnterPasswordDialog::setPromptForUserName(bool prompt)
|
||||
{
|
||||
m_ui->userNameLineEdit->setHidden(!prompt);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether a verification (password has to be entered twice) is required.
|
||||
*
|
||||
* \sa EnterPasswordDialog::setVerificationRequired()
|
||||
*/
|
||||
bool EnterPasswordDialog::isVerificationRequired() const
|
||||
{
|
||||
return !m_ui->password2LineEdit->isHidden();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the user is force to enter a password.
|
||||
*
|
||||
* If no password is required, the user is allowed to skip the dialog without entering
|
||||
* a password.
|
||||
*
|
||||
* \sa EnterPasswordDialog::setPasswordRequired()
|
||||
*/
|
||||
bool EnterPasswordDialog::isPasswordRequired() const
|
||||
{
|
||||
return m_ui->noPwCheckBox->isHidden();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether the user is force to enter a password.
|
||||
*
|
||||
* If no password is required, the user is allowed to skip the dialog without entering
|
||||
* a password.
|
||||
*
|
||||
* \sa EnterPasswordDialog::isPasswordRequired()
|
||||
*/
|
||||
void EnterPasswordDialog::setPasswordRequired(bool value)
|
||||
{
|
||||
m_ui->noPwCheckBox->setHidden(value);
|
||||
m_ui->noPwCheckBox->setChecked(false);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the relevant controls to show entered characters or to mask them them.
|
||||
*
|
||||
* This private slot is called when m_ui->showPasswordCheckBox is clicked.
|
||||
*/
|
||||
void EnterPasswordDialog::updateShowPassword()
|
||||
{
|
||||
m_ui->password1LineEdit->setEchoMode(m_ui->showPasswordCheckBox->isChecked()
|
||||
? QLineEdit::Normal
|
||||
: QLineEdit::Password);
|
||||
m_ui->password1LineEdit->setEnabled(!m_ui->noPwCheckBox->isChecked());
|
||||
m_ui->password2LineEdit->setEnabled(!(m_ui->showPasswordCheckBox->isChecked() || m_ui->noPwCheckBox->isChecked()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether a verification (password has to be entered twice) is required.
|
||||
*
|
||||
* \sa EnterPasswordDialog::isVerificationRequired()
|
||||
*/
|
||||
void EnterPasswordDialog::setVerificationRequired(bool value)
|
||||
{
|
||||
if(m_instruction.isEmpty()) {
|
||||
m_ui->instructionLabel->setText(value ? tr("Enter the new password") : tr("Enter the password"));
|
||||
}
|
||||
m_ui->password2LineEdit->setHidden(!value);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the instruction text.
|
||||
*
|
||||
* \sa EnterPasswordDialog::instruction()
|
||||
*/
|
||||
void EnterPasswordDialog::setInstruction(const QString &value)
|
||||
{
|
||||
m_instruction = value;
|
||||
if(m_instruction.isEmpty()) {
|
||||
m_ui->instructionLabel->setText(isVerificationRequired() ? tr("Enter the new password") : tr("Enter the password"));
|
||||
} else {
|
||||
m_ui->instructionLabel->setText(value);
|
||||
}
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
bool EnterPasswordDialog::event(QEvent *event)
|
||||
{
|
||||
switch(event->type()) {
|
||||
case QEvent::KeyPress: {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if(keyEvent->key() == Qt::Key_CapsLock) {
|
||||
m_capslockPressed = !m_capslockPressed;
|
||||
}
|
||||
m_ui->capslockWarningWidget->setVisible(m_capslockPressed);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
return QDialog::event(event);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Internal method to notice when the capslock key is pressed by the user.
|
||||
*
|
||||
* Invocation of this method is done by installing the event filter in the constructor.
|
||||
*/
|
||||
bool EnterPasswordDialog::eventFilter(QObject *sender, QEvent *event)
|
||||
{
|
||||
switch(event->type()) {
|
||||
case QEvent::KeyPress: {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if(keyEvent->key() == Qt::Key_CapsLock) {
|
||||
m_capslockPressed = !m_capslockPressed;
|
||||
} else {
|
||||
QString text = keyEvent->text();
|
||||
if(text.length()) {
|
||||
QChar firstChar = text.at(0);
|
||||
bool shiftPressed = (keyEvent->modifiers() & Qt::ShiftModifier) != 0;
|
||||
if((shiftPressed && firstChar.isLower()) || (!shiftPressed && firstChar.isUpper())) {
|
||||
m_capslockPressed = true;
|
||||
} else if(firstChar.isLetter()) {
|
||||
m_capslockPressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ui->capslockWarningWidget->setVisible(m_capslockPressed);
|
||||
}
|
||||
break;
|
||||
case QEvent::FocusIn:
|
||||
if(sender == m_ui->userNameLineEdit || sender == m_ui->password1LineEdit || sender == m_ui->password2LineEdit) {
|
||||
releaseKeyboard();
|
||||
qobject_cast<QWidget *>(sender)->grabKeyboard();
|
||||
}
|
||||
break;
|
||||
case QEvent::FocusOut:
|
||||
if(sender == m_ui->userNameLineEdit || sender == m_ui->password1LineEdit || sender == m_ui->password2LineEdit) {
|
||||
qobject_cast<QWidget *>(sender)->releaseKeyboard();
|
||||
grabKeyboard();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the dialog status to QDialog::Accepted if a valid password has been enterd.
|
||||
* Displays an error message otherwise.
|
||||
*
|
||||
* This private slot is called when m_ui->confirmPushButton is clicked.
|
||||
*/
|
||||
void EnterPasswordDialog::confirm()
|
||||
{
|
||||
if(!isPasswordRequired() && m_ui->noPwCheckBox->isChecked()) {
|
||||
m_password.clear();
|
||||
done(QDialog::Accepted);
|
||||
} else {
|
||||
QString userName = m_ui->userNameLineEdit->text();
|
||||
QString password = m_ui->password1LineEdit->text();
|
||||
QString repeatedPassword = m_ui->password2LineEdit->text();
|
||||
if(promtForUserName() && userName.isEmpty()) {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You didn't enter a user name."));
|
||||
} else if(password.isEmpty()) {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You didn't enter a password."));
|
||||
} else {
|
||||
if(isVerificationRequired() && (password != repeatedPassword) && !m_ui->showPasswordCheckBox->isChecked()) {
|
||||
if(repeatedPassword.isEmpty()) {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You have to enter the new password twice to ensure you enterd it correct."));
|
||||
} else {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You mistyped the password."));
|
||||
}
|
||||
} else {
|
||||
m_userName = userName;
|
||||
m_password = password;
|
||||
done(QDialog::Accepted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the capslock key is pressed using platform specific functions.
|
||||
*
|
||||
* \remarks - Returns always false for unsupported platforms.
|
||||
* - This method is only avialable if the library is built with
|
||||
* PLATFORM_SPECIFIC_CAPSLOCK_DETECTION defined.
|
||||
* - This static function will be used internally to detect whether the capslock key is pressed
|
||||
* when initializing the dialog if available.
|
||||
* - The function requires the application to be linked against X11 on Linux/Unix/Max OS X.
|
||||
*/
|
||||
#ifdef PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
bool EnterPasswordDialog::isCapslockPressed()
|
||||
{
|
||||
// platform dependent method of determining if CAPS LOCK is pressed
|
||||
# if defined(Q_OS_WIN32)
|
||||
return GetKeyState(VK_CAPITAL) == 1;
|
||||
# elif defined(Q_OS_UNIX)
|
||||
Display *d = XOpenDisplay((char*)0);
|
||||
bool caps_state = false;
|
||||
if (d) {
|
||||
unsigned n;
|
||||
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
|
||||
caps_state = (n & 0x01) == 1;
|
||||
}
|
||||
return caps_state;
|
||||
# else
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#ifndef ENTERPASSWORDDIALOG_H
|
||||
#define ENTERPASSWORDDIALOG_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
namespace Ui {
|
||||
class EnterPasswordDialog;
|
||||
}
|
||||
|
||||
class LIB_EXPORT EnterPasswordDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString userName READ userName)
|
||||
Q_PROPERTY(QString password READ password)
|
||||
Q_PROPERTY(QString description READ description WRITE setDescription)
|
||||
Q_PROPERTY(bool promtForUserName READ promtForUserName WRITE setPromptForUserName)
|
||||
Q_PROPERTY(bool isVerificationRequired READ isVerificationRequired WRITE setVerificationRequired)
|
||||
Q_PROPERTY(bool isPasswordRequired READ isPasswordRequired WRITE setPasswordRequired)
|
||||
Q_PROPERTY(QString instruction READ instruction WRITE setInstruction)
|
||||
Q_PROPERTY(bool isCapslockPressed READ isCapslockPressed)
|
||||
|
||||
public:
|
||||
explicit EnterPasswordDialog(QWidget *parent = nullptr);
|
||||
~EnterPasswordDialog();
|
||||
const QString &userName() const;
|
||||
const QString &password() const;
|
||||
QString description() const;
|
||||
void setDescription(const QString &description = QString());
|
||||
bool promtForUserName() const;
|
||||
void setPromptForUserName(bool prompt);
|
||||
bool isVerificationRequired() const;
|
||||
void setVerificationRequired(bool value);
|
||||
bool isPasswordRequired() const;
|
||||
void setPasswordRequired(bool value);
|
||||
const QString &instruction() const;
|
||||
void setInstruction(const QString &value);
|
||||
#ifdef PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
static bool isCapslockPressed();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event);
|
||||
bool eventFilter(QObject *sender, QEvent *event);
|
||||
|
||||
private slots:
|
||||
void updateShowPassword();
|
||||
void confirm();
|
||||
void abort();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::EnterPasswordDialog> m_ui;
|
||||
QString m_userName;
|
||||
QString m_password;
|
||||
QString m_instruction;
|
||||
bool m_capslockPressed;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the entered user name.
|
||||
*/
|
||||
inline const QString &EnterPasswordDialog::userName() const
|
||||
{
|
||||
return m_userName;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the entered password.
|
||||
*/
|
||||
inline const QString &EnterPasswordDialog::password() const
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the instruction text.
|
||||
*
|
||||
* The instruction text is displayed at the top of the dialog.
|
||||
* If the instruction text is empty the default text "Enter the new password"
|
||||
* or "Enter the password" (depending on whether the verification is requried or
|
||||
* not) displayed.
|
||||
*
|
||||
* \sa EnterPasswordDialog::setInstruction()
|
||||
*/
|
||||
inline const QString &EnterPasswordDialog::instruction() const
|
||||
{
|
||||
return m_instruction;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears all results and sets the dialog status to QDialog::Rejected.
|
||||
*
|
||||
* This private slot is called when m_ui->abortPushButton is clicked.
|
||||
*/
|
||||
inline void EnterPasswordDialog::abort()
|
||||
{
|
||||
m_password.clear();
|
||||
done(QDialog::Rejected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ENTERPASSWORDDIALOG_H
|
|
@ -0,0 +1,283 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialogs::EnterPasswordDialog</class>
|
||||
<widget class="QDialog" name="Dialogs::EnterPasswordDialog">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Enter the password</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="mainWidget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="instructionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter the password</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="descLabel"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Widgets::ClearLineEdit" name="userNameLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>user name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Widgets::ClearLineEdit" name="password1LineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Widgets::ClearLineEdit" name="password2LineEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>repeat password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="checkboxesWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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="QCheckBox" name="showPasswordCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>show password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="noPwCheckBox">
|
||||
<property name="text">
|
||||
<string>don't use a password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bottomWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="capslockWarningWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="capslockWarningGraphicsView">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: transparent;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="backgroundBrush">
|
||||
<brush brushstyle="NoBrush">
|
||||
<color alpha="0">
|
||||
<red>0</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</property>
|
||||
<property name="sceneRect">
|
||||
<rectf>
|
||||
<x>0.000000000000000</x>
|
||||
<y>0.000000000000000</y>
|
||||
<width>16.000000000000000</width>
|
||||
<height>16.000000000000000</height>
|
||||
</rectf>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="capslockWarningLabel">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-weight: bold;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Capslock is active</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>168</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="abortPushButton">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: none;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Abort</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="window-close">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="confirmPushButton">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: none;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Confirm</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-next">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Widgets::ClearLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header location="global">qtutilities/widgets/clearlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>password1LineEdit</tabstop>
|
||||
<tabstop>password2LineEdit</tabstop>
|
||||
<tabstop>confirmPushButton</tabstop>
|
||||
<tabstop>abortPushButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,71 @@
|
|||
# template
|
||||
TEMPLATE = lib
|
||||
#dirs
|
||||
UI_DIR = ./gui
|
||||
MOC_DIR = ./moc
|
||||
OBJECTS_DIR = ./obj
|
||||
RCC_DIR = ./res
|
||||
# compiler flags
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
QMAKE_LFLAGS += -std=c++11
|
||||
unix {
|
||||
QMAKE_LFLAGS += "-Wl,--rpath=./"
|
||||
}
|
||||
# prefix
|
||||
targetprefix = .
|
||||
# target
|
||||
CONFIG(debug, debug|release) {
|
||||
TARGET = $$targetprefix/$${projectname}d
|
||||
} else {
|
||||
TARGET = $$targetprefix/$$projectname
|
||||
}
|
||||
# variables to check target architecture
|
||||
win32-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch
|
||||
win32-g++-32:QMAKE_TARGET.arch = x86
|
||||
win32-g++-64:QMAKE_TARGET.arch = x86_64
|
||||
linux-g++:QMAKE_TARGET.arch = $$QMAKE_HOST.arch
|
||||
linux-g++-32:QMAKE_TARGET.arch = x86
|
||||
linux-g++-64:QMAKE_TARGET.arch = x86_64
|
||||
# configuration
|
||||
mobile {
|
||||
DEFINES += CONFIG_MOBILE
|
||||
} else:desktop {
|
||||
DEFINES += CONFIG_DESKTOP
|
||||
} else:android {
|
||||
CONFIG += mobile
|
||||
DEFINES += CONFIG_MOBILE
|
||||
} else {
|
||||
CONFIG += desktop
|
||||
DEFINES += CONFIG_DESKTOP
|
||||
}
|
||||
no-gui {
|
||||
QT -= gui
|
||||
DEFINES += GUI_NONE
|
||||
guiqtquick || guiqtwidgets {
|
||||
error("Can not use no-gui with guiqtquick or guiqtwidgets.")
|
||||
} else {
|
||||
message("Configured for no GUI support.")
|
||||
}
|
||||
} else {
|
||||
QT += gui
|
||||
mobile {
|
||||
CONFIG += guiqtquick
|
||||
}
|
||||
desktop {
|
||||
CONFIG += guiqtwidgets
|
||||
}
|
||||
}
|
||||
guiqtquick {
|
||||
message("Configured for Qt Quick GUI support.")
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += quick
|
||||
CONFIG(debug, debug|release) {
|
||||
CONFIG += qml_debug
|
||||
}
|
||||
DEFINES += GUI_QTQUICK
|
||||
}
|
||||
guiqtwidgets {
|
||||
message("Configured for Qt widgets GUI support.")
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
DEFINES += GUI_QTWIDGETS
|
||||
DEFINES += MODEL_UNDO_SUPPORT
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
#include "checklistmodel.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
/*!
|
||||
\namespace Models
|
||||
\brief Provides common models.
|
||||
*/
|
||||
|
||||
namespace Models {
|
||||
|
||||
/*!
|
||||
* \class Models::ChecklistItem
|
||||
* \brief The ChecklistItem class provides an item for use with the ChecklistModel class.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \class Models::ChecklistModel
|
||||
* \brief The ChecklistModel class provides a generic model for storing checkable items.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new checklist model.
|
||||
*/
|
||||
ChecklistModel::ChecklistModel(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
{}
|
||||
|
||||
int ChecklistModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(!parent.isValid()) {
|
||||
return m_items.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Qt::ItemFlags ChecklistModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if(!index.isValid() || index.row() >= m_items.count() || index.model() != this) {
|
||||
return Qt::ItemIsDropEnabled; // allows drops outside the items
|
||||
}
|
||||
return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
||||
}
|
||||
|
||||
QVariant ChecklistModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(index.isValid() && index.row() < m_items.size()) {
|
||||
switch(role) {
|
||||
case Qt::DisplayRole:
|
||||
return m_items.at(index.row()).label();
|
||||
case Qt::CheckStateRole:
|
||||
return m_items.at(index.row()).checkState();
|
||||
case idRole():
|
||||
return m_items.at(index.row()).id();
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QMap<int, QVariant> ChecklistModel::itemData(const QModelIndex &index) const
|
||||
{
|
||||
QMap<int, QVariant> roles;
|
||||
roles.insert(Qt::DisplayRole, data(index, Qt::DisplayRole));
|
||||
roles.insert(Qt::CheckStateRole, data(index, Qt::CheckStateRole));
|
||||
roles.insert(idRole(), data(index, idRole()));
|
||||
return roles;
|
||||
}
|
||||
|
||||
bool ChecklistModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
bool success = false;
|
||||
QVector<int> roles;
|
||||
roles << role;
|
||||
if(index.isValid() && index.row() < m_items.size()) {
|
||||
switch(role) {
|
||||
case Qt::DisplayRole:
|
||||
m_items[index.row()].m_label = value.toString();
|
||||
success = true;
|
||||
break;
|
||||
case Qt::CheckStateRole:
|
||||
if(value.canConvert(QMetaType::Int)) {
|
||||
m_items[index.row()].m_checkState = static_cast<Qt::CheckState>(value.toInt());
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
case idRole(): {
|
||||
m_items[index.row()].m_id = value;
|
||||
success = true;
|
||||
QString label = labelForId(value);
|
||||
if(!label.isEmpty()) {
|
||||
m_items[index.row()].m_label = label;
|
||||
roles << Qt::DisplayRole;
|
||||
}
|
||||
break;
|
||||
} default:
|
||||
;
|
||||
}
|
||||
}
|
||||
if(success) {
|
||||
dataChanged(index, index, roles);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ChecklistModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
|
||||
{
|
||||
for(QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it) {
|
||||
setData(index, it.value(), it.key());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the label for the specified \a id.
|
||||
*
|
||||
* This method might be reimplemented when subclassing to provide labels
|
||||
* for the item IDs.
|
||||
*
|
||||
* If an item's ID is set (using setData() and idRole()) this method is called
|
||||
* to update the item's label as well. If this method returns an empty string
|
||||
* (default behaviour) the item's label will not be updated.
|
||||
*/
|
||||
QString ChecklistModel::labelForId(const QVariant &) const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
Qt::DropActions ChecklistModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::MoveAction;
|
||||
}
|
||||
|
||||
bool ChecklistModel::insertRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (count < 1 || row < 0 || row > rowCount() || parent.isValid()) {
|
||||
return false;
|
||||
}
|
||||
beginInsertRows(QModelIndex(), row, row + count - 1);
|
||||
for(int index = row, end = row + count; index < end; ++index) {
|
||||
m_items.insert(index, ChecklistItem());
|
||||
}
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChecklistModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (count < 1 || row < 0 || (row + count) > rowCount() || parent.isValid()) {
|
||||
return false;
|
||||
}
|
||||
beginRemoveRows(QModelIndex(), row, row + count - 1);
|
||||
for(int index = row, end = row + count; index < end; ++index) {
|
||||
m_items.removeAt(index);
|
||||
}
|
||||
endRemoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the items. Resets the model.
|
||||
*/
|
||||
void ChecklistModel::setItems(const QList<ChecklistItem> &items)
|
||||
{
|
||||
beginResetModel();
|
||||
m_items = items;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restores the IDs and checkstates read from the specified \a settings object.
|
||||
*
|
||||
* The items will be read from the array with the specified \a name.
|
||||
*
|
||||
* Resets the model (current items are cleared).
|
||||
*
|
||||
* Does not restore any labels. Labels are meant to be restored from the ID.
|
||||
*/
|
||||
void ChecklistModel::restore(QSettings &settings, const QString &name)
|
||||
{
|
||||
beginResetModel();
|
||||
auto currentItems = m_items;
|
||||
QList<QVariant> restoredIds;
|
||||
m_items.clear();
|
||||
int rows = settings.beginReadArray(name);
|
||||
m_items.reserve(rows);
|
||||
for(int i = 0; i < rows; ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
QVariant id = settings.value(QStringLiteral("id"));
|
||||
QVariant selected = settings.value(QStringLiteral("selected"));
|
||||
if(!id.isNull() && !selected.isNull() && selected.canConvert(QMetaType::Bool) && !restoredIds.contains(id)) {
|
||||
m_items << ChecklistItem(id, labelForId(id), selected.toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
restoredIds << id;
|
||||
}
|
||||
}
|
||||
settings.endArray();
|
||||
for(const ChecklistItem &item : currentItems) {
|
||||
if(!restoredIds.contains(item.id())) {
|
||||
m_items << item;
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Saves the IDs and checkstates to the specified \a settings object.
|
||||
*
|
||||
* The items will be stored using an array with the specified \a name.
|
||||
*
|
||||
* Does not save any labels.
|
||||
*/
|
||||
void ChecklistModel::save(QSettings &settings, const QString &name) const
|
||||
{
|
||||
settings.beginWriteArray(name, m_items.size());
|
||||
int index = 0;
|
||||
for(const ChecklistItem &item : m_items) {
|
||||
settings.setArrayIndex(index);
|
||||
settings.setValue(QStringLiteral("id"), item.id());
|
||||
settings.setValue(QStringLiteral("selected"), item.isChecked());
|
||||
++index;
|
||||
}
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef CHECKLISTMODEL_H
|
||||
#define CHECKLISTMODEL_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSettings;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Models {
|
||||
|
||||
class ChecklistModel;
|
||||
|
||||
class LIB_EXPORT ChecklistItem
|
||||
{
|
||||
friend class ChecklistModel;
|
||||
|
||||
public:
|
||||
ChecklistItem(const QVariant &id = QVariant(), const QString &label = QString(), Qt::CheckState checked = Qt::Unchecked);
|
||||
|
||||
const QVariant &id() const;
|
||||
const QString &label() const;
|
||||
Qt::CheckState checkState() const;
|
||||
bool isChecked() const;
|
||||
|
||||
private:
|
||||
QVariant m_id;
|
||||
QString m_label;
|
||||
Qt::CheckState m_checkState;
|
||||
};
|
||||
|
||||
inline ChecklistItem::ChecklistItem(const QVariant &id, const QString &label, Qt::CheckState checkState) :
|
||||
m_id(id),
|
||||
m_label(label),
|
||||
m_checkState(checkState)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the ID of the item.
|
||||
*/
|
||||
inline const QVariant &ChecklistItem::id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the label.
|
||||
*/
|
||||
inline const QString &ChecklistItem::label() const
|
||||
{
|
||||
return m_label;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the check state.
|
||||
*/
|
||||
inline Qt::CheckState ChecklistItem::checkState() const
|
||||
{
|
||||
return m_checkState;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the item is checked.
|
||||
*/
|
||||
|
||||
inline bool ChecklistItem::isChecked() const
|
||||
{
|
||||
return m_checkState == Qt::Checked;
|
||||
}
|
||||
|
||||
class LIB_EXPORT ChecklistModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ChecklistModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
QMap<int, QVariant> itemData(const QModelIndex &index) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
|
||||
bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
|
||||
virtual QString labelForId(const QVariant &id) const;
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
bool insertRows(int row, int count, const QModelIndex &parent);
|
||||
bool removeRows(int row, int count, const QModelIndex &parent);
|
||||
const QList<ChecklistItem> &items() const;
|
||||
void setItems(const QList<ChecklistItem> &items);
|
||||
void restore(QSettings &settings, const QString &name);
|
||||
void save(QSettings &settings, const QString &name) const;
|
||||
static inline constexpr int idRole();
|
||||
|
||||
private:
|
||||
QList<ChecklistItem> m_items;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the items.
|
||||
*/
|
||||
inline const QList<ChecklistItem> &ChecklistModel::items() const
|
||||
{
|
||||
return m_items;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the role used to get or set the item ID.
|
||||
*/
|
||||
inline constexpr int ChecklistModel::idRole()
|
||||
{
|
||||
return Qt::UserRole + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CHECKLISTMODEL_H
|
|
@ -0,0 +1,22 @@
|
|||
pkgname=qtutilities
|
||||
pkgver=1.0.4
|
||||
pkgrel=1
|
||||
arch=('i686' 'x86_64')
|
||||
pkgdesc="Collection of Qt related utility classes and functions used by Tageditor, Video downloader and Password manager."
|
||||
license=('GPL')
|
||||
depends=('c++utilities')
|
||||
makedepends=
|
||||
url="http://martchus.netai.net/"
|
||||
source=("$pkgname.tar.gz")
|
||||
md5sums=('cee38afc5eb60b2da4eba64107628ed7')
|
||||
# head end
|
||||
build() {
|
||||
cd $srcdir/$pkgname
|
||||
INSTALL_ROOT=$pkgdir/usr/ qmake-qt5 "$pkgname.pro" -r -spec linux-g++
|
||||
make
|
||||
}
|
||||
|
||||
package() {
|
||||
cd $srcdir/$pkgname
|
||||
make install
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
_name=qtutilities
|
||||
pkgname=mingw-w64-$_name
|
||||
pkgver=1.0.4
|
||||
pkgrel=1
|
||||
arch=('any')
|
||||
pkgdesc="Collection of Qt related utility classes and functions used by Tageditor, Video downloader and Password manager (mingw-w64)."
|
||||
license=('GPL')
|
||||
depends=('mingw-w64-crt' 'mingw-w64-qt5-base' 'mingw-w64-c++utilities')
|
||||
makedepends=('mingw-w64-gcc')
|
||||
url="http://martchus.netai.net/"
|
||||
source=("${_name}.tar.gz")
|
||||
md5sums=('4e94aff9225d8873f752995c1bcc5f15')
|
||||
options=('staticlibs' '!strip')
|
||||
_architectures="i686-w64-mingw32 x86_64-w64-mingw32"
|
||||
# head end
|
||||
build() {
|
||||
cd $srcdir/$_name
|
||||
# build utilities for each architecture
|
||||
for _arch in ${_architectures}; do
|
||||
mkdir -p build-${_arch} && pushd build-${_arch}
|
||||
INSTALL_ROOT=$pkgdir/usr/ ${_arch}-qmake-qt5 -r ../${_name}.pro
|
||||
make
|
||||
popd
|
||||
done
|
||||
}
|
||||
|
||||
package() {
|
||||
cd $srcdir/$_name
|
||||
for _arch in ${_architectures}; do
|
||||
# bin stuff
|
||||
pushd build-${_arch}
|
||||
${_arch}-strip --strip-unneeded ./release/${_name}.dll
|
||||
${_arch}-strip --strip-unneeded ./release/lib${_name}.dll.a
|
||||
install -m755 -D ./release/${_name}.dll $pkgdir/usr/${_arch}/bin/${_name}.dll
|
||||
install -m755 -D ./release/lib${_name}.dll.a $pkgdir/usr/${_arch}/lib/lib${_name}.dll.a
|
||||
popd
|
||||
# include files
|
||||
for dir in aboutdialog enterpassworddialog settingsdialog widgets resources models
|
||||
do
|
||||
mkdir -p $pkgdir/usr/${_arch}/include/${_name}/$dir
|
||||
install -m644 -D ./$dir/*.h $pkgdir/usr/${_arch}/include/${_name}/$dir
|
||||
done
|
||||
done
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
|||
projectname = qtutilities
|
||||
|
||||
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
|
||||
!include(../../common.pri) {
|
||||
!include(./general.pri) {
|
||||
error("Couldn't find the common.pri or the general.pri file!")
|
||||
}
|
||||
}
|
||||
|
||||
QT += core gui
|
||||
|
||||
CONFIG(noplatformspecificcapslockdetection, noplatformspecificcapslockdetection|platformspecificcapslockdetection) {
|
||||
DEFINES -= PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
} else {
|
||||
DEFINES += PLATFORM_SPECIFIC_CAPSLOCK_DETECTION
|
||||
}
|
||||
|
||||
win32 {
|
||||
CONFIG += dll
|
||||
}
|
||||
|
||||
contains(DEFINES, PLATFORM_SPECIFIC_CAPSLOCK_DETECTION) {
|
||||
x11 {
|
||||
LIBS += -lX11
|
||||
}
|
||||
}
|
||||
|
||||
SOURCES += resources/resources.cpp \
|
||||
models/checklistmodel.cpp \
|
||||
resources/qtconfigarguments.cpp
|
||||
|
||||
contains(DEFINES, GUI_QTWIDGETS) {
|
||||
SOURCES += aboutdialog/aboutdialog.cpp \
|
||||
enterpassworddialog/enterpassworddialog.cpp \
|
||||
settingsdialog/optioncategorymodel.cpp \
|
||||
settingsdialog/settingsdialog.cpp \
|
||||
settingsdialog/optionpage.cpp \
|
||||
settingsdialog/optioncategory.cpp \
|
||||
settingsdialog/optioncategoryfiltermodel.cpp \
|
||||
widgets/clearlineedit.cpp \
|
||||
widgets/iconbutton.cpp \
|
||||
widgets/buttonoverlay.cpp \
|
||||
widgets/clearcombobox.cpp \
|
||||
widgets/clearspinbox.cpp \
|
||||
widgets/clearplaintextedit.cpp
|
||||
|
||||
FORMS += aboutdialog/aboutdialog.ui \
|
||||
enterpassworddialog/enterpassworddialog.ui \
|
||||
settingsdialog/settingsdialog.ui
|
||||
}
|
||||
|
||||
HEADERS += resources/resources.h \
|
||||
models/checklistmodel.h \
|
||||
resources/qtconfigarguments.h
|
||||
|
||||
contains(DEFINES, GUI_QTWIDGETS) {
|
||||
HEADERS += aboutdialog/aboutdialog.h \
|
||||
enterpassworddialog/enterpassworddialog.h \
|
||||
settingsdialog/optioncategorymodel.h \
|
||||
settingsdialog/settingsdialog.h \
|
||||
settingsdialog/optioncategory.h \
|
||||
settingsdialog/optionpage.h \
|
||||
settingsdialog/optioncategoryfiltermodel.h \
|
||||
widgets/clearlineedit.h \
|
||||
widgets/iconbutton.h \
|
||||
widgets/buttonoverlay.h \
|
||||
widgets/clearcombobox.h \
|
||||
widgets/clearspinbox.h \
|
||||
widgets/clearplaintextedit.h
|
||||
}
|
||||
|
||||
OTHER_FILES += \
|
||||
pkgbuild/default/PKGBUILD \
|
||||
pkgbuild/mingw-w64/PKGBUILD
|
||||
|
||||
# libs and includepath
|
||||
CONFIG(debug, debug|release) {
|
||||
LIBS += -L../../ -lc++utilitiesd
|
||||
} else {
|
||||
LIBS += -L../../ -lc++utilities
|
||||
}
|
||||
INCLUDEPATH += ../
|
||||
|
||||
RESOURCES += resources/qtutilsicons.qrc
|
||||
|
||||
# installs
|
||||
target.path = $$(INSTALL_ROOT)/lib
|
||||
INSTALLS += target
|
||||
for(dir, $$list(aboutdialog enterpassworddialog models resources settingsdialog widgets)) {
|
||||
eval(inc_$${dir} = $${dir})
|
||||
inc_$${dir}.path = $$(INSTALL_ROOT)/include/$$projectname/$${dir}
|
||||
inc_$${dir}.files = $${dir}/*.h
|
||||
INSTALLS += inc_$${dir}
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 736 B |
Binary file not shown.
After Width: | Height: | Size: 632 B |
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,92 @@
|
|||
#include "qtconfigarguments.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QLocale>
|
||||
#include <QFont>
|
||||
#include <QIcon>
|
||||
#ifdef GUI_QTWIDGETS
|
||||
# include <QApplication>
|
||||
# include <QStyleFactory>
|
||||
#else
|
||||
# include <QGuiApplication>
|
||||
#endif
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ApplicationUtilities {
|
||||
|
||||
QtConfigArguments::QtConfigArguments() :
|
||||
m_qtWidgetsGuiArg("qt-widgets-gui", "g", "shows a Qt widgets based graphical user interface"),
|
||||
m_qtQuickGuiArg("qt-quick-gui", "q", "shows a Qt quick based graphical user interface"),
|
||||
m_lngArg("lang", "l", "sets the language for the Qt GUI"),
|
||||
m_qmlDebuggerArg("qmljsdebugger", "qmljsdebugger", "enables QML debugging (see http://doc.qt.io/qt-5/qtquick-debugging.html)"),
|
||||
m_styleArg("style", string(), "sets the Qt widgets style"),
|
||||
m_iconThemeArg("icon-theme", string(), "sets the icon theme for the Qt GUI"),
|
||||
m_fontArg("font", string(), "sets the font family and size (point) for the Qt GUI")
|
||||
{
|
||||
// language
|
||||
m_lngArg.setValueNames({"language"});
|
||||
m_lngArg.setRequiredValueCount(1);
|
||||
m_lngArg.setRequired(false);
|
||||
m_lngArg.setCallback([] (const StringVector &values) {
|
||||
QLocale::setDefault(QLocale(QString::fromLocal8Bit(values.front().c_str())));
|
||||
});
|
||||
// qml debugger (handled by Qt, just to let the parser know of it)
|
||||
m_qmlDebuggerArg.setValueNames({"port:<port_from>[,port_to][,host:<ip address>][,block]"});
|
||||
m_qmlDebuggerArg.setRequiredValueCount(1);
|
||||
// appearance
|
||||
m_styleArg.setValueNames({"style name"});
|
||||
m_styleArg.setRequiredValueCount(1);
|
||||
m_styleArg.setCallback([] (const StringVector &values) {
|
||||
#ifdef GUI_QTWIDGETS
|
||||
if(QStyle *style = QStyleFactory::create(QString::fromLocal8Bit(values.front().c_str()))) {
|
||||
QApplication::setStyle(style);
|
||||
} else {
|
||||
cout << "Warning: Can not find the specified style." << endl;
|
||||
}
|
||||
#endif
|
||||
#ifdef GUI_QTQUICK
|
||||
Q_UNUSED(values)
|
||||
cout << "Warning: Can not set a style for the Qt Quick GUI." << endl;
|
||||
#endif
|
||||
});
|
||||
m_iconThemeArg.setValueNames({"theme name"});
|
||||
m_iconThemeArg.setRequiredValueCount(1);
|
||||
m_iconThemeArg.setCallback([] (const StringVector &values) {
|
||||
QIcon::setThemeName(QString::fromLocal8Bit(values.front().c_str()));
|
||||
});
|
||||
m_fontArg.setValueNames({"name", "size"});
|
||||
m_fontArg.setRequiredValueCount(2);
|
||||
m_fontArg.setDefault(true);
|
||||
#ifdef Q_OS_WIN32
|
||||
m_fontArg.setDefaultValues({"Segoe UI", "9"});
|
||||
#else
|
||||
m_fontArg.setDefaultValues({string(), string()});
|
||||
#endif
|
||||
m_fontArg.setCallback([] (const StringVector &values) {
|
||||
if(!values.front().empty()) {
|
||||
QFont font;
|
||||
font.setFamily(QString::fromLocal8Bit(values.front().c_str()));
|
||||
bool ok;
|
||||
int size = QString::fromLocal8Bit(values.back().c_str()).toInt(&ok);
|
||||
if(ok) {
|
||||
font.setPointSize(size);
|
||||
} else {
|
||||
cout << "Warning: Can not parse specified font size. It will be ignored." << endl;
|
||||
}
|
||||
QGuiApplication::setFont(font);
|
||||
}
|
||||
});
|
||||
m_qtWidgetsGuiArg.setSecondaryArguments({&m_lngArg, &m_qmlDebuggerArg, &m_styleArg, &m_iconThemeArg, &m_fontArg});
|
||||
m_qtQuickGuiArg.setSecondaryArguments({&m_lngArg, &m_qmlDebuggerArg, &m_iconThemeArg, &m_fontArg});
|
||||
#if defined GUI_QTWIDGETS
|
||||
m_qtWidgetsGuiArg.setDefault(true);
|
||||
#elif defined GUI_QTQUICK
|
||||
m_qtQuickGuiArg.setDefault(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef QTCONFIGARGUMENTS_H
|
||||
#define QTCONFIGARGUMENTS_H
|
||||
|
||||
#include <c++utilities/application/argumentparser.h>
|
||||
|
||||
namespace ApplicationUtilities {
|
||||
|
||||
class LIB_EXPORT QtConfigArguments
|
||||
{
|
||||
public:
|
||||
QtConfigArguments();
|
||||
|
||||
Argument &qtWidgetsGuiArg();
|
||||
Argument &qtQuickGuiArg();
|
||||
Argument &languageArg();
|
||||
|
||||
bool areQtGuiArgsPresent() const;
|
||||
|
||||
private:
|
||||
Argument m_qtWidgetsGuiArg;
|
||||
Argument m_qtQuickGuiArg;
|
||||
Argument m_lngArg;
|
||||
Argument m_qmlDebuggerArg;
|
||||
Argument m_styleArg;
|
||||
Argument m_iconThemeArg;
|
||||
Argument m_fontArg;
|
||||
};
|
||||
|
||||
inline Argument &QtConfigArguments::qtWidgetsGuiArg()
|
||||
{
|
||||
return m_qtWidgetsGuiArg;
|
||||
}
|
||||
|
||||
inline Argument &QtConfigArguments::qtQuickGuiArg()
|
||||
{
|
||||
return m_qtQuickGuiArg;
|
||||
}
|
||||
|
||||
inline Argument &QtConfigArguments::languageArg()
|
||||
{
|
||||
return m_lngArg;
|
||||
}
|
||||
|
||||
inline bool QtConfigArguments::areQtGuiArgsPresent() const
|
||||
{
|
||||
return m_qtWidgetsGuiArg.isPresent() || m_qtQuickGuiArg.isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // QTCONFIGARGUMENTS_H
|
||||
|
||||
#ifdef QT_CONFIG_ARGUMENTS
|
||||
#undef QT_CONFIG_ARGUMENTS
|
||||
#endif
|
||||
#define QT_CONFIG_ARGUMENTS ApplicationUtilities::QtConfigArguments
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/qtutilities">
|
||||
<file>icons/hicolor/16x16/actions/edit-clear.png</file>
|
||||
<file>icons/hicolor/16x16/actions/edit-menu.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,129 @@
|
|||
#include "resources.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
#include <QLibraryInfo>
|
||||
#if defined(GUI_QTWIDGETS)
|
||||
# include <QApplication>
|
||||
# include <QIcon>
|
||||
# include <QFont>
|
||||
# include <QStyleFactory>
|
||||
#elif defined(GUI_QTQUICK)
|
||||
# include <QGuiApplication>
|
||||
# include <QIcon>
|
||||
# include <QFont>
|
||||
#else
|
||||
# include <QCoreApplication>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void qInitResources_qtutilsicons();
|
||||
void qCleanupResources_qtutilsicons();
|
||||
|
||||
namespace QtUtilitiesResources {
|
||||
|
||||
/*!
|
||||
* \brief Initiates the resources used and provided by this library.
|
||||
*/
|
||||
void init()
|
||||
{
|
||||
qInitResources_qtutilsicons();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Frees the resources used and provided by this library.
|
||||
*/
|
||||
void cleanup()
|
||||
{
|
||||
qCleanupResources_qtutilsicons();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace TranslationFiles {
|
||||
|
||||
/*!
|
||||
* \brief Loads and installs the appropriate Qt translation file.
|
||||
*/
|
||||
void loadQtTranslationFile()
|
||||
{
|
||||
QLocale locale;
|
||||
if(locale.language() != QLocale::English) {
|
||||
QTranslator *qtTranslator = new QTranslator;
|
||||
if(qtTranslator->load(QStringLiteral("qt_%1").arg(locale.name()),
|
||||
QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||
QCoreApplication::installTranslator(qtTranslator);
|
||||
} else {
|
||||
cout << "Unable to load Qt translation file for the language " << locale.name().toStdString() << "." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Loads and installs the appropriate application translation file.
|
||||
* \param applicationName Specifies the name of the application.
|
||||
* \remarks Translation files have to be placed in one of the following
|
||||
* locations:
|
||||
* - /usr/share/$application/translations
|
||||
* - ./translations
|
||||
* Translation files must be named using the following scheme:
|
||||
* - $application_$language.qm
|
||||
*/
|
||||
void loadApplicationTranslationFile(const QString &applicationName)
|
||||
{
|
||||
QLocale locale;
|
||||
QTranslator *appTranslator = new QTranslator;
|
||||
QString fileName = QStringLiteral("%1_%2").arg(applicationName, locale.name());
|
||||
if(appTranslator->load(fileName, QStringLiteral("./translations"))) {
|
||||
QCoreApplication::installTranslator(appTranslator);
|
||||
} else if(appTranslator->load(fileName, QStringLiteral("/usr/share/%1/translations").arg(applicationName))) {
|
||||
QCoreApplication::installTranslator(appTranslator);
|
||||
} else {
|
||||
cout << "Unable to load application translation file for the language " << locale.name().toStdString() << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Theme {
|
||||
|
||||
/*!
|
||||
* \brief Sets the default icon theme.
|
||||
*/
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
void setup()
|
||||
{
|
||||
if(QIcon::themeName().isEmpty()) {
|
||||
QIcon::setThemeName(QStringLiteral("oxygen"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
namespace ApplicationInstances {
|
||||
|
||||
#if defined(GUI_QTWIDGETS)
|
||||
bool hasWidgetsApp()
|
||||
{
|
||||
return qobject_cast<QApplication*>(QCoreApplication::instance()) != nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
bool hasGuiApp()
|
||||
{
|
||||
return qobject_cast<QGuiApplication*>(QCoreApplication::instance()) != nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasCoreApp()
|
||||
{
|
||||
return qobject_cast<QCoreApplication*>(QCoreApplication::instance()) != nullptr;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QString;
|
||||
class QStringList;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QtUtilitiesResources {
|
||||
|
||||
LIB_EXPORT void init();
|
||||
LIB_EXPORT void cleanup();
|
||||
|
||||
}
|
||||
|
||||
namespace TranslationFiles {
|
||||
|
||||
LIB_EXPORT void loadQtTranslationFile();
|
||||
LIB_EXPORT void loadApplicationTranslationFile(const QString &applicationName);
|
||||
|
||||
}
|
||||
|
||||
namespace Theme {
|
||||
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
LIB_EXPORT void setup();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
namespace ApplicationInstances {
|
||||
|
||||
#if defined(GUI_QTWIDGETS)
|
||||
LIB_EXPORT bool hasWidgetsApp();
|
||||
#endif
|
||||
#if defined(GUI_QTWIDGETS) || defined(GUI_QTQUICK)
|
||||
LIB_EXPORT bool hasGuiApp();
|
||||
#endif
|
||||
LIB_EXPORT bool hasCoreApp();
|
||||
|
||||
}
|
||||
|
||||
#endif // RESOURCES_H
|
|
@ -0,0 +1,92 @@
|
|||
#include "optioncategory.h"
|
||||
#include "optionpage.h"
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::OptionCategory
|
||||
* \brief The OptionCategory class wraps associated option pages.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a option category.
|
||||
*/
|
||||
OptionCategory::OptionCategory(QObject *parent) :
|
||||
QObject(parent)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the option category.
|
||||
*/
|
||||
OptionCategory::~OptionCategory()
|
||||
{
|
||||
qDeleteAll(m_pages);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies all pages.
|
||||
* \sa OptionPage::apply()
|
||||
*/
|
||||
bool OptionCategory::applyAllPages()
|
||||
{
|
||||
foreach(OptionPage *page, m_pages) {
|
||||
if(!page->apply()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets all pages.
|
||||
* \sa OptionPage::reset()
|
||||
*/
|
||||
void OptionCategory::resetAllPages()
|
||||
{
|
||||
foreach(OptionPage *page, m_pages) {
|
||||
page->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the option category matches the specified \a searchKeyWord.
|
||||
*/
|
||||
bool OptionCategory::matches(const QString &searchKeyWord) const
|
||||
{
|
||||
foreach(OptionPage *page, m_pages) {
|
||||
if(page->matches(searchKeyWord)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the specified \a pages to the category.
|
||||
*
|
||||
* Previously assigned pages get deleted. The pagesChanged() signal is emitted.
|
||||
* The category takes ownership over the given \a pages.
|
||||
*/
|
||||
void OptionCategory::assignPages(const QList<OptionPage *> pages)
|
||||
{
|
||||
qDeleteAll(m_pages);
|
||||
m_pages = pages;
|
||||
emit pagesChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \fn OptionCategory::displayNameChanged()
|
||||
* \brief Emitted when the display name changed.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn OptionCategory::iconChanged()
|
||||
* \brief Emitted when the icon changed.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn OptionCategory::pagesChanged()
|
||||
* \brief Emitted when the pages changed.
|
||||
*/
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef OPTIONSCATEGORY_H
|
||||
#define OPTIONSCATEGORY_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
#include <QList>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class OptionPage;
|
||||
|
||||
class LIB_EXPORT OptionCategory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY iconChanged)
|
||||
Q_PROPERTY(QList<OptionPage *> pages READ pages WRITE assignPages NOTIFY pagesChanged)
|
||||
|
||||
public:
|
||||
explicit OptionCategory(QObject *parent = nullptr);
|
||||
virtual ~OptionCategory();
|
||||
|
||||
const QString &displayName() const;
|
||||
void setDisplayName(const QString &displayName);
|
||||
const QIcon &icon() const;
|
||||
void setIcon(const QIcon &icon);
|
||||
const QList<OptionPage *> pages() const;
|
||||
void assignPages(const QList<OptionPage *> pages);
|
||||
bool applyAllPages();
|
||||
void resetAllPages();
|
||||
bool matches(const QString &searchKeyWord) const;
|
||||
|
||||
signals:
|
||||
void displayNameChanged();
|
||||
void iconChanged();
|
||||
void pagesChanged();
|
||||
|
||||
private:
|
||||
QString m_displayName;
|
||||
QIcon m_icon;
|
||||
QList<OptionPage *> m_pages;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the display name of the category.
|
||||
*/
|
||||
inline const QString &OptionCategory::displayName() const
|
||||
{
|
||||
return m_displayName;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the display name of the category.
|
||||
*/
|
||||
inline void OptionCategory::setDisplayName(const QString &displayName)
|
||||
{
|
||||
m_displayName = displayName;
|
||||
emit displayNameChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the icon of the category.
|
||||
*/
|
||||
inline const QIcon &OptionCategory::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the icon of the category.
|
||||
*/
|
||||
inline void OptionCategory::setIcon(const QIcon &icon)
|
||||
{
|
||||
m_icon = icon;
|
||||
emit iconChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the assigned pages.
|
||||
*/
|
||||
inline const QList<OptionPage *> OptionCategory::pages() const
|
||||
{
|
||||
return m_pages;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // OPTIONSCATEGORY_H
|
|
@ -0,0 +1,31 @@
|
|||
#include "optioncategoryfiltermodel.h"
|
||||
#include "optioncategorymodel.h"
|
||||
#include "optioncategory.h"
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::OptionCategoryFilterModel
|
||||
* \brief The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an option category filter model.
|
||||
*/
|
||||
OptionCategoryFilterModel::OptionCategoryFilterModel(QObject *parent) :
|
||||
QSortFilterProxyModel(parent)
|
||||
{}
|
||||
|
||||
bool OptionCategoryFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent))
|
||||
return true;
|
||||
if(OptionCategoryModel *model = qobject_cast<OptionCategoryModel *>(sourceModel())) {
|
||||
if(OptionCategory *category = model->category(sourceRow)) {
|
||||
return category->matches(filterRegExp().pattern());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef OPTIONCATEGORYFILTERMODEL_H
|
||||
#define OPTIONCATEGORYFILTERMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class OptionCategoryFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OptionCategoryFilterModel(QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // OPTIONCATEGORYFILTERMODEL_H
|
|
@ -0,0 +1,108 @@
|
|||
#include "optioncategorymodel.h"
|
||||
#include "optioncategory.h"
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::OptionCategoryModel
|
||||
* \brief The OptionCategoryModel class is used by SettingsDialog to store and display option categories.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an option category model.
|
||||
*/
|
||||
OptionCategoryModel::OptionCategoryModel(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Constructs an option category model with the specified \a categories.
|
||||
*
|
||||
* The model takes ownership over the given categories.
|
||||
*/
|
||||
OptionCategoryModel::OptionCategoryModel(const QList<Dialogs::OptionCategory *> &categories, QObject *parent) :
|
||||
QAbstractListModel(parent),
|
||||
m_categories(categories)
|
||||
{
|
||||
foreach(OptionCategory *category, m_categories) {
|
||||
category->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the option category model.
|
||||
*/
|
||||
OptionCategoryModel::~OptionCategoryModel()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Sets the \a categories for the model.
|
||||
*
|
||||
* The model takes ownership over the given \a categories.
|
||||
*/
|
||||
void OptionCategoryModel::setCategories(const QList<OptionCategory *> categories)
|
||||
{
|
||||
beginResetModel();
|
||||
qDeleteAll(m_categories);
|
||||
m_categories = categories;
|
||||
foreach(OptionCategory *category, m_categories) {
|
||||
category->setParent(this);
|
||||
connect(category, &OptionCategory::displayNameChanged, this, &OptionCategoryModel::categoryChangedName);
|
||||
connect(category, &OptionCategory::iconChanged, this, &OptionCategoryModel::categoryChangedIcon);
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int OptionCategoryModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_categories.size();
|
||||
}
|
||||
|
||||
QVariant OptionCategoryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(index.isValid() && index.row() < m_categories.size()) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return m_categories.at(index.row())->displayName();
|
||||
case Qt::DecorationRole: {
|
||||
QIcon icon = m_categories.at(index.row())->icon();
|
||||
if(!icon.isNull()) {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handles the change of name of a category.
|
||||
*/
|
||||
void OptionCategoryModel::categoryChangedName()
|
||||
{
|
||||
if(OptionCategory *senderCategory = qobject_cast<OptionCategory *>(QObject::sender())) {
|
||||
for(int i = 0, end = m_categories.size(); i < end; ++i) {
|
||||
if(senderCategory == m_categories.at(i)) {
|
||||
QModelIndex index = this->index(i);
|
||||
emit dataChanged(index, index, QVector<int>() << Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handles the a changed icon of a category.
|
||||
*/
|
||||
void OptionCategoryModel::categoryChangedIcon()
|
||||
{
|
||||
if(OptionCategory *senderCategory = qobject_cast<OptionCategory *>(QObject::sender())) {
|
||||
for(int i = 0, end = m_categories.size(); i < end; ++i) {
|
||||
if(senderCategory == m_categories.at(i)) {
|
||||
QModelIndex index = this->index(i);
|
||||
emit dataChanged(index, index, QVector<int>() << Qt::DecorationRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef OPTIONCATEGORYMODEL_H
|
||||
#define OPTIONCATEGORYMODEL_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QAbstractListModel>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class OptionPage;
|
||||
class OptionCategory;
|
||||
|
||||
class LIB_EXPORT OptionCategoryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OptionCategoryModel(QObject *parent = nullptr);
|
||||
explicit OptionCategoryModel(const QList<OptionCategory *> &categories, QObject *parent = nullptr);
|
||||
virtual ~OptionCategoryModel();
|
||||
|
||||
const QList<OptionCategory *> &categories() const;
|
||||
OptionCategory *category(const QModelIndex &index) const;
|
||||
OptionCategory *category(int row) const;
|
||||
void setCategories(const QList<OptionCategory *> categories);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
private slots:
|
||||
void categoryChangedName();
|
||||
void categoryChangedIcon();
|
||||
|
||||
private:
|
||||
QList<OptionCategory *> m_categories;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the categories.
|
||||
* \sa OptionCategoryModel::category()
|
||||
* \sa OptionCategoryModel::setCategories()
|
||||
*/
|
||||
inline const QList<OptionCategory *> &OptionCategoryModel::categories() const
|
||||
{
|
||||
return m_categories;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the category for the specified model \a index.
|
||||
* \sa OptionCategoryModel::categories()
|
||||
* \sa OptionCategoryModel::setCategories()
|
||||
*/
|
||||
inline OptionCategory *OptionCategoryModel::category(const QModelIndex &index) const
|
||||
{
|
||||
return (index.isValid())
|
||||
? category(index.row())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the category for the specified \a row.
|
||||
* \sa OptionCategoryModel::categories()
|
||||
* \sa OptionCategoryModel::setCategories()
|
||||
*/
|
||||
inline OptionCategory *OptionCategoryModel::category(int row) const
|
||||
{
|
||||
return row < m_categories.size() ? m_categories.at(row) : nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // OPTIONCATEGORYMODEL_H
|
|
@ -0,0 +1,109 @@
|
|||
#include "optionpage.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QCheckBox>
|
||||
#include <QRadioButton>
|
||||
#include <QPushButton>
|
||||
#include <QGroupBox>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::OptionPage
|
||||
* \brief The OptionPage class is the base class for SettingsDialog pages.
|
||||
*
|
||||
* The specified \a parentWindow might be used by some implementations as parent when showing dialogs.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a option page.
|
||||
*/
|
||||
OptionPage::OptionPage(QWidget *parentWindow) :
|
||||
m_parentWindow(parentWindow),
|
||||
m_shown(false),
|
||||
m_keywordsInitialized(false)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the option page.
|
||||
*/
|
||||
OptionPage::~OptionPage()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the widget for the option page.
|
||||
*
|
||||
* If the widget has not been constructed yet, a new widget will be
|
||||
* constructed using the OptionPage::setupWidget() method and the
|
||||
* current configuration is applied.
|
||||
*
|
||||
* The option page keeps ownership over the returned widget.
|
||||
*/
|
||||
QWidget *OptionPage::widget()
|
||||
{
|
||||
if(!m_widget) {
|
||||
m_widget.reset(setupWidget()); // ensure widget has been created
|
||||
}
|
||||
if(!m_shown) {
|
||||
m_shown = true;
|
||||
reset(); // show current configuration if not shown yet
|
||||
}
|
||||
return m_widget.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the pages matches the specified
|
||||
* \a searchKeyWord.
|
||||
*/
|
||||
bool OptionPage::matches(const QString &searchKeyWord)
|
||||
{
|
||||
if(searchKeyWord.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if(displayName().contains(searchKeyWord, Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
if(!m_keywordsInitialized) {
|
||||
if(!m_widget) {
|
||||
m_widget.reset(setupWidget()); // ensure widget has been created
|
||||
}
|
||||
// find common subwidgets
|
||||
foreach (const QLabel *label, m_widget->findChildren<QLabel *>())
|
||||
m_keywords << label->text();
|
||||
foreach (const QCheckBox *checkbox, m_widget->findChildren<QCheckBox *>())
|
||||
m_keywords << checkbox->text();
|
||||
foreach (const QRadioButton *checkbox, m_widget->findChildren<QRadioButton *>())
|
||||
m_keywords << checkbox->text();
|
||||
foreach (const QPushButton *pushButton, m_widget->findChildren<QPushButton *>())
|
||||
m_keywords << pushButton->text();
|
||||
foreach (const QGroupBox *groupBox, m_widget->findChildren<QGroupBox *>())
|
||||
m_keywords << groupBox->title();
|
||||
m_keywordsInitialized = true;
|
||||
}
|
||||
foreach (const QString &keyword, m_keywords)
|
||||
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \fn OptionPage::displayName()
|
||||
* \brief Returns the display name of the page.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn OptionPage::apply()
|
||||
* \brief Applies altered settings.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn OptionPage::reset()
|
||||
* \brief Discards altered settings and resets relevant widgets.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn OptionPage::setupWidget()
|
||||
* \brief Creates the widget for the page. Called in the first invocation of widget().
|
||||
*/
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#ifndef OPTIONSPAGE_H
|
||||
#define OPTIONSPAGE_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class LIB_EXPORT OptionPage
|
||||
{
|
||||
public:
|
||||
explicit OptionPage(QWidget *parentWindow = nullptr);
|
||||
virtual ~OptionPage();
|
||||
|
||||
QWidget *parentWindow() const;
|
||||
virtual QString displayName() const = 0;
|
||||
QWidget *widget();
|
||||
bool hasBeenShown() const;
|
||||
virtual bool apply() = 0;
|
||||
virtual void reset() = 0;
|
||||
bool matches(const QString &searchKeyWord);
|
||||
|
||||
protected:
|
||||
virtual QWidget *setupWidget() = 0;
|
||||
|
||||
private:
|
||||
std::unique_ptr<QWidget> m_widget;
|
||||
QWidget *m_parentWindow;
|
||||
bool m_shown;
|
||||
bool m_keywordsInitialized;
|
||||
QStringList m_keywords;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the parent window of the option page.
|
||||
*/
|
||||
inline QWidget *OptionPage::parentWindow() const
|
||||
{
|
||||
return m_parentWindow;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an indication whether the option page has been shown yet.
|
||||
*/
|
||||
inline bool OptionPage::hasBeenShown() const
|
||||
{
|
||||
return m_widget != nullptr && m_shown;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \class Dialogs::UiFileBasedOptionPage
|
||||
* \brief The UiFileBasedOptionPage class is the base class for SettingsDialog pages using UI files
|
||||
* to describe the widget tree.
|
||||
*
|
||||
* \tparam UiClass Specifies the UI class generated by uic.
|
||||
*/
|
||||
template <class UiClass>
|
||||
class LIB_EXPORT UiFileBasedOptionPage : public OptionPage
|
||||
{
|
||||
public:
|
||||
explicit UiFileBasedOptionPage(QWidget *parentWindow = nullptr);
|
||||
virtual ~UiFileBasedOptionPage();
|
||||
|
||||
virtual QString displayName() const = 0;
|
||||
virtual bool apply() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
protected:
|
||||
virtual QWidget *setupWidget();
|
||||
UiClass *ui();
|
||||
|
||||
private:
|
||||
std::unique_ptr<UiClass> m_ui;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new UI file based option page.
|
||||
*/
|
||||
template <class UiClass>
|
||||
UiFileBasedOptionPage<UiClass>::UiFileBasedOptionPage(QWidget *parentWindow) :
|
||||
OptionPage(parentWindow)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the option page.
|
||||
*/
|
||||
template <class UiClass>
|
||||
UiFileBasedOptionPage<UiClass>::~UiFileBasedOptionPage()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Sets up the widget for the option page using the UI class.
|
||||
*/
|
||||
template <class UiClass>
|
||||
QWidget *UiFileBasedOptionPage<UiClass>::setupWidget()
|
||||
{
|
||||
QWidget *widget = new QWidget();
|
||||
if(!m_ui) {
|
||||
m_ui.reset(new UiClass);
|
||||
}
|
||||
m_ui->setupUi(widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
template <class UiClass>
|
||||
inline UiClass *UiFileBasedOptionPage<UiClass>::ui()
|
||||
{
|
||||
return m_ui.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // OPTIONSPAGE_H
|
|
@ -0,0 +1,214 @@
|
|||
#include "settingsdialog.h"
|
||||
#include "ui_settingsdialog.h"
|
||||
#include "optioncategorymodel.h"
|
||||
#include "optioncategoryfiltermodel.h"
|
||||
#include "optioncategory.h"
|
||||
#include "optionpage.h"
|
||||
|
||||
#include <QItemSelectionModel>
|
||||
#include <QShowEvent>
|
||||
#include <QScrollArea>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
/*!
|
||||
* \class Dialogs::SettingsDialog
|
||||
* \brief The SettingsDialog class provides a framework for creating settings dialogs with different categories and subcategories.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a settings dialog.
|
||||
* \param parent Specifies the parent widget.
|
||||
*/
|
||||
SettingsDialog::SettingsDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_ui(new Ui::SettingsDialog),
|
||||
m_categoryModel(new OptionCategoryModel(this)),
|
||||
m_categoryFilterModel(new OptionCategoryFilterModel(this)),
|
||||
m_currentCategory(nullptr),
|
||||
m_tabBarAlwaysVisible(true)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
#ifdef Q_OS_WIN32
|
||||
setStyleSheet(QStringLiteral("* { font: 9pt \"Segoe UI\"; } #mainWidget { color: black; background-color: white; border: none; } #bottomWidget { background-color: #F0F0F0; border-top: 1px solid #DFDFDF; } QMessageBox QLabel, QInputDialog QLabel, #instructionLabel {font-size: 12pt; color: #003399; }"));
|
||||
#else
|
||||
setStyleSheet(QStringLiteral("#instructionLabel { font-weight: bold; font-size: 12pt; }"));
|
||||
#endif
|
||||
// setup models
|
||||
m_categoryFilterModel->setSourceModel(m_categoryModel);
|
||||
m_ui->categoriesListView->setModel(m_categoryFilterModel);
|
||||
// connect signals and slots
|
||||
// selection models
|
||||
connect(m_ui->categoriesListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &SettingsDialog::currentCategoryChanged);
|
||||
// buttons
|
||||
connect(m_ui->abortPushButton, &QPushButton::clicked, this, &SettingsDialog::reject);
|
||||
connect(m_ui->applyPushButton, &QPushButton::clicked, this, &SettingsDialog::apply);
|
||||
connect(m_ui->okPushButton, &QPushButton::clicked, this, &SettingsDialog::accept);
|
||||
// dialog
|
||||
connect(this, &SettingsDialog::accepted, this, &SettingsDialog::apply);
|
||||
connect(this, &SettingsDialog::rejected, this, &SettingsDialog::reset);
|
||||
// misc
|
||||
connect(m_ui->filterLineEdit, &QLineEdit::textChanged, m_categoryFilterModel, &OptionCategoryFilterModel::setFilterFixedString);
|
||||
connect(m_ui->filterLineEdit, &QLineEdit::textChanged, this, &SettingsDialog::updateTabWidget);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the settings dialog.
|
||||
*/
|
||||
SettingsDialog::~SettingsDialog()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether the tab bar is always visible.
|
||||
*
|
||||
* \sa SettingsDialog::isTabBarAlwaysVisible()
|
||||
*/
|
||||
void SettingsDialog::setTabBarAlwaysVisible(bool value)
|
||||
{
|
||||
m_tabBarAlwaysVisible = value;
|
||||
if(m_currentCategory) {
|
||||
m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the category for the specified \a categoryIndex.
|
||||
*
|
||||
* The settings dialog keeps ownership over the returned category.
|
||||
* If no category exists for the specified index a null pointer is returned.
|
||||
*/
|
||||
OptionCategory *SettingsDialog::category(int categoryIndex) const
|
||||
{
|
||||
return m_categoryModel->category(categoryIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the page for the specified \a categoryIndex and the specified \a pageIndex.
|
||||
*
|
||||
* The settings dialog keeps ownership over the returned category.
|
||||
* If no page for the specified indices a null pointer is returned.
|
||||
*/
|
||||
OptionPage *SettingsDialog::page(int categoryIndex, int pageIndex) const
|
||||
{
|
||||
if(OptionCategory *category = this->category(categoryIndex)) {
|
||||
if(pageIndex < category->pages().length()) {
|
||||
return category->pages()[pageIndex];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets all pages before the dialog is shown by the application.
|
||||
*/
|
||||
void SettingsDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
if(!event->spontaneous()) {
|
||||
foreach(OptionCategory *category, m_categoryModel->categories()) {
|
||||
foreach(OptionPage *page, category->pages()) {
|
||||
page->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Shows the selected category specified by its model \a index in the category model.
|
||||
*
|
||||
* This private slot is called when m_ui->categoriesListView->selectionModel()->currentChanged() is emitted.
|
||||
*/
|
||||
void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
|
||||
{
|
||||
showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the current category to the specified \a category and updates the relevant widgets to show it.
|
||||
*/
|
||||
void SettingsDialog::showCategory(OptionCategory *category)
|
||||
{
|
||||
if(category) {
|
||||
if(m_currentCategory != category) {
|
||||
m_currentCategory = category;
|
||||
m_ui->instructionLabel->setText(category->displayName());
|
||||
}
|
||||
} else {
|
||||
m_currentCategory = nullptr;
|
||||
m_ui->instructionLabel->setText(tr("No category selected"));
|
||||
}
|
||||
updateTabWidget();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the tab widget to show the pages for the current category.
|
||||
*/
|
||||
void SettingsDialog::updateTabWidget()
|
||||
{
|
||||
if(m_currentCategory) {
|
||||
m_ui->pagesTabWidget->setUpdatesEnabled(false);
|
||||
QString searchKeyWord = m_ui->filterLineEdit->text();
|
||||
int index = 0;
|
||||
foreach(OptionPage *page, m_currentCategory->pages()) {
|
||||
if(page->matches(searchKeyWord)) {
|
||||
QScrollArea *scrollArea;
|
||||
if(index < m_ui->pagesTabWidget->count()) {
|
||||
scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
|
||||
scrollArea->takeWidget();
|
||||
m_ui->pagesTabWidget->setTabText(index, page->displayName());
|
||||
} else {
|
||||
scrollArea = new QScrollArea(m_ui->pagesTabWidget);
|
||||
scrollArea->setFrameStyle(QFrame::NoFrame);
|
||||
scrollArea->setBackgroundRole(QPalette::Base);
|
||||
scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
m_ui->pagesTabWidget->addTab(scrollArea, page->displayName());
|
||||
}
|
||||
if(page->widget()->layout()) {
|
||||
page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
}
|
||||
scrollArea->setWidget(page->widget());
|
||||
}
|
||||
++index;
|
||||
}
|
||||
while(index < m_ui->pagesTabWidget->count()) {
|
||||
QScrollArea *scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
|
||||
scrollArea->takeWidget();
|
||||
m_ui->pagesTabWidget->removeTab(index);
|
||||
delete scrollArea;
|
||||
}
|
||||
m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
|
||||
m_ui->pagesTabWidget->setUpdatesEnabled(true);
|
||||
} else {
|
||||
m_ui->pagesTabWidget->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies all changes. Calls OptionCategory::applyAllPages() for each category.
|
||||
*/
|
||||
bool SettingsDialog::apply()
|
||||
{
|
||||
foreach(OptionCategory *category, m_categoryModel->categories()) {
|
||||
foreach(OptionPage *page, category->pages()) {
|
||||
if(!page->apply()) {
|
||||
return false;
|
||||
}
|
||||
category->applyAllPages();
|
||||
}
|
||||
}
|
||||
emit applied();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets all changes. Calls OptionCategory::resetAllPages() for each category.
|
||||
*/
|
||||
void SettingsDialog::reset()
|
||||
{
|
||||
foreach(OptionCategory *category, m_categoryModel->categories()) {
|
||||
category->resetAllPages();
|
||||
}
|
||||
emit resetted();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef QT_UTILITIES_SETTINGSDIALOG_H
|
||||
#define QT_UTILITIES_SETTINGSDIALOG_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class OptionCategoryModel;
|
||||
class OptionCategoryFilterModel;
|
||||
class OptionCategory;
|
||||
class OptionPage;
|
||||
|
||||
namespace Ui {
|
||||
class SettingsDialog;
|
||||
}
|
||||
|
||||
class LIB_EXPORT SettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isTabBarAlwaysVisible READ isTabBarAlwaysVisible WRITE setTabBarAlwaysVisible)
|
||||
|
||||
public:
|
||||
explicit SettingsDialog(QWidget *parent = nullptr);
|
||||
virtual ~SettingsDialog();
|
||||
bool isTabBarAlwaysVisible() const;
|
||||
void setTabBarAlwaysVisible(bool value);
|
||||
OptionCategoryModel *categoryModel();
|
||||
OptionCategory *category(int categoryIndex) const;
|
||||
OptionPage *page(int categoryIndex, int pageIndex) const;
|
||||
|
||||
signals:
|
||||
void applied();
|
||||
void resetted();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event);
|
||||
|
||||
private slots:
|
||||
void currentCategoryChanged(const QModelIndex &index);
|
||||
void updateTabWidget();
|
||||
|
||||
bool apply();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
void showCategory(OptionCategory *category);
|
||||
|
||||
std::unique_ptr<Ui::SettingsDialog> m_ui;
|
||||
OptionCategoryModel *m_categoryModel;
|
||||
OptionCategoryFilterModel *m_categoryFilterModel;
|
||||
OptionCategory *m_currentCategory;
|
||||
bool m_tabBarAlwaysVisible;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the tab bar is always visible.
|
||||
*
|
||||
* The tab bar is always visible by default.
|
||||
*
|
||||
* \sa SettingsDialog::setTabBarAlwaysVisible()
|
||||
*/
|
||||
inline bool SettingsDialog::isTabBarAlwaysVisible() const
|
||||
{
|
||||
return m_tabBarAlwaysVisible;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the category model used by the settings dialog to manage the categories.
|
||||
*/
|
||||
inline OptionCategoryModel *SettingsDialog::categoryModel()
|
||||
{
|
||||
return m_categoryModel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // QT_UTILITIES_SETTINGSDIALOG_H
|
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialogs::SettingsDialog</class>
|
||||
<widget class="QDialog" name="Dialogs::SettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>515</width>
|
||||
<height>311</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="mainWidget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="instructionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>No category selected</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="Widgets::ClearLineEdit" name="filterLineEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QTabWidget" name="pagesTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListView" name="categoriesListView">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bottomWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>168</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="abortPushButton">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: none;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Abort</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="dialog-cancel">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="applyPushButton">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: none;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="dialog-ok-apply">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okPushButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="dialog-ok">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Widgets::ClearLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header location="global">qtutilities/widgets/clearlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,188 @@
|
|||
#include "buttonoverlay.h"
|
||||
#include "iconbutton.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QToolTip>
|
||||
#include <QCursor>
|
||||
|
||||
#include <functional>
|
||||
|
||||
/*!
|
||||
* \namespace Widgets
|
||||
* \brief Provides a set of extended widgets such as ClearLineEdit and ClearComboBox.
|
||||
*/
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::ButtonOverlay
|
||||
* \brief The ButtonOverlay class is used to display buttons on top of other widgets.
|
||||
*
|
||||
* The class creates a new layout manager and sets it to the widget which is specified
|
||||
* when constructing an instance. Thus this widget must not already have a layout manager.
|
||||
*
|
||||
* The class is used to implement widget customization like ClearLineEidt and ClearComboBox.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a button overlay for the specified \a widget.
|
||||
* \param widget Specifies the widget to display the buttons on.
|
||||
*/
|
||||
ButtonOverlay::ButtonOverlay(QWidget *widget) :
|
||||
m_widget(widget),
|
||||
m_buttonWidget(new QWidget(widget)),
|
||||
m_buttonLayout(new QHBoxLayout(m_buttonWidget)),
|
||||
m_clearButton(nullptr),
|
||||
m_infoButton(nullptr)
|
||||
{
|
||||
// setup button widget and layout
|
||||
const QMargins margins = widget->contentsMargins();
|
||||
QStyleOption opt;
|
||||
opt.initFrom(m_widget);
|
||||
const int frameWidth = widget->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, m_widget);
|
||||
const int pad = 2;
|
||||
m_buttonLayout->setContentsMargins(margins.left() + frameWidth + pad, margins.top() + frameWidth, margins.right() + frameWidth + pad, margins.bottom() + frameWidth);
|
||||
m_buttonLayout->setAlignment(Qt::AlignCenter | Qt::AlignRight);
|
||||
widget->setLayout(m_buttonLayout);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the button overlay.
|
||||
*/
|
||||
ButtonOverlay::~ButtonOverlay()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether the clear button is enabled.
|
||||
*/
|
||||
void ButtonOverlay::setClearButtonEnabled(bool enabled)
|
||||
{
|
||||
if(isClearButtonEnabled() && !enabled) {
|
||||
// disable clear button
|
||||
m_buttonLayout->removeWidget(m_clearButton);
|
||||
delete m_clearButton;
|
||||
m_clearButton = nullptr;
|
||||
} else if(!isClearButtonEnabled() && enabled) {
|
||||
// enable clear button
|
||||
m_clearButton = new IconButton;
|
||||
m_clearButton->setHidden(isCleared());
|
||||
m_clearButton->setPixmap(/*QIcon::fromTheme(QStringLiteral("edit-clear"), */QIcon(QStringLiteral(":/qtutilities/icons/hicolor/16x16/actions/edit-clear.png")/*)*/).pixmap(16));
|
||||
m_clearButton->setGeometry(0, 0, 16, 16);
|
||||
m_clearButton->setToolTip(QObject::tr("clear"));
|
||||
QObject::connect(m_clearButton, &IconButton::clicked, std::bind(&ButtonOverlay::handleClearButtonClicked, this));
|
||||
m_buttonLayout->addWidget(m_clearButton);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Shows an info button with the specified \a pixmap and \a infoText.
|
||||
*
|
||||
* If there is already an info button enabled, it gets replaced with the new button.
|
||||
*
|
||||
* \sa ButtonOverlay::disableInfoButton()
|
||||
*/
|
||||
void ButtonOverlay::enableInfoButton(const QPixmap &pixmap, const QString &infoText)
|
||||
{
|
||||
if(!m_infoButton) {
|
||||
m_infoButton = new IconButton;
|
||||
m_infoButton->setGeometry(0, 0, 16, 16);
|
||||
QObject::connect(m_infoButton, &IconButton::clicked, std::bind(&ButtonOverlay::showInfo, this));
|
||||
if(m_clearButton) {
|
||||
m_buttonLayout->insertWidget(m_buttonLayout->count() - 2, m_infoButton);
|
||||
} else {
|
||||
m_buttonLayout->addWidget(m_infoButton);
|
||||
}
|
||||
}
|
||||
m_infoButton->setPixmap(pixmap);
|
||||
m_infoButton->setToolTip(infoText);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Hides an info button if one is shown.
|
||||
* \sa ButtonOverlay::enableInfoButton()
|
||||
*/
|
||||
void ButtonOverlay::disableInfoButton()
|
||||
{
|
||||
if(m_infoButton) {
|
||||
m_buttonLayout->removeWidget(m_infoButton);
|
||||
delete m_infoButton;
|
||||
m_infoButton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a custom \a button.
|
||||
*
|
||||
* The button overlay takes ownership over the specified \a button.
|
||||
*/
|
||||
void ButtonOverlay::addCustomButton(QWidget *button)
|
||||
{
|
||||
m_buttonLayout->addWidget(button);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Inserts a custom \a button at the specified \a index.
|
||||
*
|
||||
* The button overlay takes ownership over the specified \a button.
|
||||
*/
|
||||
void ButtonOverlay::insertCustomButton(int index, QWidget *button)
|
||||
{
|
||||
m_buttonLayout->insertWidget(index, button);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes the specified custom \a button.
|
||||
*
|
||||
* The ownership of widget remains the same as when it was added.
|
||||
*/
|
||||
void ButtonOverlay::removeCustomButton(QWidget *button)
|
||||
{
|
||||
m_buttonLayout->removeWidget(button);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the visibility of the clear button.
|
||||
*
|
||||
* This method is meant to be called when subclassing.
|
||||
*/
|
||||
void ButtonOverlay::updateClearButtonVisibility(bool visible)
|
||||
{
|
||||
if(m_clearButton) {
|
||||
m_clearButton->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the related widget.
|
||||
*
|
||||
* This method is meant to be implemented when subclassing.
|
||||
*/
|
||||
void ButtonOverlay::handleClearButtonClicked()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the related widget is cleared.
|
||||
*
|
||||
* This method is meant to be implemented when subclassing.
|
||||
*/
|
||||
bool ButtonOverlay::isCleared() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Shows the info text using a tool tip.
|
||||
*
|
||||
* This method is called when the info button is clicked.
|
||||
*/
|
||||
void ButtonOverlay::showInfo()
|
||||
{
|
||||
if(m_infoButton) {
|
||||
QToolTip::showText(QCursor::pos(), m_infoButton->toolTip(), m_infoButton);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef WIDGETS_CLEARABLEWIDGET_H
|
||||
#define WIDGETS_CLEARABLEWIDGET_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWidget;
|
||||
class QHBoxLayout;
|
||||
class QString;
|
||||
class QPixmap;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class IconButton;
|
||||
|
||||
class LIB_EXPORT ButtonOverlay
|
||||
{
|
||||
public:
|
||||
explicit ButtonOverlay(QWidget *widget);
|
||||
virtual ~ButtonOverlay();
|
||||
|
||||
QHBoxLayout *buttonLayout();
|
||||
bool isClearButtonEnabled() const;
|
||||
void setClearButtonEnabled(bool enabled);
|
||||
bool isInfoButtonEnabled() const;
|
||||
void enableInfoButton(const QPixmap &pixmap, const QString &infoText);
|
||||
void disableInfoButton();
|
||||
void addCustomButton(QWidget *button);
|
||||
void insertCustomButton(int index, QWidget *button);
|
||||
void removeCustomButton(QWidget *button);
|
||||
virtual bool isCleared() const;
|
||||
|
||||
protected:
|
||||
void updateClearButtonVisibility(bool visible);
|
||||
virtual void handleClearButtonClicked();
|
||||
|
||||
private:
|
||||
void showInfo();
|
||||
|
||||
QWidget *m_widget;
|
||||
QWidget *m_buttonWidget;
|
||||
QHBoxLayout *m_buttonLayout;
|
||||
IconButton *m_clearButton;
|
||||
IconButton *m_infoButton;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the layout manager holding the buttons.
|
||||
*/
|
||||
inline QHBoxLayout *ButtonOverlay::buttonLayout()
|
||||
{
|
||||
return m_buttonLayout;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the clear button is enabled.
|
||||
*/
|
||||
inline bool ButtonOverlay::isClearButtonEnabled() const
|
||||
{
|
||||
return m_clearButton != nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the info button is enabled.
|
||||
*/
|
||||
inline bool ButtonOverlay::isInfoButtonEnabled() const
|
||||
{
|
||||
return m_infoButton != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // WIDGETS_CLEARABLEWIDGET_H
|
|
@ -0,0 +1,56 @@
|
|||
#include "clearcombobox.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionComboBox>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::ClearComboBox
|
||||
* \brief A QComboBox with an embedded button for clearing its contents.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a clear combo box.
|
||||
*/
|
||||
ClearComboBox::ClearComboBox(QWidget *parent) :
|
||||
QComboBox(parent),
|
||||
ButtonOverlay(this)
|
||||
{
|
||||
const QMargins margins = contentsMargins();
|
||||
QStyleOptionComboBox opt;
|
||||
opt.initFrom(this);
|
||||
const int frameWidth = style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth, &opt, this);
|
||||
const int pad = 2;
|
||||
const int buttonWidth = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, this).width();
|
||||
buttonLayout()->setContentsMargins(margins.left() + frameWidth + pad, margins.top() + frameWidth, margins.right() + frameWidth + pad + buttonWidth, margins.bottom() + frameWidth);
|
||||
setClearButtonEnabled(isEditable());
|
||||
connect(this, &ClearComboBox::currentTextChanged, this, &ClearComboBox::handleTextChanged);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the clear combo box.
|
||||
*/
|
||||
ClearComboBox::~ClearComboBox()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Updates the visibility of the clear button.
|
||||
*/
|
||||
void ClearComboBox::handleTextChanged(const QString &text)
|
||||
{
|
||||
updateClearButtonVisibility(!text.isEmpty());
|
||||
}
|
||||
|
||||
void ClearComboBox::handleClearButtonClicked()
|
||||
{
|
||||
clearEditText();
|
||||
}
|
||||
|
||||
bool ClearComboBox::isCleared() const
|
||||
{
|
||||
return currentText().isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef WIDGETS_CLEARCOMBOBOX_H
|
||||
#define WIDGETS_CLEARCOMBOBOX_H
|
||||
|
||||
#include "buttonoverlay.h"
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class LIB_EXPORT ClearComboBox : public QComboBox, public ButtonOverlay
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClearComboBox(QWidget *parent = nullptr);
|
||||
~ClearComboBox();
|
||||
bool isCleared() const;
|
||||
|
||||
private slots:
|
||||
void handleTextChanged(const QString &text);
|
||||
void handleClearButtonClicked();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Widgets
|
||||
|
||||
#endif // WIDGETS_CLEARCOMBOBOX_H
|
|
@ -0,0 +1,45 @@
|
|||
#include "clearlineedit.h"
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::ClearLineEdit
|
||||
* \brief A QLineEdit with an embedded button for clearing its contents.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a clear line edit.
|
||||
*/
|
||||
ClearLineEdit::ClearLineEdit(QWidget *parent) :
|
||||
QLineEdit(parent),
|
||||
ButtonOverlay(this)
|
||||
{
|
||||
ButtonOverlay::setClearButtonEnabled(true);
|
||||
connect(this, &ClearLineEdit::textChanged, this, &ClearLineEdit::handleTextChanged);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the clear combo box.
|
||||
*/
|
||||
ClearLineEdit::~ClearLineEdit()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Updates the visibility of the clear button.
|
||||
*/
|
||||
void ClearLineEdit::handleTextChanged(const QString &text)
|
||||
{
|
||||
updateClearButtonVisibility(!text.isEmpty());
|
||||
}
|
||||
|
||||
void ClearLineEdit::handleClearButtonClicked()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool ClearLineEdit::isCleared() const
|
||||
{
|
||||
return text().isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef WIDGETS_TAGFIELDLINEEDIT_H
|
||||
#define WIDGETS_TAGFIELDLINEEDIT_H
|
||||
|
||||
#include "buttonoverlay.h"
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QHBoxLayout;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class IconButton;
|
||||
|
||||
class LIB_EXPORT ClearLineEdit : public QLineEdit, public ButtonOverlay
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClearLineEdit(QWidget *parent = nullptr);
|
||||
~ClearLineEdit();
|
||||
bool isCleared() const;
|
||||
|
||||
private slots:
|
||||
void handleTextChanged(const QString &text);
|
||||
void handleClearButtonClicked();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WIDGETS_TAGFIELDLINEEDIT_H
|
|
@ -0,0 +1,52 @@
|
|||
#include "clearplaintextedit.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::ClearPlainTextEdit
|
||||
* \brief A QPlainTextEdit with an embedded button for clearing its contents.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a clear plain text edit.
|
||||
*/
|
||||
ClearPlainTextEdit::ClearPlainTextEdit(QWidget *parent) :
|
||||
QPlainTextEdit(parent),
|
||||
ButtonOverlay(this)
|
||||
{
|
||||
// set alignment to show buttons in the bottom right corner
|
||||
ButtonOverlay::buttonLayout()->setAlignment(Qt::AlignBottom | Qt::AlignRight);
|
||||
ButtonOverlay::setClearButtonEnabled(true);
|
||||
connect(document(), &QTextDocument::contentsChanged, this, &ClearPlainTextEdit::handleTextChanged);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the clear plain text edit.
|
||||
*/
|
||||
ClearPlainTextEdit::~ClearPlainTextEdit()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Updates the visibility of the clear button.
|
||||
*/
|
||||
void ClearPlainTextEdit::handleTextChanged()
|
||||
{
|
||||
updateClearButtonVisibility(!document()->isEmpty());
|
||||
}
|
||||
|
||||
void ClearPlainTextEdit::handleClearButtonClicked()
|
||||
{
|
||||
// do no call clear() here to prevent clearing of undo history
|
||||
QTextCursor cursor(document());
|
||||
cursor.select(QTextCursor::Document);
|
||||
cursor.removeSelectedText();
|
||||
}
|
||||
|
||||
bool ClearPlainTextEdit::isCleared() const
|
||||
{
|
||||
return document()->isEmpty();
|
||||
}
|
||||
|
||||
} // namespace Widgets
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef WIDGETS_CLEARPLAINTEXTEDIT_H
|
||||
#define WIDGETS_CLEARPLAINTEXTEDIT_H
|
||||
|
||||
#include "buttonoverlay.h"
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class LIB_EXPORT ClearPlainTextEdit : public QPlainTextEdit, public ButtonOverlay
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClearPlainTextEdit(QWidget *parent = nullptr);
|
||||
~ClearPlainTextEdit();
|
||||
bool isCleared() const;
|
||||
|
||||
private slots:
|
||||
void handleTextChanged();
|
||||
void handleClearButtonClicked();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Widgets
|
||||
|
||||
#endif // WIDGETS_CLEARPLAINTEXTEDIT_H
|
|
@ -0,0 +1,76 @@
|
|||
#include "clearspinbox.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionSpinBox>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::ClearSpinBox
|
||||
* \brief A QSpinBox with an embedded button for clearing its contents and the ability to hide
|
||||
* the minimum value.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a clear spin box.
|
||||
*/
|
||||
ClearSpinBox::ClearSpinBox(QWidget *parent) :
|
||||
QSpinBox(parent),
|
||||
ButtonOverlay(this),
|
||||
m_minimumHidden(false)
|
||||
{
|
||||
const QMargins margins = contentsMargins();
|
||||
QStyleOptionComboBox opt;
|
||||
opt.initFrom(this);
|
||||
const int frameWidth = style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth, &opt, this);
|
||||
const int pad = 5;
|
||||
const int buttonWidth = style()->subControlRect(QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxUp, this).width() + 10;
|
||||
buttonLayout()->setContentsMargins(margins.left() + frameWidth + pad, margins.top() + frameWidth, margins.right() + frameWidth + pad + buttonWidth, margins.bottom() + frameWidth);
|
||||
setClearButtonEnabled(true);
|
||||
connect(this, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &ClearSpinBox::handleValueChanged);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the clear spin box.
|
||||
*/
|
||||
ClearSpinBox::~ClearSpinBox()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Updates the visibility of the clear button.
|
||||
*/
|
||||
void ClearSpinBox::handleValueChanged(int value)
|
||||
{
|
||||
updateClearButtonVisibility(value != minimum());
|
||||
}
|
||||
|
||||
void ClearSpinBox::handleClearButtonClicked()
|
||||
{
|
||||
setValue(minimum());
|
||||
}
|
||||
|
||||
bool ClearSpinBox::isCleared() const
|
||||
{
|
||||
return value() == minimum();
|
||||
}
|
||||
|
||||
int ClearSpinBox::valueFromText(const QString &text) const
|
||||
{
|
||||
if(m_minimumHidden && text.isEmpty()) {
|
||||
return minimum();
|
||||
} else {
|
||||
return QSpinBox::valueFromText(text);
|
||||
}
|
||||
}
|
||||
|
||||
QString ClearSpinBox::textFromValue(int val) const
|
||||
{
|
||||
if(m_minimumHidden && (val == minimum())) {
|
||||
return QString();
|
||||
} else {
|
||||
return QSpinBox::textFromValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
#ifndef WIDGETS_CLEARSPINBOX_H
|
||||
#define WIDGETS_CLEARSPINBOX_H
|
||||
|
||||
#include "buttonoverlay.h"
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QSpinBox>
|
||||
#include <QLineEdit>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QHBoxLayout;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class IconButton;
|
||||
|
||||
class LIB_EXPORT ClearSpinBox : public QSpinBox, public ButtonOverlay
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool minimumHidden READ minimumHidden WRITE setMinimumHidden)
|
||||
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText)
|
||||
Q_PROPERTY(bool isCleared READ isCleared)
|
||||
|
||||
public:
|
||||
explicit ClearSpinBox(QWidget *parent = nullptr);
|
||||
~ClearSpinBox();
|
||||
bool minimumHidden() const;
|
||||
void setMinimumHidden(bool value);
|
||||
QString placeholderText() const;
|
||||
void setPlaceholderText(const QString &placeholderText);
|
||||
bool isCleared() const;
|
||||
|
||||
protected:
|
||||
int valueFromText(const QString &text) const;
|
||||
QString textFromValue(int val) const;
|
||||
|
||||
private slots:
|
||||
void handleValueChanged(int value);
|
||||
void handleClearButtonClicked();
|
||||
|
||||
private:
|
||||
bool m_minimumHidden;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the minimum value will be hidden.
|
||||
*/
|
||||
inline bool ClearSpinBox::minimumHidden() const
|
||||
{
|
||||
return m_minimumHidden;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether the minimum value should be hidden.
|
||||
*/
|
||||
inline void ClearSpinBox::setMinimumHidden(bool value)
|
||||
{
|
||||
m_minimumHidden = value;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the placeholder text.
|
||||
* \sa QLineEdit::placeholderText()
|
||||
*/
|
||||
inline QString ClearSpinBox::placeholderText() const
|
||||
{
|
||||
return lineEdit()->placeholderText();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the placeholder text.
|
||||
* \sa QLineEdit::setPlaceholderText()
|
||||
*/
|
||||
inline void ClearSpinBox::setPlaceholderText(const QString &placeholderText)
|
||||
{
|
||||
lineEdit()->setPlaceholderText(placeholderText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // WIDGETS_CLEARSPINBOX_H
|
|
@ -0,0 +1,80 @@
|
|||
#include "iconbutton.h"
|
||||
|
||||
#include <QStylePainter>
|
||||
#include <QStyleOptionFocusRect>
|
||||
#include <QKeyEvent>
|
||||
#include <QDebug>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
/*!
|
||||
* \class Widgets::IconButton
|
||||
* \brief A simple QAbstractButton implementation displaying a QPixmap.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an icon button.
|
||||
*/
|
||||
IconButton::IconButton(QWidget *parent) :
|
||||
QAbstractButton(parent)
|
||||
{
|
||||
setCursor(Qt::ArrowCursor);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the icon button.
|
||||
*/
|
||||
IconButton::~IconButton()
|
||||
{}
|
||||
|
||||
QSize IconButton::sizeHint() const
|
||||
{
|
||||
#if QT_VERSION >= 0x050100
|
||||
const qreal pixmapRatio = m_pixmap.devicePixelRatio();
|
||||
#else
|
||||
const qreal pixmapRatio = 1.0;
|
||||
#endif
|
||||
return QSize(m_pixmap.width() / pixmapRatio, m_pixmap.height() / pixmapRatio);
|
||||
}
|
||||
|
||||
void IconButton::paintEvent(QPaintEvent *)
|
||||
{
|
||||
#if QT_VERSION >= 0x050100
|
||||
const qreal pixmapRatio = m_pixmap.devicePixelRatio();
|
||||
#else
|
||||
const qreal pixmapRatio = 1.0;
|
||||
#endif
|
||||
QStylePainter painter(this);
|
||||
QRect pixmapRect = QRect(0, 0, m_pixmap.width() / pixmapRatio, m_pixmap.height() / pixmapRatio);
|
||||
pixmapRect.moveCenter(rect().center());
|
||||
painter.drawPixmap(pixmapRect, m_pixmap);
|
||||
if(hasFocus()) {
|
||||
QStyleOptionFocusRect focusOption;
|
||||
focusOption.initFrom(this);
|
||||
focusOption.rect = pixmapRect;
|
||||
#ifdef Q_OS_MAC
|
||||
focusOption.rect.adjust(-4, -4, 4, 4);
|
||||
painter.drawControl(QStyle::CE_FocusFrame, focusOption);
|
||||
#else
|
||||
painter.drawPrimitive(QStyle::PE_FrameFocusRect, focusOption);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void IconButton::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
QAbstractButton::keyPressEvent(event);
|
||||
if (!event->modifiers() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) {
|
||||
click();
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void IconButton::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
QAbstractButton::keyReleaseEvent(event);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef WIDGETS_ICONBUTTON_H
|
||||
#define WIDGETS_ICONBUTTON_H
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class LIB_EXPORT IconButton : public QAbstractButton
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)
|
||||
|
||||
public:
|
||||
explicit IconButton(QWidget *parent = nullptr);
|
||||
~IconButton();
|
||||
|
||||
const QPixmap &pixmap() const;
|
||||
void setPixmap(const QPixmap &pixmap);
|
||||
QSize sizeHint() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void keyReleaseEvent(QKeyEvent *event);
|
||||
|
||||
private:
|
||||
QPixmap m_pixmap;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the pixmap.
|
||||
*/
|
||||
inline const QPixmap &IconButton::pixmap() const
|
||||
{
|
||||
return m_pixmap;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the pixmap.
|
||||
*/
|
||||
inline void IconButton::setPixmap(const QPixmap &pixmap)
|
||||
{
|
||||
m_pixmap = pixmap;
|
||||
update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // WIDGETS_ICONBUTTON_H
|
Loading…
Reference in New Issue