chore(cpn): Fetch maxlibqt from forked repo at compile time (#4249)
Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com>
This commit is contained in:
co-authored by
raphaelcoeffic
parent
34bee45f61
commit
a891c5e907
@@ -0,0 +1,17 @@
|
||||
# Fetch maxLibQt source code from Github
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
maxLibQt
|
||||
GIT_REPOSITORY https://github.com/edgetx/maxLibQt
|
||||
GIT_TAG b5418f76cc4891e09f4e21276175d39dbb130f66
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(maxLibQt)
|
||||
|
||||
message("Fetched maxLibQt source code from Github: ${maxLibQt_SOURCE_DIR}")
|
||||
include_directories(
|
||||
${maxLibQt_SOURCE_DIR}
|
||||
${maxLibQt_BINARY_DIR}
|
||||
)
|
||||
@@ -142,7 +142,6 @@ endif()
|
||||
############# Common lib ###############
|
||||
|
||||
set(common_SRCS
|
||||
appdebugmessagehandler.cpp
|
||||
customdebug.cpp
|
||||
helpers.cpp
|
||||
translations.cpp
|
||||
@@ -151,7 +150,6 @@ set(common_SRCS
|
||||
)
|
||||
|
||||
set(common_MOC_HDRS
|
||||
appdebugmessagehandler.h
|
||||
helpers.h
|
||||
modeledit/node.h
|
||||
)
|
||||
@@ -170,7 +168,7 @@ target_link_libraries(common
|
||||
firmwares
|
||||
storage
|
||||
simulation
|
||||
maxLibQtWidgets
|
||||
maxLibQt
|
||||
Qt5::Core
|
||||
Qt5::Xml
|
||||
Qt5::Widgets
|
||||
@@ -185,6 +183,8 @@ set(CPN_COMMON_LIB common)
|
||||
|
||||
include(FetchMiniz)
|
||||
|
||||
include(FetchMaxLibQt)
|
||||
|
||||
add_subdirectory(datamodels)
|
||||
add_subdirectory(firmwares)
|
||||
add_subdirectory(shared)
|
||||
@@ -193,7 +193,6 @@ add_subdirectory(generaledit)
|
||||
add_subdirectory(simulation)
|
||||
add_subdirectory(storage)
|
||||
add_subdirectory(thirdparty/qcustomplot)
|
||||
add_subdirectory(thirdparty/maxlibqt/src/widgets)
|
||||
add_subdirectory(updates)
|
||||
|
||||
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "Enable testing" FORCE)
|
||||
@@ -204,6 +203,8 @@ add_subdirectory(thirdparty/yaml-cpp)
|
||||
|
||||
############# Companion ###############
|
||||
|
||||
include_directories(${maxLibQt_SOURCE_DIR}/widgets)
|
||||
|
||||
set(companion_SRCS
|
||||
helpers_html.cpp
|
||||
mdichild.cpp
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "appdebugmessagehandler.h"
|
||||
|
||||
#include <QFileDevice>
|
||||
|
||||
AppDebugMessageHandler::AppDebugMessageHandler(QObject * parent) :
|
||||
QObject(parent),
|
||||
m_appDebugOutputLevel(APP_DBG_HANDLER_DEFAULT_LEVEL),
|
||||
m_showSourcePath(APP_DBG_HANDLER_SHOW_SRC_PATH),
|
||||
m_showFunctionDeclarations(APP_DBG_HANDLER_SHOW_FUNCTION_DECL)
|
||||
{
|
||||
m_srcPathFilter = QRegularExpression("^" APP_DBG_HANDLER_SRC_PATH "[\\\\\\/](.*?)$", QRegularExpression::InvertedGreedinessOption);
|
||||
m_functionFilter = QRegularExpression("^.+?(\\w+\\().+$");
|
||||
}
|
||||
|
||||
AppDebugMessageHandler * AppDebugMessageHandler::instance()
|
||||
{
|
||||
static AppDebugMessageHandler * _instance = NULL;
|
||||
#if APP_DBG_HANDLER_ENABLE
|
||||
if(_instance == NULL && !qApp->closingDown())
|
||||
_instance = new AppDebugMessageHandler(qApp); // Ensure this object is cleaned up when the QApplication exits.
|
||||
#endif
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::setAppDebugOutputLevel(const quint8 & appDebugOutputLevel)
|
||||
{
|
||||
m_appDebugOutputLevel = appDebugOutputLevel;
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::setShowSourcePath(bool showSourcePath)
|
||||
{
|
||||
m_showSourcePath = showSourcePath;
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::setShowFunctionDeclarations(bool showFunctionDeclarations)
|
||||
{
|
||||
m_showFunctionDeclarations = showFunctionDeclarations;
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::addOutputDevice(QIODevice * device)
|
||||
{
|
||||
if (device && !m_outputDevices.contains(device))
|
||||
m_outputDevices.append(device);
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::removeOutputDevice(QIODevice * device)
|
||||
{
|
||||
if (device) {
|
||||
// no QVector::removeAll() in Qt < 5.4
|
||||
int i = 0;
|
||||
foreach (QIODevice * d, m_outputDevices) {
|
||||
if (d == device)
|
||||
m_outputDevices.remove(i);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::installAppMessageHandler()
|
||||
{
|
||||
m_defaultHandler = qInstallMessageHandler(g_appDebugMessageHandler);
|
||||
}
|
||||
|
||||
void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
|
||||
{
|
||||
static const char symbols[] = { 'D', 'W', 'E', 'X', 'I' }; // correspond to QtMsgType enum
|
||||
// normalize types, QtDebugMsg stays 0, QtInfoMsg becomes 1, rest are QtMsgType + 1
|
||||
quint8 lvl = type;
|
||||
if (type == QtInfoMsg)
|
||||
lvl = 1;
|
||||
else if (type > QtDebugMsg)
|
||||
++lvl;
|
||||
|
||||
if (lvl < m_appDebugOutputLevel && type != QtFatalMsg)
|
||||
return;
|
||||
|
||||
#if defined(Q_OS_LINUX) && (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
|
||||
// Filter out lots of QPainter warnings from undocked QDockWidgets... hackish but effective (only workaround found so far)
|
||||
if (lvl == 2 && QString(context.function).contains("QPainter::"))
|
||||
return;
|
||||
#endif
|
||||
|
||||
QString msgPattern = QString("[%1] ").arg(symbols[type]);
|
||||
|
||||
if (m_showSourcePath) {
|
||||
QString file = QString("%1::").arg(context.file);
|
||||
file.replace(m_srcPathFilter, "\\1");
|
||||
msgPattern.append(file);
|
||||
}
|
||||
if (m_showFunctionDeclarations)
|
||||
msgPattern.append(context.function);
|
||||
else
|
||||
msgPattern.append("%{function}()");
|
||||
|
||||
msgPattern.append(":%{line} -%{if-category} [%{category}]%{endif} %{message}");
|
||||
|
||||
if (type == QtFatalMsg)
|
||||
msgPattern.append("\nBACKTRACE:\n%{backtrace depth=12 separator=\"\n\"}");
|
||||
|
||||
qSetMessagePattern(msgPattern);
|
||||
|
||||
if (!m_defaultHandler || m_outputDevices.size() || receivers(SIGNAL(messageOutput(quint8, const QString &)))) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
||||
msgPattern = qFormatLogMessage(type, context, msg);
|
||||
#else
|
||||
msgPattern.replace("%{line}", QString::number(context.line));
|
||||
msgPattern.replace("%{if-category} [%{category}]%{endif}", QString(context.category));
|
||||
msgPattern.replace("%{message}", msg);
|
||||
if (!m_showFunctionDeclarations) {
|
||||
QString func = context.function;
|
||||
msgPattern.replace("%{function}", func.replace(m_functionFilter, "\\1)"));
|
||||
}
|
||||
#endif
|
||||
|
||||
emit messageOutput(lvl, msgPattern);
|
||||
|
||||
foreach (QIODevice * d, m_outputDevices) {
|
||||
if (d && d->isWritable() && (!d->property("level").isValid() || d->property("level").toInt() <= lvl)) {
|
||||
d->write(qPrintable(msgPattern % "\n"));
|
||||
if (QFileDevice * fd = qobject_cast<QFileDevice *>(d))
|
||||
fd->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (QThread::currentThread() == qApp->thread()) // gui thread
|
||||
|
||||
if (m_defaultHandler) {
|
||||
m_defaultHandler(type, context, msg);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s", qPrintable(msgPattern));
|
||||
if (type == QtFatalMsg)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Message handler which is installed using qInstallMessageHandler. This needs to be global.
|
||||
void g_appDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
{
|
||||
if (AppDebugMessageHandler::instance())
|
||||
AppDebugMessageHandler::instance()->messageHandler(type, context, msg);
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef APPDEBUGMESSAGEHANDLER_H
|
||||
#define APPDEBUGMESSAGEHANDLER_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QMessageLogContext>
|
||||
#include <QObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
/*
|
||||
* Custom debug/message handler class to work in conjunction with qDebug() family of functions.
|
||||
* Formats all stderr output generated by the application in a consistent manner.
|
||||
* It can also be used by other event listeners to intercept messages they may be interested in (connect to messageOutput() signal).
|
||||
*
|
||||
* Include this header to use qInfo() safely with Qt < v5.5 (qInfo becomes alias for qDebug).
|
||||
*
|
||||
* Note that the default message format can still be overriden by setting QT_MESSAGE_PATTERN environment variable at _runtime_.
|
||||
* see: https://doc.qt.io/qt-5/qtglobal.html#qSetMessagePattern
|
||||
*
|
||||
* This is an app-wide "global" thread-safe singleton class, use it with AppDebugMessageHandler::instance().
|
||||
* For example, at start of application:
|
||||
*
|
||||
* QApplication app(argc, argv);
|
||||
* AppDebugMessageHandler::instance()->installAppMessageHandler();
|
||||
*
|
||||
* To connect to a signal:
|
||||
*
|
||||
* connect(AppDebugMessageHandler::instance(), &AppDebugMessageHandler::messageOutput, this, &DebugOutput::onAppDebugMessage);
|
||||
*
|
||||
* This singleton will self-destruct upon QApplication termination.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(QT_DEBUG) || defined(DEBUG)
|
||||
#define APP_DBG_HANDLER_IS_DBG_BUILD 1
|
||||
#else
|
||||
#define APP_DBG_HANDLER_IS_DBG_BUILD 0
|
||||
#endif
|
||||
|
||||
// Enable/disable this custom handler handler entirely
|
||||
#ifndef APP_DBG_HANDLER_ENABLE
|
||||
#define APP_DBG_HANDLER_ENABLE 1
|
||||
#endif
|
||||
|
||||
// Default log level (can also be set with setAppDebugOutputLevel()):
|
||||
// 0 = debug+; 1 = info+; 2 = warn+; 3 = critical+; 4 = fatal only
|
||||
#ifndef APP_DBG_HANDLER_DEFAULT_LEVEL
|
||||
#define APP_DBG_HANDLER_DEFAULT_LEVEL 0
|
||||
#endif
|
||||
|
||||
// Include source file path/name in output (filtered with APP_DBG_HANDLER_SRC_PATH)
|
||||
#ifndef APP_DBG_HANDLER_SHOW_SRC_PATH
|
||||
#define APP_DBG_HANDLER_SHOW_SRC_PATH APP_DBG_HANDLER_IS_DBG_BUILD
|
||||
#endif
|
||||
|
||||
// Show just the function Class::name vs. full declaration with return and param types
|
||||
#ifndef APP_DBG_HANDLER_SHOW_FUNCTION_DECL
|
||||
#define APP_DBG_HANDLER_SHOW_FUNCTION_DECL 0
|
||||
#endif
|
||||
|
||||
// base path for source file name filter, everything after this is kept; RegEx, non-greedy
|
||||
#ifndef APP_DBG_HANDLER_SRC_PATH
|
||||
#define APP_DBG_HANDLER_SRC_PATH ".*src"
|
||||
#endif
|
||||
|
||||
// Make sure to include this header if using qInfo()
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
|
||||
#if defined(QT_NO_INFO_OUTPUT)
|
||||
#define qInfo QT_NO_QDEBUG_MACRO
|
||||
#else
|
||||
#define qInfo qDebug
|
||||
#endif
|
||||
#define QtInfoMsg QtMsgType(4)
|
||||
#endif
|
||||
|
||||
class AppDebugMessageHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// This class implements the singleton design pattern and is therefore publicly accessible only through instance().
|
||||
static AppDebugMessageHandler * instance();
|
||||
AppDebugMessageHandler(AppDebugMessageHandler const &) = delete;
|
||||
void operator = (AppDebugMessageHandler const &) = delete;
|
||||
|
||||
void setAppDebugOutputLevel(const quint8 & appDebugOutputLevel);
|
||||
void setShowSourcePath(bool showSourcePath);
|
||||
void setShowFunctionDeclarations(bool showFunctionDeclarations);
|
||||
void addOutputDevice(QIODevice * device);
|
||||
void removeOutputDevice(QIODevice * device);
|
||||
|
||||
void installAppMessageHandler();
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg);
|
||||
|
||||
private:
|
||||
// This class implements the singleton design pattern and therefore has only a private constructor.
|
||||
explicit AppDebugMessageHandler(QObject * parent = Q_NULLPTR);
|
||||
~AppDebugMessageHandler() { }
|
||||
|
||||
QtMessageHandler m_defaultHandler;
|
||||
QRegularExpression m_srcPathFilter;
|
||||
QRegularExpression m_functionFilter;
|
||||
quint8 m_appDebugOutputLevel;
|
||||
QVector<QIODevice *> m_outputDevices;
|
||||
bool m_showSourcePath;
|
||||
bool m_showFunctionDeclarations;
|
||||
|
||||
signals:
|
||||
void messageOutput(quint8 level, const QString & msg);
|
||||
};
|
||||
|
||||
// Message handler which is installed using qInstallMessageHandler. This needs to be global.
|
||||
// Use AppDebugMessageHandler::instance()->installAppMessageHandler();
|
||||
// instead of installing this function directly (it will verify this handler is enabled, etc).
|
||||
void g_appDebugMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);
|
||||
|
||||
#endif // APPDEBUGMESSAGEHANDLER_H
|
||||
@@ -29,7 +29,8 @@
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#include "appdebugmessagehandler.h"
|
||||
#include <AppDebugMessageHandler>
|
||||
|
||||
#include "customdebug.h"
|
||||
#include "mainwindow.h"
|
||||
#include "version.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${maxLibQt_SOURCE_DIR}/widgets)
|
||||
|
||||
set(generaledit_NAMES
|
||||
generaledit
|
||||
|
||||
@@ -2,6 +2,7 @@ include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${COMPANION_SRC_DIRECTORY}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${maxLibQt_SOURCE_DIR}/widgets
|
||||
)
|
||||
|
||||
set(modeledit_NAMES
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${maxLibQt_SOURCE_DIR}/widgets)
|
||||
|
||||
set(shared_NAMES
|
||||
genericpanel
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
#include "debugoutput.h"
|
||||
#include "ui_debugoutput.h"
|
||||
|
||||
#include "appdebugmessagehandler.h"
|
||||
#include "appdata.h"
|
||||
#include "filteredtextbuffer.h"
|
||||
|
||||
#include <AppDebugMessageHandler>
|
||||
#include <QElapsedTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "simulatorwidget.h"
|
||||
#include "ui_simulatorwidget.h"
|
||||
|
||||
#include "appdebugmessagehandler.h"
|
||||
#include "appdata.h"
|
||||
#include "radiofaderwidget.h"
|
||||
#include "radiokeywidget.h"
|
||||
#include "radioknobwidget.h"
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "joystickdialog.h"
|
||||
#endif
|
||||
|
||||
#include <AppDebugMessageHandler>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <iostream>
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QMouseEvent>
|
||||
#include <AppDebugMessageHandler>
|
||||
|
||||
#include "appdata.h"
|
||||
#include "appdebugmessagehandler.h"
|
||||
|
||||
#define LCD_WIDGET_REFRESH_PERIOD 16 // [ms] 16 = 62.5fps
|
||||
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#include <AppDebugMessageHandler>
|
||||
|
||||
#include "appdata.h"
|
||||
#include "appdebugmessagehandler.h"
|
||||
#include "constants.h"
|
||||
#include "customdebug.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_policy(SET CMP0020 NEW)
|
||||
|
||||
find_package(Qt5Core)
|
||||
find_package(Qt5Widgets)
|
||||
|
||||
project(maxLibQtWidgets)
|
||||
|
||||
set(SRCS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ExportableTableView.cpp"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/ScrollableMessageBox.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TimerEdit.cpp"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TreeComboBox.cpp"
|
||||
)
|
||||
|
||||
set(HDRS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ExportableTableView.h"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/ScrollableMessageBox.h"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TimerEdit.h"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TreeComboBox.h"
|
||||
)
|
||||
|
||||
qt5_wrap_cpp(SRCS ${HDRS})
|
||||
|
||||
add_library(${PROJECT_NAME} ${SRCS} ${HDRS})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Widgets)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE QT_USE_QSTRINGBUILDER)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
# need to push this upstream
|
||||
set(BUILT_LIBRARIES ${BUILT_LIBRARIES} ${PROJECT_NAME} PARENT_SCOPE)
|
||||
@@ -1 +0,0 @@
|
||||
#include "ExportableTableView.h"
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
ExportableTableView
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ExportableTableView.h"
|
||||
|
||||
ExportableTableView::ExportableTableView(QWidget *parent) : QTableView(parent)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setHtmlTemplate(getDefaultHtmlTemplate());
|
||||
|
||||
QAction * selAll = new QAction(tr("Select All"), this);
|
||||
selAll->setShortcut(QKeySequence::SelectAll);
|
||||
addAction(selAll);
|
||||
|
||||
QAction * cpyTab = new QAction(tr("Copy selection as TAB-delimited text"), this);
|
||||
cpyTab->setShortcut(QKeySequence::Copy);
|
||||
cpyTab->setProperty("delim", "\t");
|
||||
addAction(cpyTab);
|
||||
|
||||
QAction * cpyCsv = new QAction(tr("Copy selection as cooma-delimited text (CSV)"), this);
|
||||
cpyCsv->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_C);
|
||||
cpyCsv->setProperty("delim", ", ");
|
||||
addAction(cpyCsv);
|
||||
|
||||
QAction * cpyPipe = new QAction(tr("Copy selection as pipe-delimited text"), this);
|
||||
cpyPipe->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_C);
|
||||
cpyPipe->setProperty("delim", " | ");
|
||||
addAction(cpyPipe);
|
||||
|
||||
QAction * cpyHtml = new QAction(tr("Copy selection as HTML"), this);
|
||||
cpyHtml->setProperty("delim", "html");
|
||||
addAction(cpyHtml);
|
||||
|
||||
QAction * saveFile = new QAction(tr("Save selection to file"), this);
|
||||
saveFile->setShortcut(QKeySequence::Save);
|
||||
addAction(saveFile);
|
||||
|
||||
connect(selAll, &QAction::triggered, this, &QTableView::selectAll);
|
||||
connect(cpyTab, &QAction::triggered, this, &ExportableTableView::copy);
|
||||
connect(cpyCsv, &QAction::triggered, this, &ExportableTableView::copy);
|
||||
connect(cpyPipe, &QAction::triggered, this, &ExportableTableView::copy);
|
||||
connect(cpyHtml, &QAction::triggered, this, &ExportableTableView::copy);
|
||||
connect(saveFile, &QAction::triggered, this, &ExportableTableView::save);
|
||||
connect(this, &QTableView::customContextMenuRequested, this, &ExportableTableView::onCustomContextMenuRequested);
|
||||
}
|
||||
|
||||
QString ExportableTableView::getDefaultHtmlTemplate()
|
||||
{
|
||||
return "<!DOCTYPE html>\n<html>\n<head><meta charset='utf-8'/><style>" \
|
||||
"th, td {font-family: sans-serif; padding: 3px 15px 3px 3px;}" \
|
||||
"</style></head>\n<body>\n" \
|
||||
"<table border=0 cellspacing=2>\n" \
|
||||
"%1" \
|
||||
"</table>\n" \
|
||||
"</body></html>";
|
||||
}
|
||||
|
||||
void ExportableTableView::setHtmlTemplate(const QString &value)
|
||||
{
|
||||
m_htmlTemplate = value;
|
||||
}
|
||||
|
||||
QString ExportableTableView::toPlainText(const QModelIndexList &indexList, const QString &delim) const
|
||||
{
|
||||
QString ret, header;
|
||||
const QChar rowDelim = '\n';
|
||||
bool firstRow = true;
|
||||
for (int i = 0; i < indexList.count(); ++i) {
|
||||
const QModelIndex & idx = indexList.at(i);
|
||||
|
||||
if (firstRow)
|
||||
header.append(model()->headerData(idx.column(), Qt::Horizontal).toString());
|
||||
|
||||
ret.append(idx.data(Qt::DisplayRole).toString());
|
||||
|
||||
if (i + 1 == indexList.count() || indexList.at(i+1).row() != idx.row()) {
|
||||
ret.append(rowDelim);
|
||||
if (firstRow && !header.isEmpty())
|
||||
header.append(rowDelim);
|
||||
firstRow = false;
|
||||
}
|
||||
else {
|
||||
ret.append(delim);
|
||||
if (firstRow && !header.isEmpty())
|
||||
header.append(delim);
|
||||
}
|
||||
}
|
||||
if (!header.isEmpty())
|
||||
ret.prepend(header);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString ExportableTableView::toHtml(const QModelIndexList &indexList) const
|
||||
{
|
||||
QString ret, header, row;
|
||||
bool firstRow = true;
|
||||
|
||||
for (int i = 0; i < indexList.count(); ++i) {
|
||||
const QModelIndex & idx = indexList.at(i);
|
||||
const int algn = (idx.data(Qt::TextAlignmentRole).isValid() ? idx.data(Qt::TextAlignmentRole).toInt() : (Qt::AlignLeft | Qt::AlignVCenter));
|
||||
const QString fg = (idx.data(Qt::ForegroundRole).isValid() ? idx.data(Qt::ForegroundRole).value<QBrush>().color().name(QColor::HexRgb) : "initial");
|
||||
const QString bg = (idx.data(Qt::BackgroundRole).isValid() ? idx.data(Qt::BackgroundRole).value<QBrush>().color().name(QColor::HexRgb) : "initial");
|
||||
const QString ttl = (idx.data(Qt::ToolTipRole).isValid() ? idx.data(Qt::ToolTipRole).toString().replace("\"", "\"\"") : QString());
|
||||
|
||||
QString fnt;
|
||||
if (idx.data(Qt::FontRole).isValid()) {
|
||||
const QFont font = idx.data(Qt::FontRole).value<QFont>();
|
||||
fnt = "font: \"" % font.family() % "\" " % QString::number(font.pointSize()) % "pt;";
|
||||
}
|
||||
|
||||
if (firstRow)
|
||||
header.append(QString("<th align='left'>%1</th>\n").arg(model()->headerData(idx.column(), Qt::Horizontal).toString()));
|
||||
|
||||
row.append("<td style='color: %2; background-color: %3; %4' align='%5' valign='%6' %7>%1</td>\n"); // cell template
|
||||
row = row.arg(idx.data(Qt::DisplayRole).toString()).arg(fg).arg(bg).arg(fnt);
|
||||
row = row.arg((algn & Qt::AlignRight) ? "right" : (algn & Qt::AlignHCenter) ? "center" : "left");
|
||||
row = row.arg((algn & Qt::AlignTop) ? "top" : (algn & Qt::AlignBottom) ? "bottom" : "middle");
|
||||
row = row.arg(ttl.isEmpty() ? ttl : QString("title=\"%1\"").arg(ttl));
|
||||
|
||||
if (i + 1 == indexList.count() || indexList.at(i+1).row() != idx.row()) {
|
||||
ret.append(QString("<tr>\n%1</tr>\n").arg(row));
|
||||
row.clear();
|
||||
firstRow = false;
|
||||
}
|
||||
}
|
||||
|
||||
ret = QString("<tbody>\n%1</tbody>\n").arg(ret);
|
||||
if (!header.isEmpty())
|
||||
ret.prepend(QString("<thead>\n<tr>\n%1</tr>\n</thead>\n").arg(header));
|
||||
ret = m_htmlTemplate.arg(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ExportableTableView::saveToFile(const QModelIndexList &indexList, const QString &fileName)
|
||||
{
|
||||
static QString lastDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
|
||||
if (indexList.isEmpty())
|
||||
return false;
|
||||
|
||||
QString fname = fileName;
|
||||
if (fname.isEmpty()) {
|
||||
QString types = tr("Tab-delimited text") % " (*.tab);;" % tr("Comma-delimited text") % " (*.csv);;" % tr("Pipe-delimited text") % " (*.txt);;" % tr("HTML") % " (*.html)";
|
||||
fname = QFileDialog::getSaveFileName(this, tr("Save to file"), lastDir, types);
|
||||
}
|
||||
|
||||
if (fname.isEmpty())
|
||||
return false;
|
||||
|
||||
QFile file(fname);
|
||||
QFileInfo fi(file);
|
||||
lastDir = fi.absolutePath();
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return false;
|
||||
|
||||
if (fi.suffix() == "html")
|
||||
file.write(toHtml(indexList).toUtf8());
|
||||
else
|
||||
file.write(toPlainText(indexList, (fi.suffix() == "tab" ? "\t" : fi.suffix() == "csv" ? ", " : " | ")).toUtf8());
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QSize ExportableTableView::sizeHint() const
|
||||
{
|
||||
int w = 0;
|
||||
for (int i = 0; i < model()->columnCount(); ++i)
|
||||
w += sizeHintForColumn(i);
|
||||
return QSize(w + verticalScrollBar()->sizeHint().width() + 60, sizeHintForRow(0) * model()->rowCount());
|
||||
}
|
||||
|
||||
void ExportableTableView::copyText(const QString &delim)
|
||||
{
|
||||
QApplication::clipboard()->setText(toPlainText(getSelectedOrAll(), delim));
|
||||
}
|
||||
|
||||
void ExportableTableView::copyHtml()
|
||||
{
|
||||
QMimeData * mdata = new QMimeData;
|
||||
mdata->setHtml(toHtml(getSelectedOrAll()));
|
||||
QApplication::clipboard()->setMimeData(mdata);
|
||||
}
|
||||
|
||||
void ExportableTableView::copy()
|
||||
{
|
||||
QString delim = "\t";
|
||||
if (sender() && sender()->property("delim").isValid())
|
||||
delim = sender()->property("delim").toString();
|
||||
if (delim == "html")
|
||||
copyHtml();
|
||||
else
|
||||
copyText(delim);
|
||||
}
|
||||
|
||||
void ExportableTableView::save()
|
||||
{
|
||||
saveToFile(getSelectedOrAll());
|
||||
}
|
||||
|
||||
QModelIndexList ExportableTableView::getSelectedOrAll()
|
||||
{
|
||||
QModelIndexList sel = selectionModel()->selectedIndexes();
|
||||
if (sel.isEmpty()) {
|
||||
selectAll();
|
||||
sel = selectionModel()->selectedIndexes();
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
void ExportableTableView::onCustomContextMenuRequested(const QPoint & pos)
|
||||
{
|
||||
QMenu menu;
|
||||
menu.addActions(actions());
|
||||
menu.exec(mapToGlobal(pos));
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
ExportableTableView
|
||||
https://github.com/mpaperno/maxLibQt
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXPORTABLETABLEVIEW_H
|
||||
#define EXPORTABLETABLEVIEW_H
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QScrollBar>
|
||||
#include <QStandardPaths>
|
||||
#include <QTableView>
|
||||
|
||||
/**
|
||||
\class ExportableTableView
|
||||
\version 1.0.0
|
||||
|
||||
\brief The ExportableTableView class provides a regular QTableView but with features to export the data
|
||||
as plain text or HTML.
|
||||
|
||||
Any selection of data can be exported. The horizontal headings, if any, are included in the export.
|
||||
The export functions are available to the user via a custom context menu or keyboard shortcuts.
|
||||
3 field delimiter choices are available for plain-text export (tab, comma, or pipe).
|
||||
Data can be saved to the clipboard or to a file.
|
||||
|
||||
The export functions can also be accessed programmatically via \c toPlainText(), \c toHtml(),
|
||||
and \c saveToFile().
|
||||
|
||||
The overall HTML template can be customized by setting \c setHtmlTemplate(). The data itself is always
|
||||
formatted as a basic HTML table and then inserted into the template at the \c %1 placeholder.
|
||||
HTML version tries to preserve many data role attributes of the model items:
|
||||
|
||||
\li \c Qt::FontRole
|
||||
\li \c Qt::ForegroundRole
|
||||
\li \c Qt::BackgroundRole
|
||||
\li \c Qt::TextAlignmentRole
|
||||
\li \c Qt::ToolTipRole
|
||||
|
||||
Note that \c Qt::EditRole data is not specifically preserved (unless it already matches \c Qt::DisplayRole ).
|
||||
|
||||
*/
|
||||
class ExportableTableView : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportableTableView(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
static QString getDefaultHtmlTemplate();
|
||||
void setHtmlTemplate(const QString &value);
|
||||
|
||||
QString toPlainText(const QModelIndexList &indexList, const QString &delim = "\t") const;
|
||||
QString toHtml(const QModelIndexList &indexList) const;
|
||||
bool saveToFile(const QModelIndexList &indexList, const QString &fileName = QString());
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
void copyText(const QString &delim = QString("\t"));
|
||||
void copyHtml();
|
||||
void copy();
|
||||
void save();
|
||||
QModelIndexList getSelectedOrAll();
|
||||
|
||||
protected:
|
||||
void onCustomContextMenuRequested(const QPoint &pos);
|
||||
|
||||
QString m_htmlTemplate;
|
||||
};
|
||||
|
||||
#endif // EXPORTABLETABLEVIEW_H
|
||||
@@ -1 +0,0 @@
|
||||
#include "TimerEdit.h"
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
TimerEdit
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TimerEdit.h"
|
||||
#include <cmath>
|
||||
|
||||
TimerEdit::TimerEdit(QWidget *parent) :
|
||||
QLineEdit(parent),
|
||||
m_showSeconds(true),
|
||||
m_minTime(0),
|
||||
m_maxTime(24 * 3600 - 1),
|
||||
m_singleStep(1),
|
||||
m_pageStep(60),
|
||||
m_hourDigits(2),
|
||||
m_validator(new QRegularExpressionValidator(this))
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
setupFormat();
|
||||
setToolTip(tr("Use mouse scroll or UP/DOWN arrow keys to change time in small steps.\nCTRL + scroll or PAGE UP/DOWN keys to change time in larger steps."));
|
||||
connect(this, &TimerEdit::textEdited, this, &TimerEdit::textEditedHandler);
|
||||
}
|
||||
|
||||
int TimerEdit::timeInSeconds() const
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret += timepart(text(), TimeParts::Hours) * 3600;
|
||||
ret += timepart(text(), TimeParts::Minutes) * 60;
|
||||
ret += timepart(text(), TimeParts::Seconds);
|
||||
ret *= timepart(text(), TimeParts::Polarity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TimerEdit::timepart(const QString &input, TimerEdit::TimeParts part) const
|
||||
{
|
||||
int ret = 0;
|
||||
QRegularExpressionMatch match = m_validator->regularExpression().match(input, 0, QRegularExpression::NormalMatch);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
switch (part) {
|
||||
case Hours:
|
||||
if (!match.captured("hrs").isEmpty())
|
||||
ret = match.captured("hrs").toInt();
|
||||
break;
|
||||
|
||||
case Minutes:
|
||||
if (!match.captured("mins").isEmpty())
|
||||
ret = match.captured("mins").toInt();
|
||||
break;
|
||||
|
||||
case Seconds:
|
||||
if (!match.captured("secs").isEmpty())
|
||||
ret = match.captured("secs").toInt();
|
||||
break;
|
||||
|
||||
case Polarity:
|
||||
if (!match.captured("pol").isEmpty() && !match.captured("pol").compare("-"))
|
||||
ret = -1;
|
||||
else
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//// Slots ////
|
||||
|
||||
void TimerEdit::setTime(int seconds)
|
||||
{
|
||||
if (seconds > m_maxTime)
|
||||
seconds = m_maxTime;
|
||||
else if (seconds < m_minTime)
|
||||
seconds = m_minTime;
|
||||
|
||||
div_t qrM = div(abs(seconds), 60);
|
||||
div_t qrH = div(qrM.quot, 60);
|
||||
|
||||
QString val = QString("%1").arg(qrH.rem, 2, 10, QChar('0'));
|
||||
|
||||
if (m_hourDigits)
|
||||
val.prepend(QString("%1:").arg(qrH.quot, m_hourDigits, 10, QChar('0')));
|
||||
|
||||
if (m_showSeconds)
|
||||
val.append(QString(":%1").arg(qrM.rem, 2, 10, QChar('0')));
|
||||
|
||||
if (m_minTime < 0) {
|
||||
if (seconds < 0)
|
||||
val.prepend("-");
|
||||
else
|
||||
val.prepend(" ");
|
||||
}
|
||||
|
||||
if (text().compare(val)) {
|
||||
setText(val);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::incrDecr(int seconds)
|
||||
{
|
||||
if (!seconds)
|
||||
return;
|
||||
|
||||
const int cs = timeInSeconds();
|
||||
int s = seconds + cs;
|
||||
if (s < m_minTime)
|
||||
s = m_minTime;
|
||||
if (s > m_maxTime)
|
||||
s = m_maxTime;
|
||||
if (s != cs) {
|
||||
setTime(s);
|
||||
emitValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::setTimeRange(int minSeconds, int maxSeconds)
|
||||
{
|
||||
if (minSeconds <= maxSeconds && (m_minTime != minSeconds || m_maxTime != maxSeconds)) {
|
||||
int digits = 0;
|
||||
if (maxSeconds >= 3600)
|
||||
digits = floorf(logf(round(maxSeconds / 3600)) / logf(10.0f)) + 1;
|
||||
|
||||
bool mod = (m_hourDigits != digits || std::signbit((float)m_minTime) != std::signbit((float)minSeconds));
|
||||
|
||||
m_minTime = minSeconds;
|
||||
m_maxTime = maxSeconds;
|
||||
m_hourDigits = digits;
|
||||
|
||||
if (mod)
|
||||
setupFormat();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::setMinimumTime(int minSeconds)
|
||||
{
|
||||
setTimeRange(minSeconds, (m_maxTime > minSeconds ? m_maxTime : minSeconds));
|
||||
}
|
||||
|
||||
void TimerEdit::setMaximumTime(int maxSeconds)
|
||||
{
|
||||
setTimeRange((m_minTime < maxSeconds ? m_minTime : maxSeconds), maxSeconds);
|
||||
}
|
||||
|
||||
void TimerEdit::setShowSeconds(bool showSeconds)
|
||||
{
|
||||
if (m_showSeconds != showSeconds) {
|
||||
m_showSeconds = showSeconds;
|
||||
setupFormat();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// Protected ////
|
||||
|
||||
void TimerEdit::textEditedHandler()
|
||||
{
|
||||
int sec = timeInSeconds();
|
||||
if (sec < m_minTime)
|
||||
setTime(m_minTime);
|
||||
else if (sec > m_maxTime)
|
||||
setTime(m_maxTime);
|
||||
else
|
||||
return;
|
||||
|
||||
emitValueChanged();
|
||||
}
|
||||
|
||||
void TimerEdit::setupFormat()
|
||||
{
|
||||
QString inputRe = "(?<mins>[0-5][0-9])";
|
||||
QString inputMsk = "99";
|
||||
QString suffx = "\\" % tr("m") % "\\" % tr("m");
|
||||
|
||||
if (m_hourDigits) {
|
||||
inputRe.prepend("(?<hrs>[0-9]*[0-9]):");
|
||||
inputMsk.prepend(":");
|
||||
suffx.prepend(":");
|
||||
for (int i=0; i < m_hourDigits; ++i) {
|
||||
inputMsk.prepend("9");
|
||||
suffx.prepend("\\" % tr("h"));
|
||||
}
|
||||
}
|
||||
if (m_showSeconds) {
|
||||
inputRe.append(":(?<secs>[0-5][0-9])");
|
||||
inputMsk.append(":99");
|
||||
suffx.append(":\\" % tr("s") % "\\" % tr("s"));
|
||||
}
|
||||
if (m_minTime < 0) {
|
||||
inputRe.prepend("(?<pol>-|\\+|\\s)?");
|
||||
inputMsk.prepend("#");
|
||||
}
|
||||
|
||||
inputRe.prepend("^");
|
||||
inputRe.append("\\s?\\[[^\\]]+\\]$");
|
||||
inputMsk.append(" \\[" % suffx % "\\]");
|
||||
|
||||
m_validator->setRegularExpression(QRegularExpression(inputRe));
|
||||
|
||||
setInputMask(inputMsk);
|
||||
setValidator(m_validator);
|
||||
}
|
||||
|
||||
void TimerEdit::emitValueChanged()
|
||||
{
|
||||
emit QLineEdit::textEdited(text());
|
||||
}
|
||||
|
||||
void TimerEdit::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Up:
|
||||
incrDecr(m_singleStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
incrDecr(-(int)m_singleStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_PageUp:
|
||||
incrDecr(m_pageStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_PageDown:
|
||||
incrDecr(-(int)m_pageStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_Plus:
|
||||
case Qt::Key_Equal:
|
||||
case Qt::Key_Minus:
|
||||
if (m_minTime < 0) {
|
||||
setTime(-timeInSeconds());
|
||||
emitValueChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
QLineEdit::keyPressEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (event->angleDelta().isNull()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
int numSteps = -event->angleDelta().y() / 8 / 15 * -1; // one step per 15deg
|
||||
numSteps *= (event->modifiers() & Qt::ControlModifier) ? m_pageStep : m_singleStep;
|
||||
incrDecr(numSteps);
|
||||
event->accept();
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
TimerEdit
|
||||
https://github.com/mpaperno/maxLibQt
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TIMEREDIT_H
|
||||
#define TIMEREDIT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QKeyEvent>
|
||||
#include <QWheelEvent>
|
||||
|
||||
/**
|
||||
\class TimerEdit
|
||||
\version 1.0.0
|
||||
|
||||
\brief A time value line editor which accepts negative and large times (> 23:59:59), suitable for a timer, etc.
|
||||
|
||||
Qt's \c QTimeEdit has a limitation in that it can only accept "valid" times, in the range of 0:00:00 to 23:59:59.
|
||||
The TimerEdit control aims to address that. It allows any amount of time to be entered, as well as negative times.
|
||||
It provides a mask for data entry, a validator with settable min/max times, and increment/decrement via keyboard
|
||||
or mouse wheel in configurable steps.
|
||||
|
||||
Data I/O is in seconds only, that is you set the time value in total seconds and also read it back in seconds
|
||||
(there is no conversion from/to a \e QTime object).
|
||||
|
||||
*/
|
||||
class TimerEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int minimumTime READ minimumTime WRITE setMinimumTime)
|
||||
Q_PROPERTY(int maximumTime READ maximumTime WRITE setMaximumTime)
|
||||
Q_PROPERTY(bool showSeconds READ showSeconds WRITE setShowSeconds)
|
||||
Q_PROPERTY(unsigned int singleStep READ singleStep WRITE setSingleStep)
|
||||
Q_PROPERTY(unsigned int pageStep READ pageStep WRITE setPageStep)
|
||||
|
||||
|
||||
public:
|
||||
enum TimeParts {Whole, Polarity, Hours, Minutes, Seconds};
|
||||
|
||||
TimerEdit(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
int timeInSeconds() const;
|
||||
int timepart(const QString &input, TimeParts part) const;
|
||||
|
||||
bool showSeconds() const { return m_showSeconds; }
|
||||
int minimumTime() const { return m_minTime; }
|
||||
int maximumTime() const { return m_maxTime; }
|
||||
unsigned int singleStep() const { return m_singleStep; }
|
||||
unsigned int pageStep() const { return m_pageStep; }
|
||||
|
||||
public slots:
|
||||
void setTime(int seconds);
|
||||
void incrDecr(int seconds);
|
||||
void setTimeRange(int minSeconds, int maxSeconds);
|
||||
void setMinimumTime(int minSeconds);
|
||||
void setMaximumTime(int maxSeconds);
|
||||
void setShowSeconds(bool showSeconds);
|
||||
|
||||
void setSingleStep(unsigned int step) { m_singleStep = step; }
|
||||
void setPageStep(unsigned int pageStep) { m_pageStep = pageStep; }
|
||||
|
||||
protected:
|
||||
void textEditedHandler();
|
||||
virtual void setupFormat();
|
||||
void emitValueChanged();
|
||||
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
|
||||
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
bool m_showSeconds;
|
||||
int m_minTime; // seconds
|
||||
int m_maxTime; // seconds
|
||||
unsigned m_singleStep; // seconds
|
||||
unsigned m_pageStep; // seconds
|
||||
short m_hourDigits;
|
||||
QRegularExpressionValidator * m_validator;
|
||||
};
|
||||
|
||||
#endif // TIMEREDIT_H
|
||||
Reference in New Issue
Block a user