Ok, the long awaited config wizard is here (at least in a very basic state). There...
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / core / qxtpipe.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtCore module of the Qt eXTension library
6 **
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
9 ** IBM.
10 **
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
15 **
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24
25 #include "qxtpipe.h"
26 #include <QList>
27 #include <QQueue>
28 #include <QMutableListIterator>
29
30 /**
31  * \class  QxtPipe QxtPipe
32  * \ingroup QxtCore
33  * \brief a pipeable QIODevice
34  *
35  * pipes can be connected to other pipes, to exchange data \n
36  * The default implementation uses a buffer. \n
37  * Reimplement to make your custom class able to be connected into a pipe chain. \n
38  *
39  * Example usage:
40  * \code
41  * QxtPipe p1;
42  * QxtPipe p2;
43  * p1|p2;
44  * p1.write("hello world");
45  * qDebug()<<p2.readAll();
46  * \endcode
47 */
48
49
50 struct Connection
51 {
52     QxtPipe * pipe;
53     QIODevice::OpenMode mode;
54     Qt::ConnectionType connectionType;
55 };
56
57 class QxtPipePrivate:public QxtPrivate<QxtPipe>
58 {
59     public:
60         QQueue<char> q;
61         QList<Connection> connections;
62 };
63
64 /**
65  * Contructs a new QxtPipe.
66  */
67 QxtPipe::QxtPipe(QObject * parent):QIODevice(parent)
68 {
69     setOpenMode (QIODevice::ReadWrite);
70 }
71
72
73 /** reimplemented from QIODevice*/
74 bool QxtPipe::isSequential () const
75 {
76     return true;
77 }
78
79 /** reimplemented from QIODevice*/
80 qint64 QxtPipe::bytesAvailable () const
81 {
82     return qxt_d().q.count();
83 }
84
85 /**
86  * pipes the output of this instance to the \p other  QxtPipe using the given mode and connectiontype \n
87  * connection pipes with this function can be considered thread safe \n
88  *
89  * Example usage:
90  * \code
91     QxtPipe p1;
92     QxtPipe p2;
93     p1.connect(&p2,QIODevice::ReadOnly);
94
95     ///this data will go nowhere. p2 is connected to p1, but not p2 to p1.
96     p1.write("hello");
97
98     ///while this data will end up in p1
99     p2.write("world");
100
101     qDebug()<<p1.readAll();
102
103  * \endcode
104
105  */
106 bool  QxtPipe::connect   (QxtPipe * other ,QIODevice::OpenMode mode,Qt::ConnectionType connectionType)
107 {
108
109     ///tell the other pipe to write into this
110     if(mode & QIODevice::ReadOnly)
111     {
112         other->connect(this,QIODevice::WriteOnly,connectionType);
113     }
114
115
116     Connection c;
117     c.pipe=other;
118     c.mode=mode;
119     c.connectionType=connectionType;
120     qxt_d().connections.append(c);
121
122     return true;
123 }
124
125 /**
126  * cuts the pipe to the \p other QxtPipe
127  */
128 bool QxtPipe::disconnect (QxtPipe * other )
129 {
130     bool e=false;
131
132     QMutableListIterator<Connection> i(qxt_d().connections);
133     while (i.hasNext())
134     {
135         i.next();
136         if(i.value().pipe==other)
137         {
138             i.remove();
139             e=true;
140             other->disconnect(this);
141         }
142     }
143
144     return e;
145 }
146
147 /**
148  * convinence function for QxtPipe::connect.
149  * pipes the output of this instance to the \p other  QxtPipe in readwrite mode with autoconnection
150  */
151 QxtPipe & QxtPipe::operator | ( QxtPipe & target)
152 {
153     connect(&target);
154     return *this;
155 }
156
157 /** reimplemented from QIODevice*/
158 qint64 QxtPipe::readData ( char * data, qint64 maxSize )
159 {
160     QQueue<char> * q=&qxt_d().q;
161
162     qint64 i=0;
163     for (;i<maxSize;i++)
164     {
165         if (q->isEmpty())
166             break;
167         (*data++)=q->dequeue();
168     }
169     return i;
170 }
171
172 /** reimplemented from QIODevice*/
173 qint64 QxtPipe::writeData ( const char * data, qint64 maxSize )
174 {
175     foreach(Connection c,qxt_d().connections)
176     {
177
178         if(!(c.mode & QIODevice::WriteOnly))
179             continue;
180
181         //we want thread safety, so we use a QByteArray instead of the raw data. that migth be slow
182         QMetaObject::invokeMethod(c.pipe, "receiveData",c.connectionType,
183             Q_ARG(QByteArray, data),Q_ARG(QxtPipe *,this));
184             
185     }
186     return maxSize;
187 }
188
189
190 /** 
191 receiveData is called from any connected pipe to input data into this instance.
192 */
193 qint64 QxtPipe::receiveData (QByteArray datab ,QxtPipe * sender)
194 {
195     QQueue<char> * q=&qxt_d().q;
196
197     const char * data =datab.constData();
198     qint64 maxSize =datab.size();
199
200     qint64 i=0;
201     for (;i<maxSize;i++)
202         q->enqueue(*data++);
203
204
205     foreach(Connection c,qxt_d().connections)
206     {
207
208         //don't write back to sender
209         if(c.pipe==sender)
210              continue;
211
212         if(!(c.mode & QIODevice::WriteOnly))
213             continue;
214
215
216         QMetaObject::invokeMethod(c.pipe, "receiveData",c.connectionType,
217             Q_ARG(QByteArray, datab),Q_ARG(QxtPipe *,this));
218     }
219
220
221     if (i>0)
222         emit(readyRead ());
223
224     return maxSize;
225 }
226