1 /*
2 * Copyright (C) 2013 Nicolas Bonnefon and other contributors
3 *
4 * This file is part of glogg.
5 *
6 * glogg is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * glogg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with glogg. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "signalmux.h"
21
22 #include <algorithm>
23 #include <QObject>
24
25 #include "log.h"
26
SignalMux()27 SignalMux::SignalMux() :
28 connectionList_()
29 {
30 currentDocument_ = nullptr;
31 }
32
connect(QObject * sender,const char * signal,const char * slot)33 void SignalMux::connect( QObject *sender,
34 const char *signal, const char *slot )
35 {
36 Connection new_connection = {
37 sender,
38 nullptr,
39 signal,
40 slot };
41
42 connectionList_.push_back( new_connection );
43
44 connect( new_connection );
45 }
46
disconnect(QObject * sender,const char * signal,const char * slot)47 void SignalMux::disconnect( QObject *sender,
48 const char *signal, const char *slot )
49 {
50 // Find any signal that match our description
51 auto connection = std::find_if(
52 connectionList_.begin(), connectionList_.end(),
53 [sender, signal, slot]( const Connection& c ) -> bool
54 { return ((QObject*)c.source == sender) && (c.sink == nullptr) &&
55 (qstrcmp( c.signal, signal) == 0) && (qstrcmp( c.slot, slot) == 0); } );
56
57 if ( connection != connectionList_.end() )
58 {
59 disconnect( *connection );
60
61 connectionList_.erase( connection );
62 }
63 else
64 {
65 LOG( logERROR ) << "SignalMux disconnecting a non-existing signal";
66 }
67 }
68
69 // Upstream signals
connect(const char * signal,QObject * receiver,const char * slot)70 void SignalMux::connect( const char* signal,
71 QObject* receiver, const char* slot )
72 {
73 Connection new_connection = {
74 nullptr,
75 receiver,
76 signal,
77 slot };
78
79 connectionList_.push_back( new_connection );
80
81 connect( new_connection );
82 }
83
disconnect(const char * signal,QObject * receiver,const char * slot)84 void SignalMux::disconnect( const char *signal,
85 QObject* receiver, const char *slot )
86 {
87 // Find any signal that match our description
88 auto connection = std::find_if(
89 connectionList_.begin(), connectionList_.end(),
90 [receiver, signal, slot]( const Connection& c ) -> bool
91 { return ((QObject*)c.sink == receiver) && (c.source == nullptr) &&
92 (qstrcmp( c.signal, signal) == 0) && (qstrcmp( c.slot, slot) == 0); } );
93
94 if ( connection != connectionList_.end() )
95 {
96 disconnect( *connection );
97
98 connectionList_.erase( connection );
99 }
100 else
101 {
102 LOG( logERROR ) << "SignalMux disconnecting a non-existing signal";
103 }
104 }
105
setCurrentDocument(QObject * current_document)106 void SignalMux::setCurrentDocument( QObject* current_document )
107 {
108 // First disconnect everything to/from the old document
109 for ( auto c: connectionList_ )
110 disconnect( c );
111
112 currentDocument_ = current_document;
113
114 // And now connect to/from the new document
115 for ( auto c: connectionList_ )
116 connect( c );
117
118 // And ask the doc to emit all state signals
119 MuxableDocumentInterface* doc =
120 dynamic_cast<MuxableDocumentInterface*>( current_document );
121 if ( doc )
122 doc->sendAllStateSignals();
123 }
124
125 /*
126 * Private functions
127 */
connect(const Connection & connection)128 void SignalMux::connect( const Connection& connection )
129 {
130 if ( currentDocument_ )
131 {
132 LOG( logDEBUG ) << "SignalMux::connect";
133 if ( connection.source && ( ! connection.sink ) )
134 {
135 // Downstream signal
136 QObject::connect( connection.source, connection.signal,
137 currentDocument_, connection.slot );
138 }
139 else if ( ( ! connection.source ) && connection.sink )
140 {
141 // Upstream signal
142 QObject::connect( currentDocument_, connection.signal,
143 connection.sink, connection.slot );
144 }
145 else
146 {
147 LOG( logERROR ) << "SignalMux has an unexpected signal";
148 }
149 }
150 }
151
disconnect(const Connection & connection)152 void SignalMux::disconnect( const Connection& connection )
153 {
154 if ( currentDocument_ )
155 {
156 LOG( logDEBUG ) << "SignalMux::disconnect";
157 if ( connection.source && ( ! connection.sink ) )
158 {
159 // Downstream signal
160 QObject::disconnect( connection.source, connection.signal,
161 currentDocument_, connection.slot );
162 }
163 else if ( ( ! connection.source ) && connection.sink )
164 {
165 // Upstream signal
166 QObject::disconnect( currentDocument_, connection.signal,
167 connection.sink, connection.slot );
168 }
169 else
170 {
171 LOG( logERROR ) << "SignalMux has an unexpected signal";
172 }
173 }
174 }
175