1313a820fSNicolas Bonnefon /*
2313a820fSNicolas Bonnefon * Copyright (C) 2013 Nicolas Bonnefon and other contributors
3313a820fSNicolas Bonnefon *
4313a820fSNicolas Bonnefon * This file is part of glogg.
5313a820fSNicolas Bonnefon *
6313a820fSNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify
7313a820fSNicolas Bonnefon * it under the terms of the GNU General Public License as published by
8313a820fSNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or
9313a820fSNicolas Bonnefon * (at your option) any later version.
10313a820fSNicolas Bonnefon *
11313a820fSNicolas Bonnefon * glogg is distributed in the hope that it will be useful,
12313a820fSNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of
13313a820fSNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14313a820fSNicolas Bonnefon * GNU General Public License for more details.
15313a820fSNicolas Bonnefon *
16313a820fSNicolas Bonnefon * You should have received a copy of the GNU General Public License
17313a820fSNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>.
18313a820fSNicolas Bonnefon */
19313a820fSNicolas Bonnefon
20313a820fSNicolas Bonnefon #include "signalmux.h"
21313a820fSNicolas Bonnefon
22313a820fSNicolas Bonnefon #include <algorithm>
23313a820fSNicolas Bonnefon #include <QObject>
24313a820fSNicolas Bonnefon
25313a820fSNicolas Bonnefon #include "log.h"
26313a820fSNicolas Bonnefon
SignalMux()27313a820fSNicolas Bonnefon SignalMux::SignalMux() :
28313a820fSNicolas Bonnefon connectionList_()
29313a820fSNicolas Bonnefon {
30313a820fSNicolas Bonnefon currentDocument_ = nullptr;
31313a820fSNicolas Bonnefon }
32313a820fSNicolas Bonnefon
connect(QObject * sender,const char * signal,const char * slot)33313a820fSNicolas Bonnefon void SignalMux::connect( QObject *sender,
34313a820fSNicolas Bonnefon const char *signal, const char *slot )
35313a820fSNicolas Bonnefon {
36313a820fSNicolas Bonnefon Connection new_connection = {
37313a820fSNicolas Bonnefon sender,
38313a820fSNicolas Bonnefon nullptr,
39313a820fSNicolas Bonnefon signal,
40313a820fSNicolas Bonnefon slot };
41313a820fSNicolas Bonnefon
42313a820fSNicolas Bonnefon connectionList_.push_back( new_connection );
43313a820fSNicolas Bonnefon
44313a820fSNicolas Bonnefon connect( new_connection );
45313a820fSNicolas Bonnefon }
46313a820fSNicolas Bonnefon
disconnect(QObject * sender,const char * signal,const char * slot)47313a820fSNicolas Bonnefon void SignalMux::disconnect( QObject *sender,
48313a820fSNicolas Bonnefon const char *signal, const char *slot )
49313a820fSNicolas Bonnefon {
50313a820fSNicolas Bonnefon // Find any signal that match our description
51313a820fSNicolas Bonnefon auto connection = std::find_if(
52313a820fSNicolas Bonnefon connectionList_.begin(), connectionList_.end(),
53313a820fSNicolas Bonnefon [sender, signal, slot]( const Connection& c ) -> bool
54313a820fSNicolas Bonnefon { return ((QObject*)c.source == sender) && (c.sink == nullptr) &&
55313a820fSNicolas Bonnefon (qstrcmp( c.signal, signal) == 0) && (qstrcmp( c.slot, slot) == 0); } );
56313a820fSNicolas Bonnefon
57313a820fSNicolas Bonnefon if ( connection != connectionList_.end() )
58313a820fSNicolas Bonnefon {
59313a820fSNicolas Bonnefon disconnect( *connection );
60313a820fSNicolas Bonnefon
61313a820fSNicolas Bonnefon connectionList_.erase( connection );
62313a820fSNicolas Bonnefon }
63313a820fSNicolas Bonnefon else
64313a820fSNicolas Bonnefon {
65313a820fSNicolas Bonnefon LOG( logERROR ) << "SignalMux disconnecting a non-existing signal";
66313a820fSNicolas Bonnefon }
67313a820fSNicolas Bonnefon }
68313a820fSNicolas Bonnefon
69313a820fSNicolas Bonnefon // Upstream signals
connect(const char * signal,QObject * receiver,const char * slot)70313a820fSNicolas Bonnefon void SignalMux::connect( const char* signal,
71313a820fSNicolas Bonnefon QObject* receiver, const char* slot )
72313a820fSNicolas Bonnefon {
73313a820fSNicolas Bonnefon Connection new_connection = {
74313a820fSNicolas Bonnefon nullptr,
75313a820fSNicolas Bonnefon receiver,
76313a820fSNicolas Bonnefon signal,
77313a820fSNicolas Bonnefon slot };
78313a820fSNicolas Bonnefon
79313a820fSNicolas Bonnefon connectionList_.push_back( new_connection );
80313a820fSNicolas Bonnefon
81313a820fSNicolas Bonnefon connect( new_connection );
82313a820fSNicolas Bonnefon }
83313a820fSNicolas Bonnefon
disconnect(const char * signal,QObject * receiver,const char * slot)84313a820fSNicolas Bonnefon void SignalMux::disconnect( const char *signal,
85313a820fSNicolas Bonnefon QObject* receiver, const char *slot )
86313a820fSNicolas Bonnefon {
87313a820fSNicolas Bonnefon // Find any signal that match our description
88313a820fSNicolas Bonnefon auto connection = std::find_if(
89313a820fSNicolas Bonnefon connectionList_.begin(), connectionList_.end(),
90313a820fSNicolas Bonnefon [receiver, signal, slot]( const Connection& c ) -> bool
91313a820fSNicolas Bonnefon { return ((QObject*)c.sink == receiver) && (c.source == nullptr) &&
92313a820fSNicolas Bonnefon (qstrcmp( c.signal, signal) == 0) && (qstrcmp( c.slot, slot) == 0); } );
93313a820fSNicolas Bonnefon
94313a820fSNicolas Bonnefon if ( connection != connectionList_.end() )
95313a820fSNicolas Bonnefon {
96313a820fSNicolas Bonnefon disconnect( *connection );
97313a820fSNicolas Bonnefon
98313a820fSNicolas Bonnefon connectionList_.erase( connection );
99313a820fSNicolas Bonnefon }
100313a820fSNicolas Bonnefon else
101313a820fSNicolas Bonnefon {
102313a820fSNicolas Bonnefon LOG( logERROR ) << "SignalMux disconnecting a non-existing signal";
103313a820fSNicolas Bonnefon }
104313a820fSNicolas Bonnefon }
105313a820fSNicolas Bonnefon
setCurrentDocument(QObject * current_document)106313a820fSNicolas Bonnefon void SignalMux::setCurrentDocument( QObject* current_document )
107313a820fSNicolas Bonnefon {
10832e44cfdSNicolas Bonnefon // First disconnect everything to/from the old document
10932e44cfdSNicolas Bonnefon for ( auto c: connectionList_ )
11032e44cfdSNicolas Bonnefon disconnect( c );
11132e44cfdSNicolas Bonnefon
112313a820fSNicolas Bonnefon currentDocument_ = current_document;
11332e44cfdSNicolas Bonnefon
11432e44cfdSNicolas Bonnefon // And now connect to/from the new document
11532e44cfdSNicolas Bonnefon for ( auto c: connectionList_ )
11632e44cfdSNicolas Bonnefon connect( c );
117*9cacd6a9SNicolas Bonnefon
118*9cacd6a9SNicolas Bonnefon // And ask the doc to emit all state signals
119*9cacd6a9SNicolas Bonnefon MuxableDocumentInterface* doc =
120*9cacd6a9SNicolas Bonnefon dynamic_cast<MuxableDocumentInterface*>( current_document );
121*9cacd6a9SNicolas Bonnefon if ( doc )
122*9cacd6a9SNicolas Bonnefon doc->sendAllStateSignals();
123313a820fSNicolas Bonnefon }
124313a820fSNicolas Bonnefon
125313a820fSNicolas Bonnefon /*
126313a820fSNicolas Bonnefon * Private functions
127313a820fSNicolas Bonnefon */
connect(const Connection & connection)128313a820fSNicolas Bonnefon void SignalMux::connect( const Connection& connection )
129313a820fSNicolas Bonnefon {
130313a820fSNicolas Bonnefon if ( currentDocument_ )
131313a820fSNicolas Bonnefon {
13227ddfd3aSNicolas Bonnefon LOG( logDEBUG ) << "SignalMux::connect";
133313a820fSNicolas Bonnefon if ( connection.source && ( ! connection.sink ) )
134313a820fSNicolas Bonnefon {
135313a820fSNicolas Bonnefon // Downstream signal
136313a820fSNicolas Bonnefon QObject::connect( connection.source, connection.signal,
137313a820fSNicolas Bonnefon currentDocument_, connection.slot );
138313a820fSNicolas Bonnefon }
139313a820fSNicolas Bonnefon else if ( ( ! connection.source ) && connection.sink )
140313a820fSNicolas Bonnefon {
141313a820fSNicolas Bonnefon // Upstream signal
142313a820fSNicolas Bonnefon QObject::connect( currentDocument_, connection.signal,
143313a820fSNicolas Bonnefon connection.sink, connection.slot );
144313a820fSNicolas Bonnefon }
145313a820fSNicolas Bonnefon else
146313a820fSNicolas Bonnefon {
147313a820fSNicolas Bonnefon LOG( logERROR ) << "SignalMux has an unexpected signal";
148313a820fSNicolas Bonnefon }
149313a820fSNicolas Bonnefon }
150313a820fSNicolas Bonnefon }
151313a820fSNicolas Bonnefon
disconnect(const Connection & connection)152313a820fSNicolas Bonnefon void SignalMux::disconnect( const Connection& connection )
153313a820fSNicolas Bonnefon {
154313a820fSNicolas Bonnefon if ( currentDocument_ )
155313a820fSNicolas Bonnefon {
15627ddfd3aSNicolas Bonnefon LOG( logDEBUG ) << "SignalMux::disconnect";
157313a820fSNicolas Bonnefon if ( connection.source && ( ! connection.sink ) )
158313a820fSNicolas Bonnefon {
159313a820fSNicolas Bonnefon // Downstream signal
160313a820fSNicolas Bonnefon QObject::disconnect( connection.source, connection.signal,
161313a820fSNicolas Bonnefon currentDocument_, connection.slot );
162313a820fSNicolas Bonnefon }
163313a820fSNicolas Bonnefon else if ( ( ! connection.source ) && connection.sink )
164313a820fSNicolas Bonnefon {
165313a820fSNicolas Bonnefon // Upstream signal
166313a820fSNicolas Bonnefon QObject::disconnect( currentDocument_, connection.signal,
167313a820fSNicolas Bonnefon connection.sink, connection.slot );
168313a820fSNicolas Bonnefon }
169313a820fSNicolas Bonnefon else
170313a820fSNicolas Bonnefon {
171313a820fSNicolas Bonnefon LOG( logERROR ) << "SignalMux has an unexpected signal";
172313a820fSNicolas Bonnefon }
173313a820fSNicolas Bonnefon }
174313a820fSNicolas Bonnefon }
175