Index: src/common.h =================================================================== --- src/common.h +++ src/common.h @@ -13,6 +13,7 @@ #ifndef COMMON_H #define COMMON_H +#include #include #include #include @@ -37,16 +38,6 @@ tnfNone }; - enum ConnectionState - { - SSNeverConnected, - SSDeliberatelyDisconnected, - SSInvoluntarilyDisconnected, - SSScheduledToConnect, - SSConnecting, - SSConnected - }; - enum ConnectionFlag { SilentlyReuseConnection, Index: src/connectionmanager.h =================================================================== --- src/connectionmanager.h +++ src/connectionmanager.h @@ -66,7 +66,7 @@ Q_SIGNALS: void connectionListChanged(); - void connectionChangedState(Server* server, Konversation::ConnectionState state); + void connectionChangedState(Server* server, Server::ConnectionState state); void connectionChangedAwayState(bool away); @@ -81,7 +81,7 @@ private Q_SLOTS: void delistConnection(int connectionId); - void handleConnectionStateChange(Server* server, Konversation::ConnectionState state); + void handleConnectionStateChange(Server::ConnectionState state); void handleReconnect(Server* server); Index: src/connectionmanager.cpp =================================================================== --- src/connectionmanager.cpp +++ src/connectionmanager.cpp @@ -156,8 +156,7 @@ connect(server, &Server::destroyed, this, &ConnectionManager::delistConnection); - connect(server, SIGNAL(connectionStateChanged(Server*,Konversation::ConnectionState)), - this, SLOT(handleConnectionStateChange(Server*,Konversation::ConnectionState))); + connect(server, &Server::connectionStateChanged, this, &ConnectionManager::handleConnectionStateChange); connect(server, &Server::awayState, this, &ConnectionManager::connectionChangedAwayState); @@ -184,13 +183,14 @@ emit connectionListChanged(); } -void ConnectionManager::handleConnectionStateChange(Server* server, Konversation::ConnectionState state) +void ConnectionManager::handleConnectionStateChange(Server::ConnectionState state) { + auto server = static_cast(sender()); emit connectionChangedState(server, state); int identityId = server->getIdentity()->id(); - if (state == Konversation::SSConnected) + if (state == Server::SSConnected) { m_overrideAutoReconnect = false; @@ -201,7 +201,7 @@ emit identityOnline(identityId); } } - else if (state != Konversation::SSConnecting) + else if (state != Server::SSConnecting) { if (m_activeIdentities.contains(identityId)) { @@ -211,14 +211,14 @@ } } - if (state == Konversation::SSInvoluntarilyDisconnected && !m_overrideAutoReconnect) + if (state == Server::SSInvoluntarilyDisconnected && !m_overrideAutoReconnect) { // The asynchronous invocation of handleReconnect() makes sure that // connectionChangedState() is emitted and delivered before it runs // (and causes the next connection state change to occur). emit requestReconnect(server); } - else if (state == Konversation::SSInvoluntarilyDisconnected && m_overrideAutoReconnect) + else if (state == Server::SSInvoluntarilyDisconnected && m_overrideAutoReconnect) { server->getStatusView()->appendServerMessage(i18n("Info"), i18n ("Network is down, will reconnect automatically when it is back up.")); } Index: src/irc/channel.h =================================================================== --- src/irc/channel.h +++ src/irc/channel.h @@ -248,7 +248,7 @@ void setAutoJoin(bool autojoin); - void connectionStateChanged(Server*, Konversation::ConnectionState); + void connectionStateChanged(Server::ConnectionState state); protected Q_SLOTS: void completeNick(); ///< I guess this is a GUI function, might be nice to have at DCOP level though --argonel Index: src/irc/channel.cpp =================================================================== --- src/irc/channel.cpp +++ src/irc/channel.cpp @@ -324,8 +324,7 @@ { if (m_server != server) { - connect(server, SIGNAL(connectionStateChanged(Server*,Konversation::ConnectionState)), - SLOT(connectionStateChanged(Server*,Konversation::ConnectionState))); + connect(server, &Server::connectionStateChanged, this, &Channel::connectionStateChanged); connect(server, SIGNAL(nickInfoChanged()), this, SLOT(updateNickInfos())); connect(server, SIGNAL(channelNickChanged(QString)), @@ -343,11 +342,12 @@ connect(awayLabel, SIGNAL(awayMessageChanged(QString)), m_server, SLOT(requestAway(QString))); } -void Channel::connectionStateChanged(Server* server, Konversation::ConnectionState state) +void Channel::connectionStateChanged(Server::ConnectionState state) { + Server *server = static_cast(sender()); if (server == m_server) { - if (state != Konversation::SSConnected) + if (state != Server::SSConnected) { m_joined = false; Index: src/irc/query.h =================================================================== --- src/irc/query.h +++ src/irc/query.h @@ -15,6 +15,7 @@ #include "chatwindow.h" #include "nickinfo.h" +#include "server.h" #include @@ -83,7 +84,7 @@ void sendText(const QString& text) Q_DECL_OVERRIDE; void indicateAway(bool show) Q_DECL_OVERRIDE; void setEncryptedOutput(bool); - void connectionStateChanged(Server*, Konversation::ConnectionState); + void connectionStateChanged(Server::ConnectionState); protected Q_SLOTS: void queryTextEntered(); Index: src/irc/query.cpp =================================================================== --- src/irc/query.cpp +++ src/irc/query.cpp @@ -114,8 +114,8 @@ { if (m_server != newServer) { - connect(newServer, SIGNAL(connectionStateChanged(Server*,Konversation::ConnectionState)), - SLOT(connectionStateChanged(Server*,Konversation::ConnectionState))); + connect(newServer, &Server::connectionStateChanged, + this, &Query::connectionStateChanged); connect(newServer, SIGNAL(nickInfoChanged(Server*,NickInfoPtr)), this, SLOT(updateNickInfo(Server*,NickInfoPtr))); } @@ -129,13 +129,14 @@ connect(awayLabel, SIGNAL(awayMessageChanged(QString)), m_server, SLOT(requestAway(QString))); } -void Query::connectionStateChanged(Server* server, Konversation::ConnectionState state) +void Query::connectionStateChanged(Server::ConnectionState state) { + auto server = static_cast(sender()); if (server == m_server) { ViewContainer* viewContainer = Application::instance()->getMainWindow()->getViewContainer(); - if (state == Konversation::SSConnected) + if (state == Server::SSConnected) { //HACK the way the notification priorities work sucks, this forces the tab text color to ungray right now. if (viewContainer->getFrontView() == this Index: src/irc/server.h =================================================================== --- src/irc/server.h +++ src/irc/server.h @@ -74,6 +74,7 @@ Q_PROPERTY(QString nickname READ getNickname WRITE setNickname NOTIFY nicknameChanged) Q_PROPERTY(UserModel* userModel READ getUserModel CONSTANT) // WIPQTQUICK + Q_PROPERTY(Server::ConnectionState connectionState READ getConnectionState NOTIFY connectionStateChanged) public: enum QueuePriority @@ -98,6 +99,17 @@ }; Q_DECLARE_FLAGS(CapModifiers, CapModifier) + enum ConnectionState + { + SSNeverConnected, + SSDeliberatelyDisconnected, + SSInvoluntarilyDisconnected, + SSScheduledToConnect, + SSConnecting, + SSConnected + }; + Q_ENUM(ConnectionState) + Server(QObject* parent, ConnectionSettings& settings); ~Server() override; @@ -117,11 +129,11 @@ Konversation::ServerGroupSettingsPtr getServerGroup() { return m_connectionSettings.serverGroup(); } IdentityPtr getIdentity() { return m_connectionSettings.identity(); } - Konversation::ConnectionState getConnectionState() { return m_connectionState; } + Server::ConnectionState getConnectionState() { return m_connectionState; } - bool isConnected() { return (m_connectionState == Konversation::SSConnected); } - bool isConnecting() { return (m_connectionState == Konversation::SSConnecting); } - bool isScheduledToConnect() { return (m_connectionState == Konversation::SSScheduledToConnect); } + bool isConnected() { return (m_connectionState == Server::SSConnected); } + bool isConnecting() { return (m_connectionState == Server::SSConnecting); } + bool isScheduledToConnect() { return (m_connectionState == Server::SSScheduledToConnect); } bool getUseSSL() const; QString getSSLInfo() const; @@ -467,7 +479,7 @@ void sslInitFailure(); void sslConnected(Server* server); - void connectionStateChanged(Server* server, Konversation::ConnectionState state); + void connectionStateChanged(Server::ConnectionState state); void showView(QObject* view); // WIPQTQUICK void addDccPanel(); @@ -769,8 +781,8 @@ QString m_nonAwayNick; int m_awayTime; - Konversation::ConnectionState m_connectionState; - void updateConnectionState(Konversation::ConnectionState state); + Server::ConnectionState m_connectionState; + void updateConnectionState(Server::ConnectionState state); bool isSocketConnected() const; KProcess m_preShellCommand; Index: src/irc/server.cpp =================================================================== --- src/irc/server.cpp +++ src/irc/server.cpp @@ -63,7 +63,7 @@ setConnectionSettings(settings); - m_connectionState = Konversation::SSNeverConnected; + m_connectionState = Server::SSNeverConnected; m_recreationScheduled = false; @@ -148,7 +148,7 @@ if (getIdentity()->getShellCommand().isEmpty()) connectSignals(); // TODO FIXME this disappeared in a merge, ensure it should have - updateConnectionState(Konversation::SSNeverConnected); + updateConnectionState(Server::SSNeverConnected); m_nickInfoChangedTimer = new QTimer(this); m_nickInfoChangedTimer->setSingleShot(true); @@ -455,11 +455,11 @@ // Reenable check when it works reliably for all backends // if(Solid::Networking::status() != Solid::Networking::Connected) // { -// updateConnectionState(Konversation::SSInvoluntarilyDisconnected); +// updateConnectionState(Server::SSInvoluntarilyDisconnected); // return; // } - updateConnectionState(Konversation::SSConnecting); + updateConnectionState(Server::SSConnecting); m_ownIpByUserhost.clear(); @@ -530,7 +530,7 @@ m_delayedConnectTimer->setInterval(delay * 1000); m_delayedConnectTimer->start(); - updateConnectionState(Konversation::SSScheduledToConnect); + updateConnectionState(Server::SSScheduledToConnect); } void Server::showSSLDialog() @@ -889,7 +889,7 @@ void Server::broken(KTcpSocket::Error error) { Q_UNUSED(error); - qDebug() << "Connection broken with state" << m_connectionState << "and error:" << m_socket->errorString(); + qDebug() << "Connection broken with state" << static_cast(m_connectionState) << "and error:" << m_socket->errorString(); m_socket->blockSignals(true); @@ -924,9 +924,9 @@ getConnectionSettings().server().host(), QString::number(getConnectionSettings().server().port()))); - updateConnectionState(SSDeliberatelyDisconnected); + updateConnectionState(Server::SSDeliberatelyDisconnected); } - else if (getConnectionState() == Konversation::SSDeliberatelyDisconnected) + else if (getConnectionState() == Server::SSDeliberatelyDisconnected) { if (m_reconnectImmediately) { @@ -946,7 +946,7 @@ getStatusView()->appendServerMessage(i18n("Error"), error); - updateConnectionState(Konversation::SSInvoluntarilyDisconnected); + updateConnectionState(Server::SSInvoluntarilyDisconnected); } // HACK Only show one nick change dialog at connection time. @@ -1012,7 +1012,7 @@ { // Don't auto-reconnect if the user chose to ignore the SSL errors -- // treat it as a deliberate disconnect. - updateConnectionState(Konversation::SSDeliberatelyDisconnected); + updateConnectionState(Server::SSDeliberatelyDisconnected); QString errorReason; @@ -1040,7 +1040,7 @@ if (!ownHost.isEmpty()) QHostInfo::lookupHost(ownHost, this, SLOT(gotOwnResolvedHostByWelcome(QHostInfo))); - updateConnectionState(Konversation::SSConnected); + updateConnectionState(Server::SSConnected); // Make a helper object to build ISON (notify) list. // TODO: Give the object a kick to get it started? @@ -1095,18 +1095,18 @@ return (m_socket->state() == KTcpSocket::ConnectedState); } -void Server::updateConnectionState(Konversation::ConnectionState state) +void Server::updateConnectionState(Server::ConnectionState state) { if (state != m_connectionState) { m_connectionState = state; - if (m_connectionState == Konversation::SSConnected) + if (m_connectionState == Server::SSConnected) emit serverOnline(true); - else if (m_connectionState != Konversation::SSConnecting) + else if (m_connectionState != Server::SSConnecting) emit serverOnline(false); - emit connectionStateChanged(this, state); + emit connectionStateChanged(state); } } @@ -1140,7 +1140,7 @@ // Make clear this is deliberate even if the QUIT never actually goes through the queue // (i.e. this is not redundant with _send_internal()'s updateConnectionState() call for // a QUIT). - updateConnectionState(Konversation::SSDeliberatelyDisconnected); + updateConnectionState(Server::SSDeliberatelyDisconnected); if (!m_socket) return; @@ -1570,7 +1570,7 @@ if (outboundCommand == 0 && outputLineSplit.count() >= 2) //"WHO" m_inputFilter.addWhoRequest(outputLineSplit[1]); else if (outboundCommand == 1) //"QUIT" - updateConnectionState(Konversation::SSDeliberatelyDisconnected); + updateConnectionState(Server::SSDeliberatelyDisconnected); // set channel encoding if specified QString channelCodecName; @@ -4435,17 +4435,17 @@ void Server::involuntaryQuit() { - if((m_connectionState == Konversation::SSConnected || m_connectionState == Konversation::SSConnecting) && + if((m_connectionState == Server::SSConnected || m_connectionState == Server::SSConnecting) && (m_socket->peerAddress() != QHostAddress(QHostAddress::LocalHost) && m_socket->peerAddress() != QHostAddress(QHostAddress::LocalHostIPv6))) { quitServer(); - updateConnectionState(Konversation::SSInvoluntarilyDisconnected); + updateConnectionState(Server::SSInvoluntarilyDisconnected); } } void Server::reconnectInvoluntary() { - if(m_connectionState == Konversation::SSInvoluntarilyDisconnected) + if(m_connectionState == Server::SSInvoluntarilyDisconnected) reconnectServer(); } Index: src/mainwindow.h =================================================================== --- src/mainwindow.h +++ src/mainwindow.h @@ -19,6 +19,7 @@ #include "common.h" #include "preferences.h" #include "ssllabel.h" +#include "server.h" #include @@ -74,7 +75,7 @@ void showQuickConnectDialog(); void nicksNowOnline(Server*); void endNotification(); - void serverStateChanged(Server* server, Konversation::ConnectionState state); + void serverStateChanged(Server* server, Server::ConnectionState state); void triggerRememberLine(); void triggerRememberLines(Server*); void cancelRememberLine(); Index: src/mainwindow.cpp =================================================================== --- src/mainwindow.cpp +++ src/mainwindow.cpp @@ -121,6 +121,7 @@ qputenv("QT_QUICK_CONTROLS_STYLE", "org.kde.desktop"); m_qmlEngine = new QQmlApplicationEngine(this); + qmlRegisterUncreatableType("org.kde.konversation", 1, 0, "Server", "Enums only"); qmlRegisterUncreatableType("org.kde.konversation", 1, 0, "MessageModel", ""); qmlRegisterUncreatableType("org.kde.konversation", 1, 0, "InputHistoryModel", ""); qmlRegisterUncreatableType("org.kde.konversation", 1, 0, "IrcContextMenus", ""); @@ -152,9 +153,8 @@ connect(m_viewContainer, SIGNAL(autoConnectOnStartupToggled(Konversation::ServerGroupSettingsPtr)), Application::instance(), SIGNAL(serverGroupsChanged(Konversation::ServerGroupSettingsPtr))); connect(m_viewContainer, SIGNAL(setWindowCaption(QString)), this, SLOT(setCaption(QString))); - connect(Application::instance()->getConnectionManager(), - SIGNAL(connectionChangedState(Server*,Konversation::ConnectionState)), - m_viewContainer, SLOT(connectionStateChanged(Server*,Konversation::ConnectionState))); + connect(Application::instance()->getConnectionManager(), &ConnectionManager::connectionChangedState, + m_viewContainer, &ViewContainer::connectionStateChanged); connect(this, SIGNAL(triggerRememberLine()), m_viewContainer, SLOT(insertRememberLine())); connect(this, SIGNAL(triggerRememberLines(Server*)), m_viewContainer, SLOT(insertRememberLines(Server*))); connect(this, SIGNAL(cancelRememberLine()), m_viewContainer, SLOT(cancelRememberLine())); Index: src/qtquick/uipackages/default/contents/ViewSwitcher.qml =================================================================== --- src/qtquick/uipackages/default/contents/ViewSwitcher.qml +++ src/qtquick/uipackages/default/contents/ViewSwitcher.qml @@ -15,6 +15,8 @@ import org.kde.kirigami 2.2 as Kirigami +import org.kde.konversation 1.0 as Konversation + Item { id: viewSwitcher @@ -134,7 +136,10 @@ readonly property int row: index readonly property bool hasActivity: model.HasActivity readonly property int unreadMentions: model.ViewRole.unreadMentions + property int connectionState: model.ViewRole ? model.ViewRole.server.connectionState : Konversation.Server.SSNeverConnected property Item unreadMentionsCounter: null + property Item loadingBar: null + text: model.display textMarginLeft: model.IsChild ? Kirigami.Units.gridUnit * 2 : Kirigami.Units.gridUnit @@ -155,6 +160,16 @@ Qt.callLater(ListView.view.updateOffViewportOverlay); } + onConnectionStateChanged: { + if (connectionState == Konversation.Server.SSConnecting) { + console.log("Adding loading bar"); + loadingBar = loadingBarComponent.createObject(viewListItem); + } else if (loadingBar) { + loadingBar.destroy(); + loadingBar = null; + } + } + onClicked: { viewListView.forceActiveFocus(); @@ -166,6 +181,45 @@ } } + Component { + id: loadingBarComponent + + QQC2.BusyIndicator { + id: loadingAnimator + running: true + anchors.right: parent.right + // we assume there won't be intersection with showing busy indicator and unread count + anchors.rightMargin: verticalScrollbar.visible ? verticalScrollbar.width : Kirigami.Units.smallSpacing + anchors.verticalCenter: parent.verticalCenter + height: Kirigami.Units.iconSizes.smallMedium + width: Kirigami.Units.iconSizes.smallMedium + contentItem: Kirigami.Icon { + source: "view-refresh" + } + + RotationAnimator { + target: loadingAnimator + running: loadingAnimator.visible && loadingAnimator.running + from: 360 + to: 0 + loops: Animation.Infinite + duration: 1000 + } + + NumberAnimation { + id: appear + target: loadingAnimator + property: "opacity" + duration: 1000 + from: 0.0 + to: 1.0 + + } + + Component.onCompleted: appear.running = true + } + } + Component { id: unreadMentionsCounterComponent Index: src/viewer/chatwindow.h =================================================================== --- src/viewer/chatwindow.h +++ src/viewer/chatwindow.h @@ -34,6 +34,7 @@ Q_PROPERTY(QString description READ getDescription NOTIFY descriptionChanged) Q_PROPERTY(IrcContextMenus::MenuOptions contextMenuOptions READ contextMenuOptions CONSTANT) Q_PROPERTY(int unreadMentions READ unreadMentions NOTIFY unreadMentionsChanged) + Q_PROPERTY(Server * server READ getServer NOTIFY serverChanged) public: explicit ChatWindow(QWidget* parent); @@ -156,6 +157,7 @@ void nameChanged(ChatWindow* view, const QString& newName); void titleChanged(); void descriptionChanged(); + void serverChanged(); //void online(ChatWindow* myself, bool state); /** Emit this signal when you want to change the status bar text for this tab. * It is ignored if this tab isn't focused. Index: src/viewer/chatwindow.cpp =================================================================== --- src/viewer/chatwindow.cpp +++ src/viewer/chatwindow.cpp @@ -217,18 +217,19 @@ { if (!newServer) { - qDebug() << "ChatWindow::setServer(0)!"; + qDebug() << "ChatWindow::setServer(nullptr)!"; } else if (m_server != newServer) { - m_server=newServer; + m_server = newServer; + emit serverChanged(); connect(m_server, &Server::serverOnline, this, &ChatWindow::serverOnline); // check if we need to set up the signals if(getType() != ChannelList) { if(textView) textView->setServer(newServer); - else qDebug() << "textView==0!"; + else qDebug() << "textView == nullptr!"; } serverOnline(m_server->isConnected()); Index: src/viewer/viewcontainer.h =================================================================== --- src/viewer/viewcontainer.h +++ src/viewer/viewcontainer.h @@ -222,7 +222,7 @@ void disconnectFrontServer(); void reconnectFrontServer(); void showJoinChannelDialog(); - void connectionStateChanged(Server* server, Konversation::ConnectionState state); + void connectionStateChanged(Server* server, Server::ConnectionState state); void channelJoined(Channel* channel); Channel* addChannel(Server* server, const QString& name); Index: src/viewer/viewcontainer.cpp =================================================================== --- src/viewer/viewcontainer.cpp +++ src/viewer/viewcontainer.cpp @@ -432,30 +432,32 @@ QModelIndex ViewContainer::index(int row, int column, const QModelIndex& parent) const { if (!m_tabWidget || column != 0) { + // we have only one column return QModelIndex(); } int tabIndex = -1; - if (parent.isValid()) { + // This looks like one of server tabs int parentTabIndex = m_tabWidget->indexOf(static_cast(parent.internalPointer())); - if (parentTabIndex != -1) { tabIndex = parentTabIndex + row + 1; } else { return QModelIndex(); } } else { + // We don't have parent, this may be top-level view int count = -1; - for (int i = 0; i < m_tabWidget->count(); ++i) { - if (static_cast(m_tabWidget->widget(i))->isTopLevelView()) { + // There can be more than one connected server, we should + // find correct top-level window for this row + auto window = static_cast(m_tabWidget->widget(i)); + if (window->isTopLevelView()) { ++count; } if (count == row) { tabIndex = i; - break; } } @@ -561,7 +563,7 @@ } else if (role == HighlightRole) { return (row == m_popupViewIndex); } else if (role == ViewRole) { - return qVariantFromValue(static_cast(index.internalPointer())); + return qVariantFromValue(static_cast(index.internalPointer())); } else if (role == IsChild) { return index.parent().isValid(); } else if (role == HasActivity) { @@ -2853,7 +2855,7 @@ delete dlg; } -void ViewContainer::connectionStateChanged(Server* server, Konversation::ConnectionState state) +void ViewContainer::connectionStateChanged(Server* server, Server::ConnectionState state) { Server* updateServer = nullptr; @@ -2866,20 +2868,20 @@ { QAction* action = actionCollection()->action("disconnect_server"); if (action) - action->setEnabled(state == Konversation::SSConnected || state == Konversation::SSConnecting || state == Konversation::SSScheduledToConnect); + action->setEnabled(state == Server::SSConnected || state == Server::SSConnecting || state == Server::SSScheduledToConnect); action = actionCollection()->action("join_channel"); if (action) - action->setEnabled(state == Konversation::SSConnected); + action->setEnabled(state == Server::SSConnected); if (m_frontView && m_frontView->getServer() == server && m_frontView->getType() == ChatWindow::Channel) { ChatWindow* view = m_frontView; Channel* channel = static_cast(view); action = actionCollection()->action("rejoin_channel"); - if (action) action->setEnabled(state == Konversation::SSConnected && channel->rejoinable()); + if (action) action->setEnabled(state == Server::SSConnected && channel->rejoinable()); } } }