From: Manuel Nickschas Date: Thu, 18 Sep 2008 22:26:04 +0000 (+0200) Subject: Finally sanitizificat0red the mess and #ifdef hell with main.cpp, Global:: and friends X-Git-Tag: 0.3.1~273 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=5c6804f291a63f978e328aeddcc8448e3443b45e Finally sanitizificat0red the mess and #ifdef hell with main.cpp, Global:: and friends This replaces #ifdefs mostly by OO stuff, i.e. we now have a class hierarchy in place for initializing the application. Also, namespace Global:: is gone[1]; most of its functionality is part of the new Quassel object now which encapsulates common app stuff. You should clean (rm -rf) your build dir, as these changes are quite invasive. [1] Some remnants are still there until I get around to redesigning genversion, and actually fill Quassel::buildInfo() with data. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3601b0fe..650720a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,7 +239,7 @@ endmacro(setup_qt4_variables) # Now we have everything, so just glue the right pieces together :) if(WANT_CORE) setup_qt4_variables(NETWORK SCRIPT SQL) - add_executable(quasselcore ${CMAKE_SOURCE_DIR}/src/common/main.cpp + add_executable(quasselcore src/common/main.cpp ${RC_SQL} ${RC_I18N} ${WIN32_RC}) set_target_properties(quasselcore PROPERTIES COMPILE_FLAGS "-DQT_NETWORK_LIB -DQT_SCRIPT_LIB -DQT_SQL_LIB -DBUILD_CORE") @@ -249,7 +249,7 @@ endif(WANT_CORE) if(WANT_QTCLIENT) setup_qt4_variables(${LINK_DBUS} GUI NETWORK) - add_executable(quasselclient WIN32 ${CMAKE_SOURCE_DIR}/src/common/main.cpp + add_executable(quasselclient WIN32 src/common/main.cpp ${RC_ICONS} ${RC_QUASSEL_ICONS} ${RC_I18N} ${WIN32_RC}) set_target_properties(quasselclient PROPERTIES COMPILE_FLAGS "-DQT_GUI_LIB -DQT_NETWORK_LIB -DBUILD_QTUI") @@ -259,7 +259,7 @@ endif(WANT_QTCLIENT) if(WANT_MONO) setup_qt4_variables(${LINK_DBUS} GUI NETWORK SCRIPT SQL) - add_executable(quassel WIN32 ${CMAKE_SOURCE_DIR}/src/common/main.cpp + add_executable(quassel WIN32 src/common/main.cpp src/qtui/monoapplication.cpp ${RC_ICONS} ${RC_QUASSEL_ICONS} ${RC_SQL} ${RC_I18N} ${WIN32_RC}) set_target_properties(quassel PROPERTIES COMPILE_FLAGS "-DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_SCRIPT_LIB -DQT_SQL_LIB -DBUILD_MONO") diff --git a/src/client/buffermodel.cpp b/src/client/buffermodel.cpp index 9c8df06f..de415503 100644 --- a/src/client/buffermodel.cpp +++ b/src/client/buffermodel.cpp @@ -20,19 +20,19 @@ #include "buffermodel.h" +#include + #include "client.h" -#include "global.h" #include "mappedselectionmodel.h" #include "networkmodel.h" - -#include +#include "quassel.h" BufferModel::BufferModel(NetworkModel *parent) : QSortFilterProxyModel(parent), _selectionModelSynchronizer(this) { setSourceModel(parent); - if(Global::parser.isSet("debugbufferswitches")) { + if(Quassel::isOptionSet("debugbufferswitches")) { connect(_selectionModelSynchronizer.selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(debug_currentChanged(const QModelIndex &, const QModelIndex &))); } diff --git a/src/client/client.cpp b/src/client/client.cpp index a53d07d7..9611f71b 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -28,7 +28,6 @@ #include "bufferviewmanager.h" #include "clientbacklogmanager.h" #include "clientirclisthelper.h" -#include "global.h" #include "identity.h" #include "ircchannel.h" #include "ircuser.h" @@ -52,8 +51,11 @@ Client *Client::instance() { } void Client::destroy() { - //delete instanceptr; - instanceptr->deleteLater(); + if(instanceptr) { + delete instanceptr->mainUi; + instanceptr->deleteLater(); + instanceptr = 0; + } } void Client::init(AbstractUi *ui) { diff --git a/src/client/clientsettings.cpp b/src/client/clientsettings.cpp index 3a1dbd88..980bb2f6 100644 --- a/src/client/clientsettings.cpp +++ b/src/client/clientsettings.cpp @@ -18,13 +18,13 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include + #include "client.h" #include "clientsettings.h" -#include "global.h" - -#include +#include "quassel.h" -ClientSettings::ClientSettings(QString g) : Settings(g, Global::clientApplicationName) { +ClientSettings::ClientSettings(QString g) : Settings(g, Quassel::buildInfo().clientApplicationName) { } ClientSettings::~ClientSettings() { diff --git a/src/client/clientsyncer.cpp b/src/client/clientsyncer.cpp index b65ba566..e24d8300 100644 --- a/src/client/clientsyncer.cpp +++ b/src/client/clientsyncer.cpp @@ -25,15 +25,14 @@ #endif #include "client.h" -#include "global.h" #include "identity.h" #include "ircuser.h" #include "ircchannel.h" #include "network.h" #include "networkmodel.h" +#include "quassel.h" #include "signalproxy.h" - ClientSyncer::ClientSyncer(QObject *parent) : QObject(parent) { diff --git a/src/client/treemodel.cpp b/src/client/treemodel.cpp index 4933f0d9..36cb8d6a 100644 --- a/src/client/treemodel.cpp +++ b/src/client/treemodel.cpp @@ -19,10 +19,11 @@ ***************************************************************************/ #include "treemodel.h" -#include "global.h" -#include #include +#include + +#include "quassel.h" class RemoveChildLaterEvent : public QEvent { public: @@ -54,7 +55,7 @@ bool AbstractTreeItem::newChild(AbstractTreeItem *item) { bool AbstractTreeItem::newChilds(const QList &items) { if(items.isEmpty()) return false; - + int nextRow = childCount(); int lastRow = nextRow + items.count() - 1; @@ -76,16 +77,16 @@ bool AbstractTreeItem::removeChild(int row) { emit endRemoveChilds(); checkForDeletion(); - + return true; } void AbstractTreeItem::removeAllChilds() { const int numChilds = childCount(); - + if(numChilds == 0) return; - + AbstractTreeItem *child; QList::iterator childIter; @@ -140,7 +141,7 @@ bool AbstractTreeItem::reParent(AbstractTreeItem *newParent) { int oldRow = row(); if(oldRow == -1) return false; - + emit parent()->beginRemoveChilds(oldRow, oldRow); parent()->_childItems.removeAt(oldRow); emit parent()->endRemoveChilds(); @@ -177,7 +178,7 @@ int AbstractTreeItem::row() const { qWarning() << "AbstractTreeItem::row():" << this << "has no parent AbstractTreeItem as it's parent! parent is" << QObject::parent(); return -1; } - + int row_ = parent()->_childItems.indexOf(const_cast(this)); if(row_ == -1) qWarning() << "AbstractTreeItem::row():" << this << "is not in the child list of" << QObject::parent(); @@ -195,7 +196,7 @@ void AbstractTreeItem::dumpChildList() { childIter++; } } - qDebug() << "==== End Of Childlist ===="; + qDebug() << "==== End Of Childlist ===="; } /***************************************** @@ -252,7 +253,7 @@ PropertyMapItem::PropertyMapItem(AbstractTreeItem *parent) PropertyMapItem::~PropertyMapItem() { } - + QVariant PropertyMapItem::data(int column, int role) const { if(column >= columnCount()) return QVariant(); @@ -266,7 +267,7 @@ QVariant PropertyMapItem::data(int column, int role) const { default: return QVariant(); } - + } bool PropertyMapItem::setData(int column, const QVariant &value, int role) { @@ -280,7 +281,7 @@ bool PropertyMapItem::setData(int column, const QVariant &value, int role) { int PropertyMapItem::columnCount() const { return _propertyOrder.count(); } - + void PropertyMapItem::appendProperty(const QString &property) { _propertyOrder << property; } @@ -298,7 +299,7 @@ TreeModel::TreeModel(const QList &data, QObject *parent) rootItem = new SimpleTreeItem(data, 0); connectItem(rootItem); - if(Global::parser.isSet("debugmodel")) { + if(Quassel::isOptionSet("debugmodel")) { connect(this, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), this, SLOT(debug_rowsAboutToBeInserted(const QModelIndex &, int, int))); connect(this, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), @@ -319,14 +320,14 @@ TreeModel::~TreeModel() { QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if(!hasIndex(row, column, parent)) return QModelIndex(); - + AbstractTreeItem *parentItem; - + if(!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); - + AbstractTreeItem *childItem = parentItem->child(row); if(childItem) @@ -340,7 +341,7 @@ QModelIndex TreeModel::indexByItem(AbstractTreeItem *item) const { qWarning() << "TreeModel::indexByItem(AbstractTreeItem *item) received NULL-Pointer"; return QModelIndex(); } - + if(item == rootItem) return QModelIndex(); else @@ -352,14 +353,14 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const { qWarning() << "TreeModel::parent(): has been asked for the rootItems Parent!"; return QModelIndex(); } - + AbstractTreeItem *childItem = static_cast(index.internalPointer()); AbstractTreeItem *parentItem = childItem->parent(); Q_ASSERT(parentItem); if(parentItem == rootItem) return QModelIndex(); - + return createIndex(parentItem->row(), 0, parentItem); } @@ -442,12 +443,12 @@ void TreeModel::itemDataChanged(int column) { void TreeModel::connectItem(AbstractTreeItem *item) { connect(item, SIGNAL(dataChanged(int)), this, SLOT(itemDataChanged(int))); - + connect(item, SIGNAL(beginAppendChilds(int, int)), this, SLOT(beginAppendChilds(int, int))); connect(item, SIGNAL(endAppendChilds()), this, SLOT(endAppendChilds())); - + connect(item, SIGNAL(beginRemoveChilds(int, int)), this, SLOT(beginRemoveChilds(int, int))); connect(item, SIGNAL(endRemoveChilds()), @@ -463,7 +464,7 @@ void TreeModel::beginAppendChilds(int firstRow, int lastRow) { QModelIndex parent = indexByItem(parentItem); Q_ASSERT(!_aboutToRemoveOrInsert); - + _aboutToRemoveOrInsert = true; _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); beginInsertRows(parent, firstRow, lastRow); @@ -498,7 +499,7 @@ void TreeModel::beginRemoveChilds(int firstRow, int lastRow) { for(int i = firstRow; i <= lastRow; i++) { disconnect(parentItem->child(i), 0, this, 0); } - + // consitency checks QModelIndex parent = indexByItem(parentItem); Q_ASSERT(firstRow <= lastRow); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7807157e..3dfd92a0 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -11,18 +11,18 @@ set(SOURCES buffersyncer.cpp bufferviewconfig.cpp bufferviewmanager.cpp - global.cpp + cliparser.cpp identity.cpp + ircchannel.cpp + ircuser.cpp logger.cpp message.cpp + network.cpp + quassel.cpp settings.cpp signalproxy.cpp syncableobject.cpp - util.cpp - network.cpp - ircuser.cpp - ircchannel.cpp - cliparser.cpp) + util.cpp) set(MOC_HDRS aliasmanager.h @@ -42,12 +42,11 @@ set(MOC_HDRS set(HEADERS ${MOC_HDRS} bufferinfo.h - global.h + cliparser.h logger.h message.h types.h - util.h - cliparser.h) + util.h) qt4_wrap_cpp(MOC ${MOC_HDRS}) diff --git a/src/common/cliparser.cpp b/src/common/cliparser.cpp index c4ca9b8c..a34af80a 100644 --- a/src/common/cliparser.cpp +++ b/src/common/cliparser.cpp @@ -24,11 +24,6 @@ #include #include -CliParser::CliParser(QStringList arguments) -{ - argsRaw = arguments; -} - void CliParser::addArgument(const QString &longName, const CliParserArg &arg) { if(argsHash.contains(longName)) qWarning() << "Warning: Multiple definition of argument" << longName; if(arg.shortName != 0 && !lnameOfShortArg(arg.shortName).isNull()) @@ -82,7 +77,8 @@ QString CliParser::escapedValue(const QString &value) { return escapedValue; } -bool CliParser::parse() { +bool CliParser::parse(const QStringList &args) { + argsRaw = args; QStringList::const_iterator currentArg; for (currentArg = argsRaw.constBegin(); currentArg != argsRaw.constEnd(); ++currentArg) { if(currentArg->startsWith("--")) { @@ -147,7 +143,7 @@ bool CliParser::parse() { void CliParser::usage() { qWarning() << "Usage:" << QFileInfo(argsRaw.at(0)).completeBaseName() << "[arguments]"; - + // get size of longName field QStringList keys = argsHash.keys(); uint lnameFieldSize = 0; @@ -161,12 +157,12 @@ void CliParser::usage() { size += 8; if(size > lnameFieldSize) lnameFieldSize = size; } - + QHash::const_iterator arg; for(arg = argsHash.constBegin(); arg != argsHash.constEnd(); ++arg) { QString output; QString lnameField; - + if(arg.value().shortName) { output.append(" -").append(arg.value().shortName).append(","); } diff --git a/src/common/cliparser.h b/src/common/cliparser.h index 5d83bcba..0cdfcaf1 100644 --- a/src/common/cliparser.h +++ b/src/common/cliparser.h @@ -28,9 +28,8 @@ class CliParser{ public: inline CliParser() {}; - CliParser(QStringList arguments); - bool parse(); + bool parse(const QStringList &arguments); QString value(const QString &longName); bool isSet(const QString &longName); inline void addSwitch(const QString &longName, const char shortName = 0, const QString &help = QString()) { @@ -55,7 +54,7 @@ private: def(_def), value(QString()), boolValue(false) {}; - + CliArgType type; char shortName; QString help; @@ -63,12 +62,13 @@ private: QString value; bool boolValue; }; - + void addArgument(const QString &longName, const CliParserArg &arg); bool addLongArg(const CliParserArg::CliArgType type, const QString &name, const QString &value = QString()); bool addShortArg(const CliParserArg::CliArgType type, const char shortName, const QString &value = QString()); QString escapedValue(const QString &value); QString lnameOfShortArg(const char arg); + QStringList argsRaw; QHash argsHash; }; diff --git a/src/common/global.cpp b/src/common/global.cpp deleted file mode 100644 index 13f242c7..00000000 --- a/src/common/global.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) version 3. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include -#include - -#include "global.h" -#include "message.h" -#include "identity.h" -#include "network.h" -#include "bufferinfo.h" -#include "types.h" -#include "syncableobject.h" - -extern void messageHandler(QtMsgType type, const char *msg); - -/* not done yet */ -/* -void Global::initIconMap() { -// Do not depend on GUI in core! - QDomDocument doc("IconMap"); - QFile file("images/iconmap.xml"); - if(!file.open(QIODevice::ReadOnly)) { - qDebug() << "Error opening iconMap file!"; - return; - } else if(!doc.setContent(&file)) { - file.close(); - qDebug() << "Error parsing iconMap file!"; - } else { - file.close(); - - } -} -*/ - -/** - * Retrieves an icon determined by its symbolic name. The mapping shall later - * be performed by a theme manager or something like that. - * @param symbol Symbol of requested icon - * @return Pointer to a newly created QIcon - */ -// -//QIcon *Global::getIcon(QString /*symbol*/) { - //if(symbol == "connect" - -// return 0; -//} - -//! Register our custom types with Qt's Meta Object System. -/** This makes them available for QVariant and in signals/slots, among other things. - * - */ -void Global::registerMetaTypes() { - // Complex types - qRegisterMetaType("QVariant"); - qRegisterMetaType("Message"); - qRegisterMetaType("BufferInfo"); - qRegisterMetaType("NetworkInfo"); - qRegisterMetaType("Identity"); - qRegisterMetaType("Network::ConnectionState"); - - qRegisterMetaTypeStreamOperators("QVariant"); - qRegisterMetaTypeStreamOperators("Message"); - qRegisterMetaTypeStreamOperators("BufferInfo"); - qRegisterMetaTypeStreamOperators("NetworkInfo"); - qRegisterMetaTypeStreamOperators("Identity"); - qRegisterMetaTypeStreamOperators("Network::ConnectionState"); - - qRegisterMetaType("IdentityId"); - qRegisterMetaType("BufferId"); - qRegisterMetaType("NetworkId"); - qRegisterMetaType("UserId"); - qRegisterMetaType("AccountId"); - qRegisterMetaType("MsgId"); - - qRegisterMetaTypeStreamOperators("IdentityId"); - qRegisterMetaTypeStreamOperators("BufferId"); - qRegisterMetaTypeStreamOperators("NetworkId"); - qRegisterMetaTypeStreamOperators("UserId"); - qRegisterMetaTypeStreamOperators("AccountId"); - qRegisterMetaTypeStreamOperators("MsgId"); -} - -//! This includes version.inc and possibly version.gen and sets up our version numbers. -void Global::setupVersion() { - -# include "version.inc" -# include "version.gen" - - if(quasselGeneratedVersion.isEmpty()) { - if(quasselCommit.isEmpty()) - quasselVersion = QString("v%1 (unknown rev)").arg(quasselBaseVersion); - else - quasselVersion = QString("v%1 (dist-%2, %3)").arg(quasselBaseVersion).arg(quasselCommit.left(7)) - .arg(QDateTime::fromTime_t(quasselArchiveDate).toLocalTime().toString("yyyy-MM-dd")); - } else { - QStringList parts = quasselGeneratedVersion.split(':'); - quasselVersion = QString("v%1").arg(parts[0]); - if(parts.count() >= 2) quasselVersion.append(QString(" (%1)").arg(parts[1])); - } - quasselBuildDate = __DATE__; - quasselBuildTime = __TIME__; -} - -// Static variables - -QString Global::quasselVersion; -QString Global::quasselBaseVersion; -QString Global::quasselGeneratedVersion; -QString Global::quasselBuildDate; -QString Global::quasselBuildTime; -QString Global::quasselCommit; -uint Global::quasselArchiveDate; -uint Global::protocolVersion; -uint Global::clientNeedsProtocol; -uint Global::coreNeedsProtocol; - -Global::RunMode Global::runMode; -uint Global::defaultPort; - -bool Global::DEBUG; -CliParser Global::parser; diff --git a/src/common/logger.cpp b/src/common/logger.cpp index 59efa6b6..fbee7248 100644 --- a/src/common/logger.cpp +++ b/src/common/logger.cpp @@ -19,7 +19,7 @@ ***************************************************************************/ #include "logger.h" -#include "global.h" +#include "quassel.h" #include #include @@ -37,10 +37,10 @@ Logger::~Logger() { void Logger::log() { LogLevel lvl; - if (Global::parser.value("loglevel") == "Debug") lvl = DebugLevel; - else if (Global::parser.value("loglevel") == "Info") lvl = InfoLevel; - else if (Global::parser.value("loglevel") == "Warning") lvl = WarningLevel; - else if (Global::parser.value("loglevel") == "Error") lvl = ErrorLevel; + if (Quassel::optionValue("loglevel") == "Debug") lvl = DebugLevel; + else if (Quassel::optionValue("loglevel") == "Info") lvl = InfoLevel; + else if (Quassel::optionValue("loglevel") == "Warning") lvl = WarningLevel; + else if (Quassel::optionValue("loglevel") == "Error") lvl = ErrorLevel; else lvl = InfoLevel; if(_logLevel < lvl) return; @@ -48,8 +48,8 @@ void Logger::log() { // if we can't open logfile we log to stdout QTextStream out(stdout); QFile file; - if(!Global::parser.value("logfile").isEmpty()) { - file.setFileName(Global::parser.value("logfile")); + if(!Quassel::optionValue("logfile").isEmpty()) { + file.setFileName(Quassel::optionValue("logfile")); if (file.open(QIODevice::Append | QIODevice::Text)) { out.setDevice(&file); _buffer.remove(QChar('\n')); diff --git a/src/common/main.cpp b/src/common/main.cpp index b5e205b8..3013d890 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -18,248 +18,31 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include -#include -#include -#include -#include - -#include "global.h" -#include "logger.h" -#include "network.h" -#include "settings.h" -#include "cliparser.h" - -#if defined BUILD_CORE -#include -#include "core.h" -#include "message.h" +#include +#ifdef BUILD_CORE +# include "coreapplication.h" #elif defined BUILD_QTUI -#include "client.h" -#include "qtuiapplication.h" -#include "qtui.h" - +# include "qtuiapplication.h" #elif defined BUILD_MONO -#include "client.h" -#include "core.h" -#include "coresession.h" -#include "qtuiapplication.h" -#include "qtui.h" +# include "monoapplication.h" #else #error "Something is wrong - you need to #define a build mode!" #endif - -#include - -#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) -#include -#include -#include -#endif - -//! Signal handler for graceful shutdown. -void handle_signal(int sig) { - qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig))); - QCoreApplication::quit(); -} - -#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) -void handle_crash(int sig) { - Q_UNUSED(sig) - void* callstack[128]; - int i, frames = backtrace(callstack, 128); - - QFile dumpFile(QString("Quassel-Crash-%1").arg(QDateTime::currentDateTime().toString("yyyyMMdd-hhmm.log"))); - dumpFile.open(QIODevice::WriteOnly); - QTextStream dumpStream(&dumpFile); - - for (i = 0; i < frames; ++i) { - Dl_info info; - dladdr (callstack[i], &info); - // as a reference: - // typedef struct - // { - // __const char *dli_fname; /* File name of defining object. */ - // void *dli_fbase; /* Load address of that object. */ - // __const char *dli_sname; /* Name of nearest symbol. */ - // void *dli_saddr; /* Exact value of nearest symbol. */ - // } Dl_info; - -#if __LP64__ - int addrSize = 16; -#else - int addrSize = 8; -#endif - - QString funcName; - if(info.dli_sname) { - char *func = abi::__cxa_demangle(info.dli_sname, 0, 0, 0); - if(func) { - funcName = QString(func); - free(func); - } else { - funcName = QString(info.dli_sname); - } - } else { - funcName = QString("0x%1").arg((long)info.dli_saddr, addrSize, QLatin1Char('0')); - } - - // prettificating the filename - QString fileName("???"); - if(info.dli_fname) { - fileName = QString(info.dli_fname); - int slashPos = fileName.lastIndexOf('/'); - if(slashPos != -1) - fileName = fileName.mid(slashPos + 1); - if(fileName.count() < 20) - fileName += QString(20 - fileName.count(), ' '); - } - - QString debugLine = QString("#%1 %2 0x%3 %4").arg(i, 3, 10) - .arg(fileName) - .arg((long)(callstack[i]), addrSize, 16, QLatin1Char('0')) - .arg(funcName); - - dumpStream << debugLine << "\n"; - qDebug() << qPrintable(debugLine); - } - dumpFile.close(); - exit(27); -} -#endif // #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) - +#include "quassel.h" int main(int argc, char **argv) { - // We catch SIGTERM and SIGINT (caused by Ctrl+C) to graceful shutdown Quassel. - signal(SIGTERM, handle_signal); - signal(SIGINT, handle_signal); - -#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) - signal(SIGABRT, handle_crash); - signal(SIGBUS, handle_crash); - signal(SIGSEGV, handle_crash); -#endif // #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) - - Global::registerMetaTypes(); - Global::setupVersion(); - -#if defined BUILD_CORE - Global::runMode = Global::CoreOnly; - QCoreApplication app(argc, argv); -#elif defined BUILD_QTUI - Global::runMode = Global::ClientOnly; - QtUiApplication app(argc, argv); -#else - Global::runMode = Global::Monolithic; - QtUiApplication app(argc, argv); -#endif - Global::parser = CliParser(QCoreApplication::arguments()); - -#ifndef BUILD_QTUI -// put core-only arguments here - Global::parser.addOption("port",'p',"The port quasselcore will listen at",QString("4242")); - Global::parser.addSwitch("norestore", 'n', "Don't restore last core's state"); - Global::parser.addOption("logfile",'l',"Path to logfile"); - Global::parser.addOption("loglevel",'L',"Loglevel Debug|Info|Warning|Error","Info"); - Global::parser.addOption("datadir", 0, "Specify the directory holding datafiles like the Sqlite DB and the SSL Cert"); -#endif // BUILD_QTUI -#ifndef BUILD_CORE -// put client-only arguments here - Global::parser.addSwitch("debugbufferswitches",0,"Enables debugging for bufferswitches"); - Global::parser.addSwitch("debugmodel",0,"Enables debugging for models"); -#endif // BUILD_QTCORE -// put shared client&core arguments here - Global::parser.addSwitch("debug",'d',"Enable debug output"); - Global::parser.addSwitch("help",'h', "Display this help and exit"); - - if(!Global::parser.parse() || Global::parser.isSet("help")) { - Global::parser.usage(); - return 1; - } - - /* - This is an initial check if logfile is writable since the warning would spam stdout if done - in current Logger implementation. Can be dropped whenever the logfile is only opened once. - */ - if(Global::runMode != Global::ClientOnly) { - QFile logFile; - if(!Global::parser.value("logfile").isEmpty()) { - logFile.setFileName(Global::parser.value("logfile")); - if(!logFile.open(QIODevice::Append | QIODevice::Text)) - qWarning("Warning: Couldn't open logfile '%s' - will log to stdout instead",qPrintable(logFile.fileName())); - else logFile.close(); - } - } - - qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - - // Set up i18n support - QLocale locale = QLocale::system(); - - QTranslator qtTranslator(&app); - qtTranslator.setObjectName("QtTr"); - qtTranslator.load(QString(":i18n/qt_%1").arg(locale.name())); - app.installTranslator(&qtTranslator); - - QTranslator quasselTranslator(&app); - quasselTranslator.setObjectName("QuasselTr"); - quasselTranslator.load(QString(":i18n/quassel_%1").arg(locale.name())); - app.installTranslator(&quasselTranslator); - - Network::setDefaultCodecForServer("ISO-8859-1"); - Network::setDefaultCodecForEncoding("UTF-8"); - Network::setDefaultCodecForDecoding("ISO-8859-15"); - - QCoreApplication::setOrganizationDomain("quassel-irc.org"); - QCoreApplication::setApplicationName("Quassel IRC"); - QCoreApplication::setOrganizationName("Quassel Project"); - - -#ifndef BUILD_QTUI - Core::instance(); // create and init the core -#endif - - //Settings::init(); - -#ifndef BUILD_CORE - // session resume - QtUi *gui = new QtUi(); - Client::init(gui); - // init gui only after the event loop has started - QTimer::singleShot(0, gui, SLOT(init())); - //gui->init(); -#endif - -#ifndef BUILD_QTUI - if(!Global::parser.isSet("norestore")) { - Core::restoreState(); - } -#endif - -#ifndef BUILD_CORE - app.resumeSessionIfPossible(); -#endif - - int exitCode = app.exec(); - -#ifndef BUILD_QTUI - Core::saveState(); -#endif - -#ifndef BUILD_CORE - // the mainWin has to be deleted before the Core - // if not Quassel will crash on exit under certain conditions since the gui - // still wants to access clientdata - delete gui; - Client::destroy(); -#endif -#ifndef BUILD_QTUI - Core::destroy(); -#endif +# ifdef BUILD_CORE + CoreApplication app(argc, argv); +# elif BUILD_QTUI + QtUiApplication app(argc, argv); +# elif BUILD_MONO + MonolithicApplication app(argc, argv); +# endif - return exitCode; + if(!app.init()) return EXIT_FAILURE; + return app.exec(); } diff --git a/src/common/quassel.cpp b/src/common/quassel.cpp new file mode 100644 index 00000000..9761bfb0 --- /dev/null +++ b/src/common/quassel.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "quassel.h" + +#include + +#include +#include +#include +#include + +#include "message.h" +#include "identity.h" +#include "network.h" +#include "bufferinfo.h" +#include "types.h" +#include "syncableobject.h" + +#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) +# include +# include +# include +#endif + +Quassel::BuildInfo Quassel::_buildInfo; +CliParser *Quassel::_cliParser = 0; +Quassel::RunMode Quassel::_runMode; +bool Quassel::_initialized = false; +bool Quassel::DEBUG = false; + +Quassel::Quassel() { + // We catch SIGTERM and SIGINT (caused by Ctrl+C) to graceful shutdown Quassel. + signal(SIGTERM, handleSignal); + signal(SIGINT, handleSignal); + +#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) + signal(SIGABRT, handleSignal); + signal(SIGBUS, handleSignal); + signal(SIGSEGV, handleSignal); +#endif // #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) + + _cliParser = new CliParser(); + + // put shared client&core arguments here + cliParser()->addSwitch("debug",'d', tr("Enable debug output")); + cliParser()->addSwitch("help",'h', tr("Display this help and exit")); +} + +Quassel::~Quassel() { + delete _cliParser; +} + +bool Quassel::init() { + if(_initialized) return true; // allow multiple invocations because of MonolithicApplication + + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + + registerMetaTypes(); + setupBuildInfo(); + Global::setupVersion(); + setupTranslations(); + + QCoreApplication::setApplicationName(buildInfo().applicationName); + QCoreApplication::setOrganizationName(buildInfo().organizationName); + QCoreApplication::setOrganizationDomain(buildInfo().organizationDomain); + + Network::setDefaultCodecForServer("ISO-8859-1"); + Network::setDefaultCodecForEncoding("UTF-8"); + Network::setDefaultCodecForDecoding("ISO-8859-15"); + + if(!cliParser()->parse(QCoreApplication::arguments()) || isOptionSet("help")) { + cliParser()->usage(); + return false; + } + DEBUG = isOptionSet("debug"); + return true; +} + +//! Register our custom types with Qt's Meta Object System. +/** This makes them available for QVariant and in signals/slots, among other things. +* +*/ +void Quassel::registerMetaTypes() { + // Complex types + qRegisterMetaType("QVariant"); + qRegisterMetaType("Message"); + qRegisterMetaType("BufferInfo"); + qRegisterMetaType("NetworkInfo"); + qRegisterMetaType("Identity"); + qRegisterMetaType("Network::ConnectionState"); + + qRegisterMetaTypeStreamOperators("QVariant"); + qRegisterMetaTypeStreamOperators("Message"); + qRegisterMetaTypeStreamOperators("BufferInfo"); + qRegisterMetaTypeStreamOperators("NetworkInfo"); + qRegisterMetaTypeStreamOperators("Identity"); + qRegisterMetaTypeStreamOperators("Network::ConnectionState"); + + qRegisterMetaType("IdentityId"); + qRegisterMetaType("BufferId"); + qRegisterMetaType("NetworkId"); + qRegisterMetaType("UserId"); + qRegisterMetaType("AccountId"); + qRegisterMetaType("MsgId"); + + qRegisterMetaTypeStreamOperators("IdentityId"); + qRegisterMetaTypeStreamOperators("BufferId"); + qRegisterMetaTypeStreamOperators("NetworkId"); + qRegisterMetaTypeStreamOperators("UserId"); + qRegisterMetaTypeStreamOperators("AccountId"); + qRegisterMetaTypeStreamOperators("MsgId"); +} + +void Quassel::setupTranslations() { + // Set up i18n support + QLocale locale = QLocale::system(); + + QTranslator *qtTranslator = new QTranslator(qApp); + qtTranslator->setObjectName("QtTr"); + qtTranslator->load(QString(":i18n/qt_%1").arg(locale.name())); + qApp->installTranslator(qtTranslator); + + QTranslator *quasselTranslator = new QTranslator(qApp); + quasselTranslator->setObjectName("QuasselTr"); + quasselTranslator->load(QString(":i18n/quassel_%1").arg(locale.name())); + qApp->installTranslator(quasselTranslator); +} + +void Quassel::setupBuildInfo() { + _buildInfo.applicationName = "Quassel IRC"; + _buildInfo.coreApplicationName = "Quassel Core"; + _buildInfo.clientApplicationName = "Quassel Client"; + _buildInfo.organizationName = "Quassel Project"; + _buildInfo.organizationDomain = "quassel-irc.org"; +/* +# include "version.inc" +# include "version.gen" + + if(quasselGeneratedVersion.isEmpty()) { + if(quasselCommit.isEmpty()) + quasselVersion = QString("v%1 (unknown rev)").arg(quasselBaseVersion); + else + quasselVersion = QString("v%1 (dist-%2, %3)").arg(quasselBaseVersion).arg(quasselCommit.left(7)) + .arg(QDateTime::fromTime_t(quasselArchiveDate).toLocalTime().toString("yyyy-MM-dd")); + } else { + QStringList parts = quasselGeneratedVersion.split(':'); + quasselVersion = QString("v%1").arg(parts[0]); + if(parts.count() >= 2) quasselVersion.append(QString(" (%1)").arg(parts[1])); + } + quasselBuildDate = __DATE__; + quasselBuildTime = __TIME__; + */ +} + +//! Signal handler for graceful shutdown. +void Quassel::handleSignal(int sig) { + switch(sig) { + case SIGTERM: + case SIGINT: + qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig))); + QCoreApplication::quit(); + break; + + case SIGABRT: + case SIGBUS: + case SIGSEGV: + handleCrash(); + break; + default: + break; + } +} + +void Quassel::handleCrash() { +#if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) + void* callstack[128]; + int i, frames = backtrace(callstack, 128); + + QFile dumpFile(QString("Quassel-Crash-%1").arg(QDateTime::currentDateTime().toString("yyyyMMdd-hhmm.log"))); + dumpFile.open(QIODevice::WriteOnly); + QTextStream dumpStream(&dumpFile); + + for (i = 0; i < frames; ++i) { + Dl_info info; + dladdr (callstack[i], &info); + // as a reference: + // typedef struct + // { + // __const char *dli_fname; /* File name of defining object. */ + // void *dli_fbase; /* Load address of that object. */ + // __const char *dli_sname; /* Name of nearest symbol. */ + // void *dli_saddr; /* Exact value of nearest symbol. */ + // } Dl_info; + + #if __LP64__ + int addrSize = 16; + #else + int addrSize = 8; + #endif + + QString funcName; + if(info.dli_sname) { + char *func = abi::__cxa_demangle(info.dli_sname, 0, 0, 0); + if(func) { + funcName = QString(func); + free(func); + } else { + funcName = QString(info.dli_sname); + } + } else { + funcName = QString("0x%1").arg((long)info.dli_saddr, addrSize, QLatin1Char('0')); + } + + // prettificating the filename + QString fileName("???"); + if(info.dli_fname) { + fileName = QString(info.dli_fname); + int slashPos = fileName.lastIndexOf('/'); + if(slashPos != -1) + fileName = fileName.mid(slashPos + 1); + if(fileName.count() < 20) + fileName += QString(20 - fileName.count(), ' '); + } + + QString debugLine = QString("#%1 %2 0x%3 %4").arg(i, 3, 10) + .arg(fileName) + .arg((long)(callstack[i]), addrSize, 16, QLatin1Char('0')) + .arg(funcName); + + dumpStream << debugLine << "\n"; + qDebug() << qPrintable(debugLine); + } + dumpFile.close(); + exit(27); +#endif // #if defined(HAVE_EXECINFO) and not defined(Q_OS_MAC) +} + +// FIXME temporary + +void Global::setupVersion() { + + # include "version.inc" + # include "version.gen" + + if(quasselGeneratedVersion.isEmpty()) { + if(quasselCommit.isEmpty()) + quasselVersion = QString("v%1 (unknown rev)").arg(quasselBaseVersion); + else + quasselVersion = QString("v%1 (dist-%2, %3)").arg(quasselBaseVersion).arg(quasselCommit.left(7)) + .arg(QDateTime::fromTime_t(quasselArchiveDate).toLocalTime().toString("yyyy-MM-dd")); + } else { + QStringList parts = quasselGeneratedVersion.split(':'); + quasselVersion = QString("v%1").arg(parts[0]); + if(parts.count() >= 2) quasselVersion.append(QString(" (%1)").arg(parts[1])); + } + quasselBuildDate = __DATE__; + quasselBuildTime = __TIME__; +} + +QString Global::quasselVersion; +QString Global::quasselBaseVersion; +QString Global::quasselGeneratedVersion; +QString Global::quasselBuildDate; +QString Global::quasselBuildTime; +QString Global::quasselCommit; +uint Global::quasselArchiveDate; +uint Global::protocolVersion; +uint Global::clientNeedsProtocol; +uint Global::coreNeedsProtocol; diff --git a/src/common/quassel.h b/src/common/quassel.h new file mode 100644 index 00000000..71c19b8e --- /dev/null +++ b/src/common/quassel.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef QUASSEL_H_ +#define QUASSEL_H_ + +#include +#include + +#include "cliparser.h" + +class Quassel { + Q_DECLARE_TR_FUNCTIONS(Quassel) + + public: + enum RunMode { + Monolithic, + ClientOnly, + CoreOnly + }; + + struct BuildInfo { + QString version; + QString baseVersion; + QString generatedVersion; + QString buildDate; + QString buildTime; + QString commitHash; + uint archiveDate; + uint protocolVersion; + uint clientNeedsProtocol; + uint coreNeedsProtocol; + + QString applicationName; + QString coreApplicationName; + QString clientApplicationName; + QString organizationName; + QString organizationDomain; + }; + + ~Quassel(); + + static inline const BuildInfo & buildInfo(); + static inline RunMode runMode(); + + static inline CliParser *cliParser(); + static inline QString optionValue(const QString &option); + static inline bool isOptionSet(const QString &option); + + static bool DEBUG; + + protected: + Quassel(); + virtual bool init(); + + inline void setRunMode(RunMode mode); + + + private: + void setupBuildInfo(); + void setupTranslations(); + void registerMetaTypes(); + + static void handleSignal(int signal); + static void handleCrash(); + + static BuildInfo _buildInfo; + static CliParser *_cliParser; + static RunMode _runMode; + static bool _initialized; +}; + +// FIXME temporary +namespace Global { + extern QString quasselVersion; + extern QString quasselBaseVersion; + extern QString quasselBuildDate; + extern QString quasselBuildTime; + extern QString quasselCommit; + extern uint quasselArchiveDate; + extern uint protocolVersion; + + extern uint clientNeedsProtocol; //< Minimum protocol version the client needs + extern uint coreNeedsProtocol; //< Minimum protocol version the core needs + + extern QString quasselGeneratedVersion; //< This is possibly set in version.gen + + void setupVersion(); +}; + +const Quassel::BuildInfo & Quassel::buildInfo() { return _buildInfo; } +Quassel::RunMode Quassel::runMode() { return _runMode; } +void Quassel::setRunMode(Quassel::RunMode mode) { _runMode = mode; } + +CliParser *Quassel::cliParser() { return _cliParser; } +QString Quassel::optionValue(const QString &key) { return cliParser()->value(key); } +bool Quassel::isOptionSet(const QString &key) { return cliParser()->isSet(key); } + +#endif diff --git a/src/common/util.cpp b/src/common/util.cpp index 41139dd5..1b75f29b 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -19,13 +19,14 @@ ***************************************************************************/ #include "util.h" -#include "global.h" #include #include #include #include +#include "quassel.h" + class QMetaMethod; QString nickFromMask(QString mask) { @@ -124,7 +125,7 @@ uint editingDistance(const QString &s1, const QString &s2) { min = deleteChar; else min = insertChar; - + if(s1[i-1] == s2[j-1]) { uint inheritChar = matrix[i-1][j-1]; if(inheritChar < min) @@ -144,9 +145,10 @@ QByteArray methodName(const QMetaMethod &method) { QDir quasselDir() { QString quasselDir; - if(Global::parser.isSet("datadir")) { - quasselDir = Global::parser.value("datadir"); + if(Quassel::isOptionSet("datadir")) { + quasselDir = Quassel::optionValue("datadir"); } else { + // FIXME use QDesktopServices #ifdef Q_OS_WIN32 quasselDir = qgetenv("APPDATA") + "/quassel/"; #elif defined Q_WS_MAC @@ -179,7 +181,7 @@ void loadTranslation(const QLocale &locale) { if(locale.language() == QLocale::C) return; - + qtTranslator->load(QString(":i18n/qt_%1").arg(locale.name())); quasselTranslator->load(QString(":i18n/quassel_%1").arg(locale.name())); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8198773b..c69ec2a4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES basichandler.cpp core.cpp corealiasmanager.cpp + coreapplication.cpp corebacklogmanager.cpp corebufferviewconfig.cpp corebufferviewmanager.cpp @@ -33,6 +34,7 @@ set(MOC_HDRS basichandler.h core.h corealiasmanager.h + coreapplication.h corebacklogmanager.h corebufferviewconfig.h corebufferviewmanager.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 01b341c8..87193bca 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -26,6 +26,7 @@ #include "core.h" #include "coresession.h" #include "coresettings.h" +#include "quassel.h" #include "signalproxy.h" #include "sqlitestorage.h" #include "network.h" @@ -87,7 +88,7 @@ void Core::init() { connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); - if(!startListening(cs.port())) exit(1); // TODO make this less brutal + if(!startListening()) exit(1); // TODO make this less brutal } Core::~Core() { @@ -341,8 +342,9 @@ QHash Core::bufferLastSeenMsgIds(UserId user) { /*** Network Management ***/ -bool Core::startListening(uint port) { +bool Core::startListening() { bool success = false; + uint port = Quassel::optionValue("port").toUInt(); if(_server.listen(QHostAddress::Any, port)) { quInfo() << "Listening for GUI clients on IPv6 port" << _server.serverPort() << "using protocol version" << Global::protocolVersion; @@ -356,7 +358,7 @@ bool Core::startListening(uint port) { if(!success) { quError() << qPrintable(QString("Could not open GUI client port %1: %2").arg(port).arg(_server.errorString())); } - + return success; } @@ -374,7 +376,7 @@ void Core::incomingConnection() { connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); - + QVariantMap clientInfo; blocksizes.insert(socket, (quint32)0); quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString()); @@ -491,7 +493,7 @@ void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) { quDebug() << "Using compression for Client:" << qPrintable(socket->peerAddress().toString()); } #endif - + } else { // for the rest, we need an initialized connection if(!clientInfo.contains(socket)) { @@ -546,7 +548,7 @@ void Core::clientDisconnected() { // DO NOT CALL ANY METHODS ON socket!! socket = static_cast(sender()); - + QHash::iterator blockSizeIter = blocksizes.begin(); while(blockSizeIter != blocksizes.end()) { if(blockSizeIter.key() == socket) { diff --git a/src/core/core.h b/src/core/core.h index eddaf7f3..beb7b891 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -37,7 +37,6 @@ #include "bufferinfo.h" #include "message.h" -#include "global.h" #include "sessionthread.h" #include "types.h" @@ -66,7 +65,7 @@ class Core : public QObject { * \param data The Value */ static void setUserSetting(UserId userId, const QString &settingName, const QVariant &data); - + //! Retrieve a persistent user setting /** * \param userId The users Id @@ -76,7 +75,7 @@ class Core : public QObject { */ static QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &data = QVariant()); - + //! Create a Network in the Storage and store it's Id in the given NetworkInfo /** \note This method is thredsafe. * @@ -85,7 +84,7 @@ class Core : public QObject { * \return true if successfull. */ static bool createNetwork(UserId user, NetworkInfo &info); - + //! Apply the changes to NetworkInfo info to the storage engine /** \note This method is thredsafe. * @@ -103,7 +102,7 @@ class Core : public QObject { * \return true if successfull. */ static bool removeNetwork(UserId user, const NetworkId &networkId); - + //! Returns a list of all NetworkInfos for the given UserId user /** \note This method is thredsafe. * @@ -186,7 +185,7 @@ class Core : public QObject { */ static BufferInfo getBufferInfo(UserId user, const BufferId &bufferId); - + //! Store a Message in the backlog. /** \note This method is threadsafe. * @@ -289,13 +288,13 @@ class Core : public QObject { /** \note This method is threadsafe. */ void syncStorage(); - + signals: //! Sent when a BufferInfo is updated in storage. void bufferInfoUpdated(UserId user, const BufferInfo &info); private slots: - bool startListening(uint port = Global::parser.value("port").toUInt()); + bool startListening(); void stopListening(); void incomingConnection(); void clientHasData(); @@ -327,11 +326,11 @@ class Core : public QObject { Storage *storage; QTimer _storageSyncTimer; -#ifdef HAVE_SSL +#ifdef HAVE_SSL SslServer _server, _v6server; #else QTcpServer _server, _v6server; -#endif +#endif QHash blocksizes; QHash clientInfo; diff --git a/src/core/coreapplication.cpp b/src/core/coreapplication.cpp new file mode 100644 index 00000000..d92e46d9 --- /dev/null +++ b/src/core/coreapplication.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "coreapplication.h" + +#include "core.h" + +CoreApplicationInternal::CoreApplicationInternal() { + // put core-only arguments here + CliParser *parser = Quassel::cliParser(); + parser->addOption("port",'p', tr("The port quasselcore will listen at"), QString("4242")); + parser->addSwitch("norestore", 'n', tr("Don't restore last core's state")); + parser->addOption("logfile", 'l', tr("Path to logfile")); + parser->addOption("loglevel", 'L', tr("Loglevel Debug|Info|Warning|Error"), "Info"); + parser->addOption("datadir", 0, tr("Specify the directory holding datafiles like the Sqlite DB and the SSL Cert")); +} + +CoreApplicationInternal::~CoreApplicationInternal() { + Core::saveState(); + Core::destroy(); +} + +bool CoreApplicationInternal::init() { + /* FIXME + This is an initial check if logfile is writable since the warning would spam stdout if done + in current Logger implementation. Can be dropped whenever the logfile is only opened once. + */ + QFile logFile; + if(!Quassel::optionValue("logfile").isEmpty()) { + logFile.setFileName(Quassel::optionValue("logfile")); + if(!logFile.open(QIODevice::Append | QIODevice::Text)) + qWarning("Warning: Couldn't open logfile '%s' - will log to stdout instead",qPrintable(logFile.fileName())); + else logFile.close(); + } + + Core::instance(); // create and init the core + + if(!Quassel::isOptionSet("norestore")) { + Core::restoreState(); + } + return true; +} + +/*****************************************************************************/ + +CoreApplication::CoreApplication(int &argc, char **argv) : QCoreApplication(argc, argv), Quassel() { + setRunMode(Quassel::CoreOnly); + _internal = new CoreApplicationInternal(); +} + +CoreApplication::~CoreApplication() { + delete _internal; +} + +bool CoreApplication::init() { + if(Quassel::init()) + return _internal->init(); + return false; +} diff --git a/src/common/global.h b/src/core/coreapplication.h similarity index 52% rename from src/common/global.h rename to src/core/coreapplication.h index 26f9f6b9..14eec295 100644 --- a/src/common/global.h +++ b/src/core/coreapplication.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-08 by the Quassel IRC Team * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -18,48 +18,36 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -// This file needs probably to go away at some point. Not much left anymore. +#ifndef COREAPPLICATION_H_ +#define COREAPPLICATION_H_ -#ifndef _GLOBAL_H_ -#define _GLOBAL_H_ +#include -#include "cliparser.h" +#include "quassel.h" -#include +/// Encapsulates CoreApplication's logic. +/** This allows it to be reused within MonolithicApplication as well. + */ +class CoreApplicationInternal { + Q_DECLARE_TR_FUNCTIONS(CoreApplicationInternal) -// Enable some shortcuts and stuff -//#define DEVELMODE + public: + CoreApplicationInternal(); + ~CoreApplicationInternal(); -/* Some global stuff */ - -namespace Global { - - extern QString quasselVersion; - extern QString quasselBaseVersion; - extern QString quasselBuildDate; - extern QString quasselBuildTime; - extern QString quasselCommit; - extern uint quasselArchiveDate; - extern uint protocolVersion; - - extern uint clientNeedsProtocol; //< Minimum protocol version the client needs - extern uint coreNeedsProtocol; //< Minimum protocol version the core needs - - extern QString quasselGeneratedVersion; //< This is possibly set in version.gen + bool init(); +}; - // We need different config (QSettings) files for client and gui, since the core cannot work with GUI types - // Set these here. They're used in ClientSettings and CoreSettings. - const QString coreApplicationName = "Quassel Core"; - const QString clientApplicationName = "Quassel Client"; +class CoreApplication : public QCoreApplication, public Quassel { + Q_OBJECT + public: + CoreApplication(int &argc, char **argv); + ~CoreApplication(); - enum RunMode { Monolithic, ClientOnly, CoreOnly }; - extern RunMode runMode; - extern unsigned int defaultPort; + bool init(); - extern bool DEBUG; - extern CliParser parser; - void registerMetaTypes(); - void setupVersion(); + private: + CoreApplicationInternal *_internal; }; #endif diff --git a/src/core/corecoreinfo.cpp b/src/core/corecoreinfo.cpp index 495de45e..d1b3e15a 100644 --- a/src/core/corecoreinfo.cpp +++ b/src/core/corecoreinfo.cpp @@ -22,7 +22,7 @@ #include "core.h" #include "coresession.h" -#include "global.h" +#include "quassel.h" #include "signalproxy.h" CoreCoreInfo::CoreCoreInfo(CoreSession *parent) diff --git a/src/core/coresettings.cpp b/src/core/coresettings.cpp index b7aae856..8d0a5cea 100644 --- a/src/core/coresettings.cpp +++ b/src/core/coresettings.cpp @@ -20,9 +20,9 @@ #include "coresettings.h" -#include +#include "quassel.h" -CoreSettings::CoreSettings(const QString group) : Settings(group, Global::coreApplicationName) { +CoreSettings::CoreSettings(const QString group) : Settings(group, Quassel::buildInfo().coreApplicationName) { } CoreSettings::~CoreSettings() { @@ -41,14 +41,6 @@ QVariant CoreSettings::oldDbSettings() { return localValue("DatabaseSettings"); } -void CoreSettings::setPort(const uint &port) { - setLocalValue("Port", port); -} - -uint CoreSettings::port(const uint &def) { - return localValue("Port", def).toUInt(); -} - void CoreSettings::setCoreState(const QVariant &data) { setLocalValue("CoreState", data); } diff --git a/src/core/coresettings.h b/src/core/coresettings.h index 775d88e9..17082c4e 100644 --- a/src/core/coresettings.h +++ b/src/core/coresettings.h @@ -21,7 +21,6 @@ #ifndef _CORESETTINGS_H_ #define _CORESETTINGS_H_ -#include "global.h" #include "settings.h" class CoreSettings : public Settings { @@ -35,9 +34,6 @@ class CoreSettings : public Settings { QVariant oldDbSettings(); // FIXME remove - void setPort(const uint &port); - uint port(const uint &def = Global::parser.value("port").toUInt()); - void setCoreState(const QVariant &data); QVariant coreState(const QVariant &def = QVariant()); diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp index a864fe64..a944c022 100644 --- a/src/core/ctcphandler.cpp +++ b/src/core/ctcphandler.cpp @@ -19,10 +19,10 @@ ***************************************************************************/ #include "ctcphandler.h" -#include "global.h" -#include "util.h" #include "message.h" #include "network.h" +#include "quassel.h" +#include "util.h" CtcpHandler::CtcpHandler(NetworkConnection *parent) : BasicHandler(parent), @@ -44,7 +44,7 @@ QByteArray CtcpHandler::dequote(const QByteArray &message) { QByteArray dequotedMessage; QByteArray messagepart; QHash::iterator ctcpquote; - + // copy dequote Message for(int i = 0; i < message.size(); i++) { messagepart = message.mid(i,1); @@ -86,14 +86,14 @@ QByteArray CtcpHandler::xdelimDequote(const QByteArray &message) { void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const QString &target, const QByteArray &message) { QByteArray ctcp; - + //lowlevel message dequote QByteArray dequotedMessage = dequote(message); CtcpType ctcptype = messageType == Message::Notice ? CtcpReply : CtcpQuery; - + Message::Flags flags = (messageType == Message::Notice && !network()->isChannelName(target)) ? Message::Redirected : Message::None; @@ -129,7 +129,7 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam)); } - + if(!dequotedMessage.isEmpty()) displayMsg(messageType, target, userDecode(target, dequotedMessage), prefix, flags); } diff --git a/src/qtui/CMakeLists.txt b/src/qtui/CMakeLists.txt index b62fc3a0..253268ee 100644 --- a/src/qtui/CMakeLists.txt +++ b/src/qtui/CMakeLists.txt @@ -30,8 +30,8 @@ set(SOURCES mainwin.cpp msgprocessorstatuswidget.cpp nicklistwidget.cpp - qtuiapplication.cpp qtui.cpp + qtuiapplication.cpp qtuimessageprocessor.cpp qtuisettings.cpp qtuistyle.cpp diff --git a/src/qtui/aboutdlg.cpp b/src/qtui/aboutdlg.cpp index 439d50db..3085f5bb 100644 --- a/src/qtui/aboutdlg.cpp +++ b/src/qtui/aboutdlg.cpp @@ -19,7 +19,7 @@ ***************************************************************************/ #include "aboutdlg.h" -#include "global.h" +#include "quassel.h" AboutDlg::AboutDlg(QWidget *parent) : QDialog(parent) { ui.setupUi(this); diff --git a/src/qtui/bufferwidget.cpp b/src/qtui/bufferwidget.cpp index e16735e5..bdaaff2d 100644 --- a/src/qtui/bufferwidget.cpp +++ b/src/qtui/bufferwidget.cpp @@ -25,8 +25,6 @@ #include "settings.h" #include "client.h" -#include "global.h" - #include BufferWidget::BufferWidget(QWidget *parent) @@ -42,7 +40,7 @@ BufferWidget::BufferWidget(QWidget *parent) _chatViewSearchController->setSearchSenders(ui.searchBar->searchSendersBox()->isChecked()); _chatViewSearchController->setSearchMsgs(ui.searchBar->searchMsgsBox()->isChecked()); _chatViewSearchController->setSearchOnlyRegularMsgs(ui.searchBar->searchOnlyRegularMsgsBox()->isChecked()); - + connect(ui.searchBar->searchEditLine(), SIGNAL(textChanged(const QString &)), _chatViewSearchController, SLOT(setSearchString(const QString &))); connect(ui.searchBar->caseSensitiveBox(), SIGNAL(toggled(bool)), diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index caecd84a..46756e5a 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -66,7 +66,6 @@ #include "settingspages/networkssettingspage.h" #include "settingspages/notificationssettingspage.h" -#include "global.h" #include "qtuistyle.h" MainWin::MainWin(QWidget *parent) diff --git a/src/qtui/monoapplication.cpp b/src/qtui/monoapplication.cpp new file mode 100644 index 00000000..aebe619a --- /dev/null +++ b/src/qtui/monoapplication.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "monoapplication.h" +#include "coreapplication.h" +#include "client.h" +#include "qtui.h" + +MonolithicApplication::MonolithicApplication(int &argc, char **argv) : QtUiApplication(argc, argv) { + setRunMode(Monolithic); + _internal = new CoreApplicationInternal(); + +} + +bool MonolithicApplication::init() { + if(Quassel::init() && _internal->init()) { + return QtUiApplication::init(); + } + return false; +} + +MonolithicApplication::~MonolithicApplication() { + // Client needs to be destroyed first + Client::destroy(); + + delete _internal; +} diff --git a/src/qtui/monoapplication.h b/src/qtui/monoapplication.h new file mode 100644 index 00000000..59d3747d --- /dev/null +++ b/src/qtui/monoapplication.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef MONOAPPLICATION_H_ +#define MONOAPPLICATION_H_ + +#include "qtuiapplication.h" + +class CoreApplicationInternal; + +class MonolithicApplication : public QtUiApplication { + + public: + MonolithicApplication(int &, char **); + ~MonolithicApplication(); + + bool init(); + + private: + CoreApplicationInternal *_internal; +}; + +#endif diff --git a/src/qtui/qtuiapplication.cpp b/src/qtui/qtuiapplication.cpp index 5060c2a8..7a6f0977 100644 --- a/src/qtui/qtuiapplication.cpp +++ b/src/qtui/qtuiapplication.cpp @@ -18,14 +18,40 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include "qtuiapplication.h" + #include -#include "qtuiapplication.h" -#include "sessionsettings.h" #include "client.h" +#include "cliparser.h" +#include "qtui.h" +#include "sessionsettings.h" -QtUiApplication::QtUiApplication(int &argc, char **argv) : QApplication(argc, argv) { +QtUiApplication::QtUiApplication(int &argc, char **argv) : QApplication(argc, argv), Quassel() { + setRunMode(Quassel::ClientOnly); + // put client-only arguments here + CliParser *parser = Quassel::cliParser(); + parser->addSwitch("debugbufferswitches",0,"Enables debugging for bufferswitches"); + parser->addSwitch("debugmodel",0,"Enables debugging for models"); +} + +bool QtUiApplication::init() { + if(Quassel::init()) { + // session resume + QtUi *gui = new QtUi(); + Client::init(gui); + // init gui only after the event loop has started + // QTimer::singleShot(0, gui, SLOT(init())); + gui->init(); + resumeSessionIfPossible(); + return true; + } + return false; +} + +QtUiApplication::~QtUiApplication() { + Client::destroy(); } void QtUiApplication::saveState(QSessionManager & manager) { @@ -37,9 +63,6 @@ void QtUiApplication::saveState(QSessionManager & manager) { emit saveStateToSessionSettings(s); } -QtUiApplication::~ QtUiApplication() { -} - void QtUiApplication::resumeSessionIfPossible() { // load all sessions if(isSessionRestored()) { @@ -56,4 +79,3 @@ void QtUiApplication::resumeSessionIfPossible() { s.cleanup(); } } - diff --git a/src/qtui/qtuiapplication.h b/src/qtui/qtuiapplication.h index 7b004d99..f46f3a78 100644 --- a/src/qtui/qtuiapplication.h +++ b/src/qtui/qtuiapplication.h @@ -24,22 +24,28 @@ #include #include +#include "quassel.h" #include "sessionsettings.h" -#include "qtui.h" -class QtUiApplication : public QApplication { +class QtUi; + +class QtUiApplication : public QApplication, public Quassel { Q_OBJECT + public: - QtUiApplication(int &, char**); + QtUiApplication(int &, char **); ~QtUiApplication(); + virtual bool init(); + void resumeSessionIfPossible(); virtual void saveState(QSessionManager & manager); + signals: void saveStateToSession(const QString &sessionId); - void saveStateToSessionSettings(SessionSettings &s); + void saveStateToSessionSettings(SessionSettings &s); // FIXME refs in signals won't probably work void resumeFromSession(const QString sessionId); void resumeFromSessionSettings(SessionSettings &s); - + }; #endif diff --git a/src/qtui/settingspages/networkssettingspage.cpp b/src/qtui/settingspages/networkssettingspage.cpp index 1ed468f9..0857a4e3 100644 --- a/src/qtui/settingspages/networkssettingspage.cpp +++ b/src/qtui/settingspages/networkssettingspage.cpp @@ -25,7 +25,6 @@ #include "networkssettingspage.h" #include "client.h" -#include "global.h" #include "identity.h" #include "network.h" diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index 936c0636..d93a6172 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -30,8 +30,6 @@ #include "uisettings.h" -#include "global.h" - #include #include #include @@ -115,7 +113,7 @@ void BufferView::init() { void BufferView::setModel(QAbstractItemModel *model) { delete selectionModel(); - + QTreeView::setModel(model); init(); // remove old Actions @@ -139,7 +137,7 @@ void BufferView::setModel(QAbstractItemModel *model) { connect(showSection, SIGNAL(toggled(bool)), this, SLOT(toggleHeader(bool))); header()->addAction(showSection); } - + } void BufferView::setFilteredModel(QAbstractItemModel *model_, BufferViewConfig *config) { @@ -169,7 +167,7 @@ void BufferView::setSelectionModel(QItemSelectionModel *selectionModel) { if(QTreeView::selectionModel()) disconnect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)), model(), SIGNAL(checkPreviousCurrentForRemoval(QModelIndex, QModelIndex))); - + QTreeView::setSelectionModel(selectionModel); BufferViewFilter *filter = qobject_cast(model()); if(filter) { @@ -181,7 +179,7 @@ void BufferView::setSelectionModel(QItemSelectionModel *selectionModel) { void BufferView::setConfig(BufferViewConfig *config) { if(_config == config) return; - + if(_config) { disconnect(_config, 0, this, 0); } @@ -216,7 +214,7 @@ void BufferView::joinChannel(const QModelIndex &index) { return; BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); - + Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName())); } @@ -243,7 +241,7 @@ void BufferView::removeSelectedBuffers(bool permanently) { continue; removedRows << bufferId; - + if(permanently) config()->requestRemoveBufferPermanently(bufferId); else @@ -257,7 +255,7 @@ void BufferView::rowsInserted(const QModelIndex & parent, int start, int end) { // ensure that newly inserted network nodes are expanded per default if(parent.data(NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType) return; - + if(model()->rowCount(parent) == 1 && parent.data(NetworkModel::ItemActiveRole) == true) { // without updating the parent the expand will have no effect... Qt Bug? update(parent); @@ -317,7 +315,7 @@ void BufferView::storeExpandedState(NetworkId networkId, bool expanded) { void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { QTreeView::dataChanged(topLeft, bottomRight); - + // determine how many items have been changed and if any of them is a networkitem // which just swichted from active to inactive or vice versa if(topLeft.data(NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType) @@ -421,10 +419,10 @@ void BufferView::contextMenuEvent(QContextMenuEvent *event) { connectionStateIcon = QIcon(":/22x22/actions/gear"); } } - + QMenu contextMenu(this); NetworkModel::itemType itemType = static_cast(index.data(NetworkModel::ItemTypeRole).toInt()); - + switch(itemType) { case NetworkModel::NetworkItemType: showChannelList.setData(index.data(NetworkModel::NetworkIdRole)); @@ -465,11 +463,11 @@ void BufferView::contextMenuEvent(QContextMenuEvent *event) { default: return; } - + if(contextMenu.actions().isEmpty()) return; QAction *result = contextMenu.exec(QCursor::pos()); - + // Handle Result if(network && result == &_connectNetAction) { network->requestConnect(); @@ -504,7 +502,7 @@ void BufferView::contextMenuEvent(QContextMenuEvent *event) { Client::instance()->userInput(bufferInfo, QString("/PART")); return; } - + if(result == &_hideBufferTemporarilyAction) { removeSelectedBuffers(); return; @@ -553,13 +551,13 @@ void BufferView::wheelEvent(QWheelEvent* event) { } selectionModel()->setCurrentIndex( resultingIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); selectionModel()->select( resultingIndex, QItemSelectionModel::ClearAndSelect ); - + } QSize BufferView::sizeHint() const { return QTreeView::sizeHint(); - + if(!model()) return QTreeView::sizeHint(); diff --git a/src/uisupport/uistyle.cpp b/src/uisupport/uistyle.cpp index 3326bfda..08190ed1 100644 --- a/src/uisupport/uistyle.cpp +++ b/src/uisupport/uistyle.cpp @@ -19,13 +19,13 @@ ***************************************************************************/ #include +#include "quassel.h" #include "uistyle.h" #include "uisettings.h" #include "util.h" // FIXME remove with migration code #include -#include "global.h" UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) { // register FormatList if that hasn't happened yet @@ -39,9 +39,9 @@ UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) { // FIXME remove migration at some point // We remove old settings if we find them, since they conflict #ifdef Q_WS_MAC - QSettings mys(QCoreApplication::organizationDomain(), Global::clientApplicationName); + QSettings mys(QCoreApplication::organizationDomain(), Quassel::buildInfo().clientApplicationName); #else - QSettings mys(QCoreApplication::organizationName(), Global::clientApplicationName); + QSettings mys(QCoreApplication::organizationName(), Quassel::buildInfo().clientApplicationName); #endif mys.beginGroup("QtUi"); if(mys.childGroups().contains("Colors")) {