From 04e21ce26ebabdde9586ca9d2a3168431e448df5 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Fri, 20 Oct 2006 23:32:26 +0000 Subject: [PATCH] Big, big, major commit this time: * Separation of GUI and Core finished, including synchronized global data in Global *global * Speaking of which, the Quassel class has been renamed to Global, way cooler! * TCP/IP between GUI and Core works, though the server port is still hardcoded to 4242 * The build system now handles any combination of "mono", "core" and "gui" for cmake's -DBUILD * A lot of fixes and stuff * More to come, but the basic framework should be stabilizing now. --- CMakeLists.txt | 46 +++++----- Doxyfile | 49 ++++++----- Quassel.kdevelop.filelist | 5 ++ core/core.cpp | 42 ++++------ core/core.h | 3 + core/coreproxy.cpp | 104 ++++++++++++++++++++++- core/coreproxy.h | 33 ++++++-- gui/CMakeLists.txt | 9 +- gui/coreconnectdlg.cpp | 100 ++++++++++++++++++++++ gui/coreconnectdlg.h | 50 +++++++++++ gui/coreconnectdlg.ui | 172 ++++++++++++++++++++++++++++++++++++++ gui/guiproxy.cpp | 23 ++--- gui/guiproxy.h | 35 ++++++-- gui/mainwin.cpp | 47 ++++++++--- gui/mainwin.h | 7 +- gui/serverlist.cpp | 33 ++++---- gui/serverlist.h | 2 + images/icons.qrc | 1 + images/qirc-icon.png | Bin 0 -> 9129 bytes main/CMakeLists.txt | 4 +- main/main_core.cpp | 26 +++--- main/main_gui.cpp | 56 +++++++++++-- main/main_mono.cpp | 38 ++++----- main/proxy_common.h | 4 +- main/quassel.cpp | 45 ++++++---- main/quassel.h | 39 +++++---- main/util.cpp | 46 ++++++++++ main/util.h | 44 ++++++++++ network/server.h | 4 +- 29 files changed, 864 insertions(+), 203 deletions(-) create mode 100644 gui/coreconnectdlg.cpp create mode 100644 gui/coreconnectdlg.h create mode 100644 gui/coreconnectdlg.ui create mode 100644 images/qirc-icon.png create mode 100644 main/util.cpp create mode 100644 main/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 77c3b413..58a6b95b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,32 +1,33 @@ PROJECT(Quassel) -# CMAKE_MINIMUM_REQUIRED(VERSION 2.4.2) +# 2.4.2 had a bug with out-of-source builds and UIC dependencies. +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.3 FATAL_ERROR) # Select if Quassel should be built in client, server or monolithic mode -SET(BUILD "mono" CACHE STRING "Defines which Quassel parts are to be built. Can contain 'core', 'gui' and/or 'monolithic' (which is the default).") +SET(BUILD "mono" CACHE STRING "Defines which Quassel parts are to be built. Can contain 'core', 'gui' and/or 'monolithic' (which is the default), or 'all' to build everything.") SET(BUILD_CORE ) SET(BUILD_GUI ) SET(BUILD_MONO ) -IF(BUILD MATCHES "core") +IF(BUILD MATCHES "core" OR BUILD MATCHES "all") SET(BUILD_CORE true) - MESSAGE(STATUS "Building Quassel core.") -ENDIF(BUILD MATCHES "core") -IF(BUILD MATCHES "gui") + MESSAGE("Building Quassel core.") +ENDIF(BUILD MATCHES "core" OR BUILD MATCHES "all") +IF(BUILD MATCHES "gui" OR BUILD MATCHES "all") SET(BUILD_GUI true) - MESSAGE(STATUS "Building Quassel GUI.") -ENDIF(BUILD MATCHES "gui") -IF(BUILD MATCHES "mono") + MESSAGE("Building Quassel GUI.") +ENDIF(BUILD MATCHES "gui" OR BUILD MATCHES "all") +IF(BUILD MATCHES "mono" OR BUILD MATCHES "all") SET(BUILD_MONO true) - MESSAGE(STATUS "Building monolithic Quassel.") -ENDIF(BUILD MATCHES "mono") + MESSAGE("Building monolithic Quassel.") +ENDIF(BUILD MATCHES "mono" OR BUILD MATCHES "all") IF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI) - MESSAGE(FATAL_ERROR "You have not selected which parts of Quassel I should build. Aborting.\nRun 'cmake -DBUILD=', where contains one or more of 'core', 'gui' or 'monolithic'.") + MESSAGE(FATAL_ERROR "\nYou have not selected which parts of Quassel I should build. Aborting.\nRun 'cmake -DBUILD=', where contains one or more of 'core', 'gui' or 'monolithic', or 'all' to build everything.\n") ENDIF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI) # Define files SET(quassel_mono_SRCS main/main_mono.cpp) SET(quassel_core_SRCS main/main_core.cpp) -#SET(quassel_gui_SRCS main/main_gui.cpp ${common_SRCS}) +SET(quassel_gui_SRCS main/main_gui.cpp ${common_SRCS}) SET(quassel_RCCS images/icons.qrc) SET(quassel_DIRS main gui core network) @@ -46,13 +47,23 @@ SET(QT_USE_QTNETWORK true) SET(QT_DONT_USE_QTGUI true) # This is added later if GUI is requested INCLUDE(${QT_USE_FILE}) +# Define subdirs. CMake complains if a directory is added twice, so make sure this +# does not happen in any combination of the requested targets. + ADD_SUBDIRECTORY(main) +IF(BUILD_CORE) + ADD_SUBDIRECTORY(core) + ADD_SUBDIRECTORY(network) +ENDIF(BUILD_CORE) +IF(BUILD_MONO AND NOT BUILD_CORE) + ADD_SUBDIRECTORY(core) + ADD_SUBDIRECTORY(network) +ENDIF(BUILD_MONO AND NOT BUILD_CORE) + QT4_ADD_RESOURCES(_RCCS ${quassel_RCCS}) IF(BUILD_CORE) ADD_DEFINITIONS(-DBUILD_CORE) - ADD_SUBDIRECTORY(network) - ADD_SUBDIRECTORY(core) ADD_EXECUTABLE(quasselcore ${quassel_core_SRCS} ${_RCCS}) TARGET_LINK_LIBRARIES(quasselcore core network main ${QT_LIBRARIES}) ENDIF(BUILD_CORE) @@ -63,19 +74,16 @@ IF(BUILD_GUI OR BUILD_MONO) # OK, now we need QtGui! SET(QT_INCLUDE_DIR "") SET(QT_LIBRARIES "") INCLUDE(${QT_USE_FILE}) + ADD_SUBDIRECTORY(gui) IF(BUILD_MONO) ADD_DEFINITIONS(-DBUILD_MONO) - ADD_SUBDIRECTORY(gui) - ADD_SUBDIRECTORY(network) - ADD_SUBDIRECTORY(core) ADD_EXECUTABLE(quassel ${quassel_mono_SRCS} ${_RCCS}) TARGET_LINK_LIBRARIES(quassel gui core network main ${QT_LIBRARIES}) ENDIF(BUILD_MONO) IF(BUILD_GUI) ADD_DEFINITIONS(-DBUILD_GUI) - ADD_SUBDIRECTORY(gui) ADD_EXECUTABLE(quasselgui ${quassel_gui_SRCS} ${_RCCS}) TARGET_LINK_LIBRARIES(quasselgui gui main ${QT_LIBRARIES}) ENDIF(BUILD_GUI) diff --git a/Doxyfile b/Doxyfile index e5598415..e21b5598 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,11 +1,11 @@ -# Doxyfile 1.4.1-KDevelop +# Doxyfile 1.4.7 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -PROJECT_NAME = quassel.kdevelop +PROJECT_NAME = "Quassel IRC" PROJECT_NUMBER = 0.1 -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = doc CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO @@ -24,28 +24,30 @@ ABBREVIATE_BRIEF = "The $name class" \ the ALWAYS_DETAILED_SEC = YES INLINE_INHERITED_MEMB = YES -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO STRIP_FROM_PATH = / STRIP_FROM_INC_PATH = SHORT_NAMES = YES -JAVADOC_AUTOBRIEF = YES +JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = YES INHERIT_DOCS = YES -DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = -OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO -SUBGROUPING = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO @@ -64,7 +66,7 @@ GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = NO +SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- @@ -80,7 +82,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = /home/sputnick/devel/quassel +INPUT = /home/sputnick/shared/Development/quassel/ FILE_PATTERNS = *.c \ *.cc \ *.cxx \ @@ -127,7 +129,7 @@ FILE_PATTERNS = *.c \ *.moc \ *.xpm \ *.dox -RECURSIVE = yes +RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = @@ -143,10 +145,12 @@ FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = NO -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -VERBATIM_HEADERS = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -207,7 +211,7 @@ MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- -GENERATE_XML = yes +GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = @@ -226,9 +230,9 @@ PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES +ENABLE_PREPROCESSING = NO MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = @@ -240,7 +244,7 @@ SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = quassel.tag -ALLEXTERNALS = NO +ALLEXTERNALS = YES EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- @@ -252,11 +256,12 @@ HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -UML_LOOK = NO +UML_LOOK = YES TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO +CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png diff --git a/Quassel.kdevelop.filelist b/Quassel.kdevelop.filelist index a8934b66..50baa357 100644 --- a/Quassel.kdevelop.filelist +++ b/Quassel.kdevelop.filelist @@ -35,3 +35,8 @@ main/quassel.h main/main_gui.cpp core/coreproxy.cpp core/coreproxy.h +main/util.cpp +main/util.h +gui/coreconnectdlg.ui +gui/coreconnectdlg.cpp +gui/coreconnectdlg.h diff --git a/core/core.cpp b/core/core.cpp index 7c341d57..169d28ad 100644 --- a/core/core.cpp +++ b/core/core.cpp @@ -33,30 +33,24 @@ Core::Core() { connect(&server, SIGNAL(recvLine(QString)), coreProxy, SLOT(csCoreMessage(QString))); + // Read global settings from config file QSettings s; - VarMap identities = s.value("Network/Identities").toMap(); - //VarMap networks = s.value("Network/ - quassel->putData("Identities", identities); + s.beginGroup("Global"); + QString key; + foreach(key, s.childKeys()) { + global->updateData(key, s.value(key)); + } + global->updateData("CoreReady", true); + // Now that we are in sync, we can connect signals to automatically store further updates. + // I don't think we care if global data changed locally or if it was updated by a client. + connect(global, SIGNAL(dataUpdatedRemotely(QString)), SLOT(globalDataUpdated(QString))); + connect(global, SIGNAL(dataPutLocally(QString)), SLOT(globalDataUpdated(QString))); server.start(); } -void Core::init() { - - -} - -/* -void Core::run() { - - connect(&server, SIGNAL(recvLine(const QString &)), this, SIGNAL(outputLine(const QString &))); - //connect( - server.start(); - exec(); -} -*/ - void Core::connectToIrc(const QString &h, quint16 port) { + if(server.isConnected()) return; qDebug() << "Core: Connecting to " << h << ":" << port; server.connectToIrc(h, port); } @@ -66,14 +60,10 @@ void Core::inputLine(QString s) { } -VarMap Core::loadIdentities() { - QSettings s; - return s.value("Network/Identities").toMap(); -} - -void Core::storeIdentities(VarMap identities) { +void Core::globalDataUpdated(QString key) { + QVariant data = global->getData(key); QSettings s; - s.setValue("Network/Identities", identities); + s.setValue(QString("Global/")+key, data); } -Core *core; +Core *core = 0; diff --git a/core/core.h b/core/core.h index 96cba3a0..46258ae6 100644 --- a/core/core.h +++ b/core/core.h @@ -46,6 +46,9 @@ class Core : public QObject { signals: void outputLine(const QString &); // temp + private slots: + void globalDataUpdated(QString); + private: //void run(); diff --git a/core/coreproxy.cpp b/core/coreproxy.cpp index ab003842..dd14c812 100644 --- a/core/coreproxy.cpp +++ b/core/coreproxy.cpp @@ -18,16 +18,114 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "coreproxy.h" #include +#include "coreproxy.h" +#include "quassel.h" +#include "util.h" + CoreProxy::CoreProxy() { if(coreProxy) qFatal("Trying to instantiate more than one CoreProxy object!"); + connect(global, SIGNAL(dataPutLocally(QString)), this, SLOT(updateGlobalData(QString))); + connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); + if(!server.listen(QHostAddress::Any, 4242)) { + qFatal(QString(QString("Could not open GUI client port %1: %2").arg(4242).arg(server.errorString())).toAscii()); + } + qDebug() << "Listening for GUI clients on port" << server.serverPort() << "."; +} + +void CoreProxy::incomingConnection() { + QTcpSocket *socket = server.nextPendingConnection(); + connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData())); + clients.append(socket); + blockSizes.insert(socket, (quint32)0); + qDebug() << "Client connected from " << socket->peerAddress().toString(); +} + +void CoreProxy::clientHasData() { + QTcpSocket *socket = dynamic_cast(sender()); + Q_ASSERT(socket && blockSizes.contains(socket)); + quint32 bsize = blockSizes.value(socket); + QVariant item; + while(readDataFromDevice(socket, bsize, item)) { + QList sigdata = item.toList(); + Q_ASSERT(sigdata.size() == 4); + switch((GUISignal)sigdata[0].toInt()) { + case GS_CLIENT_INIT: processClientInit(socket, sigdata[1]); break; + case GS_UPDATE_GLOBAL_DATA: processClientUpdate(socket, sigdata[1].toString(), sigdata[2]); break; + //case GS_CLIENT_READY: processClientReady(sigdata[1], sigdata[2], sigdata[3]); break; + default: recv((GUISignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]); break; + } + blockSizes[socket] = bsize = 0; + } + blockSizes[socket] = bsize; +} + +void CoreProxy::clientDisconnected() { + QTcpSocket *socket = dynamic_cast(sender()); + blockSizes.remove(socket); + clients.removeAll(socket); + qDebug() << "Client disconnected."; +} + +void CoreProxy::processClientInit(QTcpSocket *socket, const QVariant &v) { + VarMap msg = v.toMap(); + if(msg["GUIProtocol"].toUInt() != GUI_PROTOCOL) { + qDebug() << "Client version mismatch. Disconnecting."; + socket->close(); + return; + } + VarMap reply; + VarMap coreData; + QStringList dataKeys = global->getKeys(); + QString key; + foreach(key, dataKeys) { + coreData[key] = global->getData(key); + } + reply["CoreData"] = coreData; + //QVariant payload = QByteArray(1000000, 'a'); + //reply["payload"] = payload; + QList sigdata; + sigdata.append(CS_CORE_STATE); sigdata.append(QVariant(reply)); sigdata.append(QVariant()); sigdata.append(QVariant()); + writeDataToDevice(socket, QVariant(sigdata)); +} + +void CoreProxy::processClientUpdate(QTcpSocket *socket, QString key, QVariant data) { + global->updateData(key, data); + QList sigdata; + sigdata.append(CS_UPDATE_GLOBAL_DATA); sigdata.append(key); sigdata.append(data); sigdata.append(QVariant()); + QTcpSocket *s; + foreach(s, clients) { + if(s != socket) writeDataToDevice(s, QVariant(sigdata)); + } +} + +void CoreProxy::updateGlobalData(QString key) { + QVariant data = global->getData(key); + emit csUpdateGlobalData(key, data); +} + +void CoreProxy::send(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + sendToGUI(sig, arg1, arg2, arg3); + QList sigdata; + sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3); + //qDebug() << "Sending signal: " << sigdata; + QTcpSocket *socket; + foreach(socket, clients) { + writeDataToDevice(socket, QVariant(sigdata)); + } } -void CoreProxy::csCoreMessage(QString s) { - send(CS_CORE_MESSAGE, s); +void CoreProxy::recv(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + //qDebug() << "[CORE] Received signal" << sig << ":" << arg1< -#include +#include +#include +#include /** This class is the Core side of the proxy. The Core connects its signals and slots to it, * and the calls are marshalled and sent to (or received and unmarshalled from) the GUIProxy. @@ -33,21 +34,37 @@ class CoreProxy : public QObject { Q_OBJECT - private: - void send(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); - void recv(GUISignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); - public: CoreProxy(); public slots: - void csCoreMessage(QString); - + inline void csCoreMessage(QString s) { send(CS_CORE_MESSAGE, s); } + inline void csUpdateGlobalData(QString key, QVariant data) { send(CS_UPDATE_GLOBAL_DATA, key, data); } signals: + void gsPutGlobalData(QString, QVariant); void gsUserInput(QString); void gsRequestConnect(QString, quint16); + private: + void send(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + void recv(GUISignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + void sendToGUI(CoreSignal, QVariant arg1, QVariant arg2, QVariant arg3); + + void processClientInit(QTcpSocket *socket, const QVariant &v); + void processClientUpdate(QTcpSocket *, QString key, QVariant data); + + private slots: + void incomingConnection(); + void clientHasData(); + void clientDisconnected(); + void updateGlobalData(QString key); + + private: + QTcpServer server; + QList clients; + QHash blockSizes; + friend class GUIProxy; }; diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index b622620a..8a8c328b 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,13 +1,14 @@ -SET(gui_SRCS channelwidget.cpp mainwin.cpp serverlist.cpp guiproxy.cpp) +SET(gui_SRCS channelwidget.cpp mainwin.cpp serverlist.cpp coreconnectdlg.cpp guiproxy.cpp) SET(gui_HDRS ) -SET(gui_MOCS channelwidget.h mainwin.h serverlist.h guiproxy.h) -SET(gui_UICS channelwidget.ui identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui nickeditdlg.ui serverlistdlg.ui) +SET(gui_MOCS channelwidget.h mainwin.h serverlist.h coreconnectdlg.h guiproxy.h) +SET(gui_UICS channelwidget.ui identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui nickeditdlg.ui serverlistdlg.ui coreconnectdlg.ui) QT4_WRAP_UI(_UIC ${gui_UICS}) QT4_WRAP_CPP(_MOC ${gui_MOCS}) # We need to work around a dependency bug with out-of-source builds... -SET_SOURCE_FILES_PROPERTIES(${gui_SRCS} PROPERTIES OBJECT_DEPENDS "${_UIC}") +# Seems to be fixed! +#SET_SOURCE_FILES_PROPERTIES(${gui_SRCS} PROPERTIES OBJECT_DEPENDS "${_UIC}") INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) ADD_LIBRARY(gui ${gui_HDRS} ${gui_SRCS} ${_MOC} ${_UIC}) diff --git a/gui/coreconnectdlg.cpp b/gui/coreconnectdlg.cpp new file mode 100644 index 00000000..477ac042 --- /dev/null +++ b/gui/coreconnectdlg.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel 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) 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. * + * * + * 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 "coreconnectdlg.h" +#include "guiproxy.h" +#include "quassel.h" + +CoreConnectDlg::CoreConnectDlg(QWidget *parent) : QDialog(parent) { + ui.setupUi(this); + ui.progressBar->hide(); + coreState = 0; + QSettings s; + connect(ui.hostName, SIGNAL(textChanged(QString)), this, SLOT(hostEditChanged(QString))); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(hostSelected())); + + ui.hostName->setText(s.value("GUI/CoreHost", "localhost").toString()); + ui.hostName->setSelection(0, ui.hostName->text().length()); + ui.hostPort->setValue(s.value("GUI/CorePort", 4242).toInt()); + ui.autoConnect->setChecked(s.value("GUI/CoreAutoConnect", true).toBool()); + if(s.value("GUI/CoreAutoConnect").toBool()) { + hostSelected(); + } +} + +void CoreConnectDlg::setStartState() { + ui.hostName->show(); ui.hostPort->show(); ui.hostLabel->show(); ui.portLabel->show(); + ui.statusText->setText(tr("Connect to Quassel Core running on:")); + ui.buttonBox->button(QDialogButtonBox::Ok)->show(); + ui.hostName->setEnabled(true); ui.hostPort->setEnabled(true); + ui.hostName->setSelection(0, ui.hostName->text().length()); +} + +void CoreConnectDlg::hostEditChanged(QString txt) { + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(txt.length()); +} + +void CoreConnectDlg::hostSelected() { + ui.hostName->hide(); ui.hostPort->hide(); ui.hostLabel->hide(); ui.portLabel->hide(); + ui.statusText->setText(tr("Connecting to %1:%2" ).arg(ui.hostName->text()).arg(ui.hostPort->value())); + ui.buttonBox->button(QDialogButtonBox::Ok)->hide(); + connect(guiProxy, SIGNAL(coreConnected()), this, SLOT(coreConnected())); + connect(guiProxy, SIGNAL(coreConnectionError(QString)), this, SLOT(coreConnectionError(QString))); + guiProxy->connectToCore(ui.hostName->text(), ui.hostPort->value()); + +} + +void CoreConnectDlg::coreConnected() { + ui.hostLabel->hide(); ui.hostName->hide(); ui.portLabel->hide(); ui.hostPort->hide(); + ui.statusText->setText(tr("Synchronizing...")); + QSettings s; + s.setValue("GUI/CoreHost", ui.hostName->text()); + s.setValue("GUI/CorePort", ui.hostPort->value()); + s.setValue("GUI/CoreAutoConnect", ui.autoConnect->isChecked()); + connect(guiProxy, SIGNAL(recvPartialItem(quint32, quint32)), this, SLOT(updateProgressBar(quint32, quint32))); + connect(guiProxy, SIGNAL(csCoreState(QVariant)), this, SLOT(recvCoreState(QVariant))); + ui.progressBar->show(); + VarMap initmsg; + initmsg["GUIProtocol"] = GUI_PROTOCOL; + guiProxy->send(GS_CLIENT_INIT, QVariant(initmsg)); +} + +void CoreConnectDlg::coreConnectionError(QString err) { + QMessageBox::warning(this, tr("Connection Error"), tr("Could not connect to Quassel Core!
\n") + err, QMessageBox::Retry); + disconnect(guiProxy, 0, this, 0); + ui.autoConnect->setChecked(false); + setStartState(); +} + +void CoreConnectDlg::updateProgressBar(quint32 recv, quint32 avail) { + ui.progressBar->setMaximum(avail); + ui.progressBar->setValue(recv); +} + +void CoreConnectDlg::recvCoreState(QVariant state) { + ui.progressBar->hide(); + coreState = state; + accept(); +} + +QVariant CoreConnectDlg::getCoreState() { + return coreState; +} diff --git a/gui/coreconnectdlg.h b/gui/coreconnectdlg.h new file mode 100644 index 00000000..e0e85226 --- /dev/null +++ b/gui/coreconnectdlg.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel 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) 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. * + * * + * 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 _CORECONNECTDLG_H +#define _CORECONNECTDLG_H + +#include "coreconnectdlg.h" +#include "ui_coreconnectdlg.h" + +class CoreConnectDlg: public QDialog { + Q_OBJECT + + public: + CoreConnectDlg(QWidget *); + QVariant getCoreState(); + + private slots: + void hostEditChanged(QString); + void hostSelected(); + + void coreConnected(); + void coreConnectionError(QString); + void updateProgressBar(quint32 bytes, quint32 avail); + void recvCoreState(QVariant); + + private: + Ui::CoreConnectDlg ui; + QVariant coreState; + + void setStartState(); +}; + +#endif diff --git a/gui/coreconnectdlg.ui b/gui/coreconnectdlg.ui new file mode 100644 index 00000000..12b0be03 --- /dev/null +++ b/gui/coreconnectdlg.ui @@ -0,0 +1,172 @@ + + CoreConnectDlg + + + + 0 + 0 + 499 + 144 + + + + + 5 + 3 + 0 + 0 + + + + Connect to Quassel Core + + + :/default/server.png + + + false + + + + 9 + + + 6 + + + + + Connect to Quassel Core running on: + + + + + + + 0 + + + 6 + + + + + Host + + + + + + + + + + Port + + + + + + + 65535 + + + 1024 + + + 4242 + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + + 20 + 53 + + + + + + + + 0 + + + 6 + + + + + Connect automatically + + + true + + + + + + + Qt::Horizontal + + + + 101 + 31 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + + + + + buttonBox + rejected() + CoreConnectDlg + reject() + + + 507 + 273 + + + 297 + 151 + + + + + diff --git a/gui/guiproxy.cpp b/gui/guiproxy.cpp index 4875d067..256f5a2f 100644 --- a/gui/guiproxy.cpp +++ b/gui/guiproxy.cpp @@ -18,19 +18,20 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "guiproxy.h" - -GUIProxy::GUIProxy() { - if(guiProxy) qFatal("Trying to instantiate more than one CoreProxy object!"); - -} +#include -void GUIProxy::gsUserInput(QString s) { - send(GS_USER_INPUT, s); -} +#include "guiproxy.h" +#include "util.h" -void GUIProxy::gsRequestConnect(QString h, quint16 p) { - send(GS_REQUEST_CONNECT, h, p); +void GUIProxy::recv(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + //qDebug() << "[GUI] Received signal:" << sig < #include +#include /** This class is the GUI side of the proxy. The GUI connects its signals and slots to it, * and the calls are marshalled and sent to (or received and unmarshalled from) the CoreProxy. @@ -33,20 +34,42 @@ class GUIProxy : public QObject { Q_OBJECT - private: - void send(GUISignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); - void recv(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); - public: GUIProxy(); public slots: - void gsUserInput(QString); - void gsRequestConnect(QString, quint16); + inline void gsUserInput(QString s) { send(GS_USER_INPUT, s); } + inline void gsRequestConnect(QString host, quint16 port) { send(GS_REQUEST_CONNECT, host, port); } + //inline void gsPutQuasselData(QString key, QVariant data) { send(GS_PUT_QUASSEL_DATA, key, data); } + void connectToCore(QString host, quint16 port); + void disconnectFromCore(); signals: + void csCoreState(QVariant); void csCoreMessage(QString); + void csUpdateGlobalData(QString key, QVariant data); + void csGlobalDataChanged(QString key); + + void coreConnected(); + void coreDisconnected(); + void coreConnectionError(QString errorMsg); + + void recvPartialItem(quint32 avail, quint32 size); + + public: + void send(GUISignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + void recv(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + + private slots: + void updateCoreData(QString); + + void serverError(QAbstractSocket::SocketError); + void serverHasData(); + + private: + QTcpSocket socket; + quint32 blockSize; friend class CoreProxy; diff --git a/gui/mainwin.cpp b/gui/mainwin.cpp index d67309d4..ec6d8d47 100644 --- a/gui/mainwin.cpp +++ b/gui/mainwin.cpp @@ -20,30 +20,58 @@ #include +#include "quassel.h" + #include "mainwin.h" #include "channelwidget.h" #include "serverlist.h" - -#include "core.h" -#include "server.h" +#include "coreconnectdlg.h" MainWin::MainWin() : QMainWindow() { setWindowTitle("Quassel IRC"); - setWindowIcon(QIcon(":/default/tux.png")); + setWindowIcon(QIcon(":/qirc-icon.png")); setWindowIconText("Quassel IRC"); //workspace = new QWorkspace(this); //setCentralWidget(workspace); - ChannelWidget *cw = new ChannelWidget(this); + //ChannelWidget *cw = new ChannelWidget(this); //workspace->addWindow(cw); - setCentralWidget(cw); + //setCentralWidget(cw); + statusBar()->showMessage(tr("Waiting for core...")); + setEnabled(false); + show(); + syncToCore(); + setEnabled(true); serverListDlg = new ServerListDlg(this); serverListDlg->setVisible(serverListDlg->showOnStartup()); - //showServerList(); - setupMenus(); - statusBar()->showMessage(tr("Ready")); + //identitiesAct = settingsMenu->addAction(QIcon(":/default/identity.png"), tr("&Identities..."), serverListDlg, SLOT(editIdentities())); + //showServerList(); + ChannelWidget *cw = new ChannelWidget(this); + setCentralWidget(cw); + //setEnabled(true); + statusBar()->showMessage(tr("Ready.")); +} +void MainWin::syncToCore() { + if(global->getData("CoreReady").toBool()) return; + // ok, apparently we are running as standalone GUI + coreConnectDlg = new CoreConnectDlg(this); + if(coreConnectDlg->exec() != QDialog::Accepted) { + //qApp->quit(); + exit(1); + } + VarMap state = coreConnectDlg->getCoreState().toMap()["CoreData"].toMap(); + delete coreConnectDlg; + QString key; + foreach(key, state.keys()) { + global->updateData(key, state[key]); + } + if(!global->getData("CoreReady").toBool()) { + QMessageBox::critical(this, tr("Fatal Error"), tr("Could not synchronize with Quassel Core!
Quassel GUI will be aborted."), QMessageBox::Abort); + //qApp->quit(); + exit(1); + } } void MainWin::setupMenus() { @@ -75,7 +103,6 @@ void MainWin::setupMenus() { aboutAct->setEnabled(0); aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt())); - //toolBar = new QToolBar("Test", this); //toolBar->addAction(identitiesAct); //addToolBar(Qt::TopToolBarArea, toolBar); diff --git a/gui/mainwin.h b/gui/mainwin.h index 6ca7f248..faaae576 100644 --- a/gui/mainwin.h +++ b/gui/mainwin.h @@ -27,6 +27,7 @@ class QMenu; class QWorkspace; class ServerListDlg; +class CoreConnectDlg; class MainWin : public QMainWindow { Q_OBJECT @@ -38,10 +39,11 @@ class MainWin : public QMainWindow { private slots: void showServerList(); - + private: void setupMenus(); - + void syncToCore(); + QWorkspace *workspace; QToolBar *toolBar; QMenu *fileMenu, *editMenu, *ircMenu, *serverMenu, *windowMenu, *helpMenu, *settingsMenu; @@ -50,6 +52,7 @@ class MainWin : public QMainWindow { QAction *identitiesAct, *configAct; ServerListDlg *serverListDlg; + CoreConnectDlg *coreConnectDlg; }; #endif diff --git a/gui/serverlist.cpp b/gui/serverlist.cpp index 677d3f41..06e73a6a 100644 --- a/gui/serverlist.cpp +++ b/gui/serverlist.cpp @@ -24,15 +24,13 @@ /* NOTE: This dialog holds not only the server list, but also the identities. * This makes perfect sense given the fact that connections are initiated from * this dialog, and that the dialog exists during the lifetime of the program. - * This data is also only used from within the GUI, which means it shouldn't be - * part of the global Quassel class (me thinks). */ ServerListDlg::ServerListDlg(QWidget *parent) : QDialog(parent) { ui.setupUi(this); QSettings settings; - settings.beginGroup("Network"); + settings.beginGroup("GUI"); ui.showOnStartup->setChecked(settings.value("ShowServerListOnStartup", true).toBool()); // create some default entries VarMap s1, s2, s3, s4; @@ -114,22 +112,14 @@ void ServerListDlg::storeNetworks() { } void ServerListDlg::loadIdentities() { - //QSettings s; - //s.beginGroup("Identities"); - //identities = s.value("Network/Identities").toMap(); - //identities = GuiProxy::loadIdentities(); - identities = quassel->getData("Identities").toMap(); + identities = global->getData("Identities", VarMap()).toMap(); while(!identities.contains("Default")) { - identities = VarMap(); editIdentities(); } } void ServerListDlg::storeIdentities() { - //QSettings s; - //s.setValue("Network/Identities", identities); - //GuiProxy::storeIdentities(identities); - quassel->putData("Identities", identities); + global->putData("Identities", identities); } void ServerListDlg::editIdentities() { @@ -137,7 +127,7 @@ void ServerListDlg::editIdentities() { if(dlg.exec() == QDialog::Accepted) { identities = dlg.getIdentities(); QMap mapping = dlg.getNameMapping(); - // add mapping here + // add mapping here <-- well, I don't fucking know anymore what I meant by this back in 2005... // storeIdentities(); @@ -147,7 +137,7 @@ void ServerListDlg::editIdentities() { void ServerListDlg::on_showOnStartup_stateChanged(int) { QSettings s; - s.setValue("Network/ShowServerListOnStartup", ui.showOnStartup->isChecked()); + s.setValue("GUI/ShowServerListOnStartup", ui.showOnStartup->isChecked()); } /***************************************************************************/ @@ -177,6 +167,8 @@ VarMap NetworkEditDlg::createDefaultNetwork() { IdentitiesDlg::IdentitiesDlg(QWidget *parent, VarMap _identities) : QDialog(parent) { ui.setupUi(this); + connect(global, SIGNAL(dataUpdatedRemotely(QString)), this, SLOT(globalDataUpdated(QString))); + connect(ui.enableAutoAway, SIGNAL(stateChanged(int)), this, SLOT(autoAwayChecked())); identities = _identities; @@ -205,6 +197,17 @@ IdentitiesDlg::IdentitiesDlg(QWidget *parent, VarMap _identities) : QDialog(pare connect(ui.downNickButton, SIGNAL(clicked()), this, SLOT(downNick())); } +void IdentitiesDlg::globalDataUpdated(QString key) { + if(key == "Identities") { + if(QMessageBox::warning(this, tr("Data changed remotely!"), tr("Some other GUI client changed the identities data!
" + "Apply updated settings, losing all changes done locally?"), + QMessageBox::Apply|QMessageBox::Discard) == QMessageBox::Apply) { + identities = global->getData(key).toMap(); + updateWidgets(); + } + } +} + VarMap IdentitiesDlg::createDefaultIdentity() { VarMap id; id["RealName"] = "foo"; diff --git a/gui/serverlist.h b/gui/serverlist.h index 854b2403..4ce25d7a 100644 --- a/gui/serverlist.h +++ b/gui/serverlist.h @@ -103,6 +103,8 @@ class IdentitiesDlg : public QDialog { void editIdentities(); + void globalDataUpdated(QString); + private: Ui::IdentitiesDlg ui; VarMap identities; diff --git a/images/icons.qrc b/images/icons.qrc index 4f8d0ce2..9b6281c4 100644 --- a/images/icons.qrc +++ b/images/icons.qrc @@ -89,5 +89,6 @@ default/view_split.png default/view_top_bottom.png default/wizard.png + qirc-icon.png diff --git a/images/qirc-icon.png b/images/qirc-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5e438ef3f541e4b41d285632542c8af16d883894 GIT binary patch literal 9129 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 literal 0 HcmV?d00001 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 268a0276..17ce2796 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,5 +1,5 @@ -SET(main_SRCS quassel.cpp logger.cpp) -SET(main_HDRS ) +SET(main_SRCS quassel.cpp logger.cpp util.cpp) +SET(main_HDRS util.h) SET(main_MOCS quassel.h logger.h) QT4_WRAP_CPP(_MOC ${main_MOCS}) diff --git a/main/main_core.cpp b/main/main_core.cpp index 90f46c18..19970342 100644 --- a/main/main_core.cpp +++ b/main/main_core.cpp @@ -20,10 +20,14 @@ #include #include +#include +#include +#include #include "quassel.h" #include "core.h" #include "coreproxy.h" +#include "util.h" int main(int argc, char **argv) { QCoreApplication app(argc, argv); @@ -31,32 +35,22 @@ int main(int argc, char **argv) { QCoreApplication::setApplicationName("Quassel IRC"); QCoreApplication::setOrganizationName("The Quassel Team"); - Quassel::runMode = Quassel::CoreOnly; - quassel = new Quassel(); + Global::runMode = Global::CoreOnly; + global = new Global(); coreProxy = new CoreProxy(); core = new Core(); //Logger *logger = new Logger(); //Quassel::setLogger(logger); - core->init(); - int exitCode = app.exec(); delete core; delete coreProxy; - delete quassel; + delete global; return exitCode; } -Core *core = 0; - -//GUIProxy::send(uint func, QVariant arg) { - /* - switch(func) { - case LOAD_IDENTITIES: return (QVariant) CoreProxy::loadIdentities(); - case STORE_IDENTITIES: CoreProxy::storeIdentities(arg.toMap()); return 0; - - } - */ +void CoreProxy::sendToGUI(CoreSignal, QVariant, QVariant, QVariant) { + // dummy function, no GUI available! +} -//} diff --git a/main/main_gui.cpp b/main/main_gui.cpp index 10bc53e1..bf6ed146 100644 --- a/main/main_gui.cpp +++ b/main/main_gui.cpp @@ -24,6 +24,7 @@ #include "quassel.h" #include "guiproxy.h" +#include "util.h" #include "mainwin.h" @@ -33,25 +34,68 @@ int main(int argc, char **argv) { QApplication::setApplicationName("Quassel IRC"); QApplication::setOrganizationName("The Quassel Team"); - Quassel::runMode = Quassel::GUIOnly; - quassel = new Quassel(); + Global::runMode = Global::GUIOnly; + global = new Global(); guiProxy = new GUIProxy(); MainWin mainWin; - mainWin.show(); int exitCode = app.exec(); delete guiProxy; - delete quassel; + delete global; } -void GUIProxy::send(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { +GUIProxy::GUIProxy() { + if(guiProxy) qFatal("Trying to instantiate more than one CoreProxy object!"); + + blockSize = 0; + + connect(&socket, SIGNAL(readyRead()), this, SLOT(serverHasData())); + connect(&socket, SIGNAL(connected()), this, SIGNAL(coreConnected())); + connect(&socket, SIGNAL(disconnected()), this, SIGNAL(coreDisconnected())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(serverError(QAbstractSocket::SocketError))); + connect(global, SIGNAL(dataPutLocally(QString)), this, SLOT(updateCoreData(QString))); + connect(this, SIGNAL(csUpdateGlobalData(QString, QVariant)), global, SLOT(updateData(QString, QVariant))); + +} +void GUIProxy::connectToCore(QString host, quint16 port) { + socket.connectToHost(host, port); + //VarMap initmsg; + //initmsg["GUIProtocol"] = GUI_PROTOCOL; + //send(GS_CLIENT_INIT, QVariant(initmsg)); +} +void GUIProxy::disconnectFromCore() { + socket.close(); } -void GUIProxy::recv(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { +void GUIProxy::serverError(QAbstractSocket::SocketError) { + emit coreConnectionError(socket.errorString()); +} +void GUIProxy::serverHasData() { + QVariant item; + while(readDataFromDevice(&socket, blockSize, item)) { + emit recvPartialItem(1,1); + QList sigdata = item.toList(); + Q_ASSERT(sigdata.size() == 4); + recv((CoreSignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]); + blockSize = 0; + } + if(blockSize > 0) { + emit recvPartialItem(socket.bytesAvailable(), blockSize); + } +} +void GUIProxy::send(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + QList sigdata; + sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3); + //qDebug() << "Sending signal: " << sigdata; + writeDataToDevice(&socket, QVariant(sigdata)); +} +void GUIProxy::updateCoreData(QString key) { + QVariant data = global->getData(key); + send(GS_UPDATE_GLOBAL_DATA, key, data); } diff --git a/main/main_mono.cpp b/main/main_mono.cpp index c7fb094c..0a37bcbb 100644 --- a/main/main_mono.cpp +++ b/main/main_mono.cpp @@ -35,43 +35,39 @@ int main(int argc, char **argv) { QApplication::setApplicationName("Quassel IRC"); QApplication::setOrganizationName("The Quassel Team"); - Quassel::runMode = Quassel::Monolithic; - quassel = new Quassel(); + Global::runMode = Global::Monolithic; + global = new Global(); guiProxy = new GUIProxy(); coreProxy = new CoreProxy(); core = new Core(); - core->init(); - MainWin mainWin; mainWin.show(); int exitCode = app.exec(); delete core; delete guiProxy; delete coreProxy; - delete quassel; + delete global; return exitCode; } -void GUIProxy::send(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { - coreProxy->recv(sig, arg1, arg2, arg3); +void CoreProxy::sendToGUI(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + guiProxy->recv(sig, arg1, arg2, arg3); } -void CoreProxy::recv(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { - switch(sig) { - case GS_USER_INPUT: emit gsUserInput(arg1.toString()); break; - case GS_REQUEST_CONNECT: emit gsRequestConnect(arg1.toString(), arg2.toUInt()); break; - default: qWarning() << "Unknown signal in CoreProxy::recv: " << sig; - } +GUIProxy::GUIProxy() { + if(guiProxy) qFatal("Trying to instantiate more than one CoreProxy object!"); } -void CoreProxy::send(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { - guiProxy->recv(sig, arg1, arg2, arg3); +void GUIProxy::send(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + coreProxy->recv(sig, arg1, arg2, arg3); } -void GUIProxy::recv(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { - switch(sig) { - case CS_CORE_MESSAGE: emit csCoreMessage(arg1.toString()); break; - default: qWarning() << "Unknown signal in GUIProxy::recv: " << sig; - } -} +// Dummy function definitions +// These are not needed, since we don't have a network connection to the core. +void GUIProxy::serverHasData() {} +void GUIProxy::connectToCore(QString, quint16) {} +void GUIProxy::disconnectFromCore() {} +void GUIProxy::updateCoreData(QString) {} +void GUIProxy::serverError(QAbstractSocket::SocketError) {} + diff --git a/main/proxy_common.h b/main/proxy_common.h index a25864c0..197e3de6 100644 --- a/main/proxy_common.h +++ b/main/proxy_common.h @@ -21,11 +21,11 @@ #ifndef _PROXY_COMMON_H_ #define _PROXY_COMMON_H_ -enum GUISignal { GS_USER_INPUT, GS_REQUEST_CONNECT, +enum GUISignal { GS_CLIENT_INIT, GS_USER_INPUT, GS_REQUEST_CONNECT, GS_UPDATE_GLOBAL_DATA, }; -enum CoreSignal { CS_CORE_MESSAGE +enum CoreSignal { CS_CORE_STATE, CS_CORE_MESSAGE, CS_UPDATE_GLOBAL_DATA, }; diff --git a/main/quassel.cpp b/main/quassel.cpp index 7ba190b1..cb35cc21 100644 --- a/main/quassel.cpp +++ b/main/quassel.cpp @@ -20,46 +20,61 @@ #include "quassel.h" #include "logger.h" -//#include "proxy.h" #include "core.h" #include +#include #include extern void messageHandler(QtMsgType type, const char *msg); -Quassel::Quassel() { - if(quassel) qFatal("Trying to instantiate more than one Quassel object!"); +Global::Global() { + if(global) qFatal("Trying to instantiate more than one Global object!"); qInstallMsgHandler(messageHandler); //initIconMap(); } /* -void Quassel::setLogger(Logger *) { +void Global::setLogger(Logger *) { }; */ -QVariant Quassel::getData(QString key) { +QVariant Global::getData(QString key, QVariant defval) { + QVariant d; mutex.lock(); - QVariant d = data[key]; + if(data.contains(key)) d = data[key]; + else d = defval; mutex.unlock(); - qDebug() << "getData("< //#include /* Some global stuff */ typedef QMap VarMap; -extern Quassel *quassel; +extern Global *global; /** - * A static class containing global data. - * This is used in both core and GUI modules. Where appropriate, accessors are thread-safe - * to account for that fact. - */ -class Quassel : public QObject { + * This class is mostly a globally synchronized data store, meant for storing systemwide settings such + * as identities or network lists. This class is a singleton, but not static as we'd like to use signals and + * slots with it. + * The global object is used in both Core and GUI clients. Storing and retrieving data is thread-safe. + * \note While updated data is propagated to all the remote parts of Quassel quite quickly, the synchronization + * protocol is in no way designed to guarantee strict consistency at all times. In other words, it may + * well happen that different instances of global data differ from one another for a little while until + * all update messages have been processed. You should never rely on all global data stores being consistent. +*/ +class Global : public QObject { Q_OBJECT public: - Quassel(); + Global(); //static Logger *getLogger(); //static void setLogger(Logger *); // static QIcon *getIcon(QString symbol); - QVariant getData(QString key); + QVariant getData(QString key, QVariant defaultValue = QVariant()); + QStringList getKeys(); public slots: - void putData(QString key, const QVariant &data); + void putData(QString key, QVariant data); ///< Store data changed locally, will be propagated to all other clients and the core + void updateData(QString key, QVariant data); ///< Update stored data if requested by the core or other clients signals: - void dataChanged(QString key, const QVariant &data); + void dataPutLocally(QString key); + void dataUpdatedRemotely(QString key); // sent by remote update only! public: enum RunMode { Monolithic, GUIOnly, CoreOnly }; @@ -59,7 +70,7 @@ class Quassel : public QObject { private: static void initIconMap(); - + //static Logger *logger; // static QString iconPath; diff --git a/main/util.cpp b/main/util.cpp new file mode 100644 index 00000000..71c19132 --- /dev/null +++ b/main/util.cpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel 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) 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. * + * * + * 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 "util.h" + +#include + +void writeDataToDevice(QIODevice *dev, const QVariant &item) { + QByteArray block; + QDataStream out(&block, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_1); + out << (quint32)0 << item; + out.device()->seek(0); + out << (quint32)(block.size() - sizeof(quint32)); + dev->write(block); +} + +bool readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item) { + QDataStream in(dev); + in.setVersion(QDataStream::Qt_4_1); + + if(blockSize == 0) { + if(dev->bytesAvailable() < (int)sizeof(quint32)) return false; + in >> blockSize; + } + if(dev->bytesAvailable() < blockSize) return false; + in >> item; + return true; +} diff --git a/main/util.h b/main/util.h new file mode 100644 index 00000000..1df034ca --- /dev/null +++ b/main/util.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel 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) 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. * + * * + * 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 _UTIL_H_ +#define _UTIL_H_ + +#include +#include + +/** + * Writes a QVariant to a device. The data item is prefixed with the resulting blocksize, + * so the corresponding function readDataFromDevice() can check if enough data is available + * at the device to reread the item. + */ +void writeDataToDevice(QIODevice *, const QVariant &); + +/** Reads a data item from a device that has previously been written by writeDataToDevice(). + * If not enough data bytes are available, the function returns false and the QVariant reference + * remains untouched. + */ +bool readDataFromDevice(QIODevice *, quint32 &, QVariant &); + + + + + +#endif diff --git a/network/server.h b/network/server.h index b0077c19..5e619588 100644 --- a/network/server.h +++ b/network/server.h @@ -29,8 +29,9 @@ #define DEFAULT_PORT 6667 +/*! \file */ -/** +/*! \class Server * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on. * We have this run in its own thread mainly to not block other server objects or the core if something goes wrong, * e.g. if some scripts starts running wild... @@ -47,6 +48,7 @@ class Server : public QThread { void run(); // serverState state(); + bool isConnected() { return socket.state() == QAbstractSocket::ConnectedState; } public slots: // void setServerOptions(); -- 2.20.1