4 * Copyright (C) 2007 Jaroslav Reznik <rezzabuh@gmail.com>
7 #include "sessionview.h"
8 #include "mediaplayer.h"
9 #include "kiconloader.h"
14 //#include "ftstream.h"
15 #include "maknetoview.h"
16 //#include "mucview.h"
20 #include <QtGui/QVBoxLayout>
21 #include <QtGui/QHBoxLayout>
22 #include <QtGui/QPushButton>
23 #include <QtGui/QLabel>
24 #include <QtGui/QTextEdit>
25 #include <QtGui/QSplitter>
26 #include <QtXml/QDomElement>
27 #include <QtCore/QSignalMapper>
28 #include <QtCore/QBuffer>
29 #include <QtCore/QByteArray>
30 #include <QtGui/QFrame>
31 #include <QtCore/QDebug>
32 #include <QtGui/QMessageBox>
33 #include <QtCore/QSettings>
34 #include <QtGui/QGraphicsProxyWidget>
35 #include <QStringList>
36 #include <QToolButton>
37 #include <QGst/Ui/VideoWidget>
39 #include "sessiontabmanager.h"
41 #include "chatinput.h"
42 #include "chatoutput.h"
43 #include "palettewidget.h"
44 #include "plugins/pollplugin.h"
45 #include "wbforeign.h"
47 #include <Phonon/VideoPlayer>
50 #include "call-window.h"
52 SessionView::SessionView(QWidget
*parent
, MaknetoBackend::Session
*session
)
56 m_videoPreviewWindow(NULL
) {
57 qDebug() << "SessionView created";
59 m_makneto
= Makneto::Instance();
60 m_topLayout
= new QVBoxLayout(this);
61 m_topSplitter
= new QSplitter(this);
62 m_topLayout
->addWidget(m_topSplitter
);
63 m_topSplitter
->setOrientation(Qt::Horizontal
);
64 m_leftWidget
= new QWidget(this);
66 m_leftLayout
= new QVBoxLayout(m_leftWidget
);
67 m_leftWidget
->setLayout(m_leftLayout
);
69 m_leftLayout
->setMargin(0);
70 m_leftLayout
->setSpacing(0);
72 // Add Toolbar to the layout
74 QHBoxLayout
*m_toolLayout
= new QHBoxLayout();
75 m_toolLayout
->addWidget(m_wbtoolbar
);
77 // Create WhiteBoard widget
78 m_wbwidget
= new WbWidget("s1", session
->getMyId(), QSize(300, 400), this);
79 // Create palette widget
80 m_paletteWidget
= new PaletteWidget(this);
82 connect(m_paletteWidget
,
83 SIGNAL(fgColorChanged(const QColor
&)),
84 SLOT(fgColorChanged(const QColor
&)));
86 connect(m_paletteWidget
,
87 SIGNAL(bgColorChanged(const QColor
&)),
88 SLOT(bgColorChanged(const QColor
&)));
90 connect(m_paletteWidget
,
91 SIGNAL(penSizeChanged(int)),
92 SLOT(penSizeChanged(int)));
94 m_paletteWidget
->setFgColor(QColor(0, 0, 0));
95 m_paletteWidget
->setBgColor(Qt::transparent
);
96 m_paletteWidget
->setPenSize(1);
97 //end of palette setup
99 m_toolLayout
->addWidget(m_paletteWidget
);
101 //vtheman - add call button
102 QToolButton
*callButton
= new QToolButton(this);
103 callButton
->setIcon(KIcon("makneto-call.png"));
104 callButton
->setIconSize(QSize(32, 32));
105 callButton
->setText("Call");
106 callButton
->setToolTip(QString("Call " + m_session
->getName()));
107 m_toolLayout
->addWidget(callButton
);
108 connect(callButton
, SIGNAL(clicked(bool)),
109 this, SLOT(onCallRequested()));
111 QToolButton
*videoCallButton
= new QToolButton(this);
112 videoCallButton
->setIcon(KIcon("makneto-video-call.png"));
113 videoCallButton
->setIconSize(QSize(32, 32));
114 videoCallButton
->setText("Video Call");
115 videoCallButton
->setToolTip(QString("Video Call " + m_session
->getName()));
116 m_toolLayout
->addWidget(videoCallButton
);
117 connect(videoCallButton
, SIGNAL(clicked(bool)),
118 this, SLOT(onVideoCallRequested()));
121 if (m_session
->isMUC()) {
122 callButton
->setEnabled(false);
123 videoCallButton
->setEnabled(false);
125 //TODO set enabled only if the peer supports voice
127 m_leftLayout
->addLayout(m_toolLayout
);
129 m_leftSplitter
= new QSplitter(Qt::Vertical
, m_leftWidget
);
130 m_leftLayout
->addWidget(m_leftSplitter
);
132 m_leftSplitter
->addWidget(m_wbwidget
);
135 SIGNAL(newWb(QDomElement
)),
136 SLOT(sendWhiteboard(QDomElement
))); //TODO look into this
139 SIGNAL(modeChanged(WbWidget::Mode
)),
140 SLOT(modeChanged(WbWidget::Mode
)));
142 m_wbwidget
->setMode(WbWidget::DrawPath
);
143 m_wbwidget
->setMinimumSize(300, 400);
145 m_chatSplitter
= new QSplitter(Qt::Vertical
, m_leftSplitter
);
147 m_leftSplitter
->addWidget(m_chatSplitter
);
149 m_chatoutput
= new ChatOutput(m_chatSplitter
);
151 m_chatinput
= new ChatInput(m_chatSplitter
);
152 m_sendmsg
= new QPushButton("&Send", m_leftWidget
);
153 connect(m_sendmsg
, SIGNAL(clicked()), this, SLOT(sendClicked()));
154 connect(m_chatinput
, SIGNAL(send()), this, SLOT(sendClicked()));
156 // output chat text edit props
157 m_chatoutput
->setReadOnly(true);
158 // m_chatoutput->setNick(m_session->getName());
160 m_chatSplitter
->addWidget(m_chatoutput
);
161 m_chatSplitter
->addWidget(m_chatinput
);
163 m_leftLayout
->addWidget(m_sendmsg
);
165 m_topSplitter
->addWidget(m_leftWidget
);
167 // TODO: test only!!!
169 m_testbuffer
= new QBuffer(ba
, this);
170 m_testbuffer
->open(QIODevice::ReadWrite
);
173 connect(m_session, SIGNAL(textChatReady(QStringList*)), //deprecated, get rid of
174 this, SLOT(onTextChatReady(QStringList*)));
176 connect(m_session
, SIGNAL(messageReceived(const QString
&, const QString
&)),
177 this, SLOT(onMessageReceived(const QString
&, const QString
&)));
178 connect(m_session
, SIGNAL(incomingCall()),
179 this, SLOT(onIncomingCall()));
180 connect(m_session
, SIGNAL(callReady()),
181 this, SLOT(onCallReady()));
182 connect(m_session
, SIGNAL(incomingFileTransfer(QString
)),
183 this, SLOT(onIncomingFileTransfer(QString
)));
185 connect(m_session
, SIGNAL(videoPreviewAvailable(QGst::ElementPtr
)),
186 this, SLOT(onVideoPreviewAvailable(QGst::ElementPtr
)));
187 connect(m_session
, SIGNAL(videoAvailable(QGst::ElementPtr
)),
188 this, SLOT(onVideoAvailable(QGst::ElementPtr
)));
189 connect(m_session
, SIGNAL(videoPreviewRemoved(QGst::ElementPtr
)),
190 this, SLOT(onVideoPreviewRemoved(QGst::ElementPtr
)));
191 connect(m_session
, SIGNAL(videoRemoved(QGst::ElementPtr
)),
192 this, SLOT(onVideoRemoved(QGst::ElementPtr
)));
199 SessionView::~SessionView() {
200 m_session
->deleteLater();
202 settings
.setValue("m_topSplitter", m_topSplitter
->saveState());
208 void SessionView::createToolBar() {
210 m_wbtoolbar
= new KToolBar(this);
211 m_wbtoolbar
->setIconDimensions(16);
212 m_wbtoolbar
->setToolButtonStyle(Qt::ToolButtonIconOnly
);
214 QActionGroup
*groupMode
= new QActionGroup(this);
215 connect(groupMode
, SIGNAL(triggered(QAction
*)), this, SLOT(setMode(QAction
*)));
217 actionSelect
= new KAction(KIcon("select-rectangular"), i18n("Selection"), groupMode
);
218 m_wbtoolbar
->addAction(actionSelect
);
219 actionSelect
->setData(QVariant(WbWidget::Select
));
221 KAction
*actionTransformMove
= new KAction(KIcon("transform-move"), i18n("Transform - move"), groupMode
);
222 m_wbtoolbar
->addAction(actionTransformMove
);
223 actionTransformMove
->setData(QVariant(WbWidget::Translate
));
225 KAction
*actionRotate
= new KAction(KIcon("transform-rotate"), i18n("Transform - rotate"), groupMode
);
226 m_wbtoolbar
->addAction(actionRotate
);
227 actionRotate
->setData(QVariant(WbWidget::Rotate
));
229 KAction
*actionScale
= new KAction(KIcon("zoom-fit-best"), i18n("Transform - scale"), groupMode
);
230 m_wbtoolbar
->addAction(actionScale
);
231 actionScale
->setData(QVariant(WbWidget::Scale
));
233 KAction
*actionErase
= new KAction(KIcon("draw-eraser"), i18n("Erase"), groupMode
);
234 m_wbtoolbar
->addAction(actionErase
);
235 actionErase
->setData(QVariant(WbWidget::Erase
));
237 KAction
*actionPencil
= new KAction(KIcon("draw-freehand"), i18n("Freehand"), groupMode
);
238 m_wbtoolbar
->addAction(actionPencil
);
239 actionPencil
->setData(QVariant(WbWidget::DrawPath
));
241 KAction
*actionLine
= new KAction(KIcon("draw-line"), i18n("Line"), groupMode
);
242 m_wbtoolbar
->addAction(actionLine
);
243 actionLine
->setData(QVariant(WbWidget::DrawLine
));
245 KAction
*actionRectangle
= new KAction(KIcon("draw-rectangle"), i18n("Rectangle"), groupMode
);
246 m_wbtoolbar
->addAction(actionRectangle
);
247 actionRectangle
->setData(QVariant(WbWidget::DrawRectangle
));
249 KAction
*actionEllipse
= new KAction(KIcon("draw-ellipse"), i18n("Ellipse"), groupMode
);
250 m_wbtoolbar
->addAction(actionEllipse
);
251 actionEllipse
->setData(QVariant(WbWidget::DrawEllipse
));
253 KAction
*actionCircle
= new KAction(KIcon("draw-circle"), i18n("Circle"), groupMode
);
254 m_wbtoolbar
->addAction(actionCircle
);
255 actionCircle
->setData(QVariant(WbWidget::DrawCircle
));
257 // KAction *actionPolyline = new KAction(KIcon("draw-polyline"), i18n("Polyline"), groupMode);
258 // m_wbtoolbar->addAction(actionPolyline);
259 // actionPolyline->setData(QVariant(WbWidget::DrawPolyline));
261 KAction
*actionText
= new KAction(KIcon("insert-text"), i18n("Text"), groupMode
);
262 m_wbtoolbar
->addAction(actionText
);
263 actionText
->setData(QVariant(WbWidget::DrawText
));
264 actionText
->setCheckable(true);
266 KAction
*actionImage
= new KAction(KIcon("insert-image"), i18n("Image"), groupMode
);
267 m_wbtoolbar
->addAction(actionImage
);
268 actionImage
->setData(QVariant(WbWidget::DrawImage
));
270 KAction
*actionSendFile
= new KAction(KIcon("mail-send"), i18n("Send file"), this);
271 m_wbtoolbar
->addAction(actionSendFile
);
272 connect(actionSendFile
, SIGNAL(triggered()), this, SLOT(actionSendFileTriggered()));
274 KAction
*actionPoll
= new KAction(KIcon("maknetopoll"), i18n("Create poll"), this);
275 m_wbtoolbar
->addAction(actionPoll
);
276 connect(actionPoll
, SIGNAL(triggered()), this, SLOT(actionCreatePollTriggered()));
286 void SessionView::sendClicked() {
287 QString text
= m_chatinput
->toPlainText();
288 if (text
== QString())
291 //TODO figure out how to treat MUC
292 //can be used as a slot
293 m_session
->sendMessage(text
);
295 //TODO Show message in chat window only in chat, not in groupchat
296 m_chatoutput
->myMessage(text
);
297 m_chatinput
->setText("");
301 //will be deleted soon
304 void SessionView::onTextChatReady(QStringList* messages) {
305 qDebug() << "SessionView: Text chat is ready";
307 foreach(QString message, *messages) {
308 //m_chatoutput->incomingMessage(message);
312 void SessionView::onMessageReceived(const QString
& text
, const QString
&contact
) {
314 doc
.setContent(text
);
315 //QDomElement e = doc.elementsByTagNameNS("http://jabber.org/protocol/svgwb", "wb").item(0).toElement();
316 QDomElement e
= doc
.elementsByTagName("wb").item(0).toElement();
318 m_wbwidget
->processWb(e
);
320 //TODO figure out what to do in case of MUC
321 m_chatoutput
->incomingMessage(text
, contact
);
326 //TODO set resource Makneto and disable the wbwidget if peer does not have makneto
328 void SessionView::sendWhiteboard(const QDomElement
&wb
) {
331 QTextStream
ts(&message
);
333 //qDebug() << "wb:" << endl << message << endl << endl;
334 //TODO check the resource
335 m_session
->sendMessage(ts
.readAll());
338 //this is the same and onCallReady and essentially might be blended into
339 //one. The session object offers two signals, one for when the user with
340 //an existing session requests an audio call, and second for when the peer
341 //requests a call and in GUI there might popup a dialog asking if the user
342 //wishes to accept the call.
344 void SessionView::onIncomingCall() {
345 qDebug() << "SessionView: Incoming call";
346 if (acceptCallQuery()) {
347 m_callWindow
= new CallWindow(m_session
, this);
348 m_callWindow
->show();
350 m_session
->rejectCall();
354 void SessionView::onCallReady() {
355 qDebug() << "SessionView: Call Ready";
356 m_callWindow
= new CallWindow(m_session
, this);
357 m_callWindow
->show();
360 void SessionView::onCallRequested() {
361 qDebug() << "SessionView: Call requested";
362 m_session
->startMediaCall(false);
365 void SessionView::onVideoCallRequested() {
366 qDebug() << "SessionView: Video Call requested";
367 m_session
->startMediaCall(true);
370 bool SessionView::acceptCallQuery() {
371 // FIXME: SessionType flags is not setup yet!
372 QString type
= (m_session
->getSessionType().testFlag(MaknetoBackend::Session::SessionTypeVideo
) ? "Video" : "Audio");
373 qDebug() << "SessionView: query for " + type
+ " call";
374 if (QMessageBox::question(this, "Makneto", QString("Incoming " + type
+ " Call from " + m_session
->getName() + ".\nAccept?"),
375 QMessageBox::Yes
| QMessageBox::No
)
376 == QMessageBox::Yes
) {
384 void SessionView::onVideoPreviewAvailable(QGst::ElementPtr videoOutElemPtr
) {
385 _videoPreviewWidget
= new QGst::Ui::VideoWidget
;
386 _videoPreviewWidget
.data()->setVideoSink(videoOutElemPtr
);
388 if (m_videoPreviewWindow
) {
389 qWarning() << "video preview window is already opened!";
393 m_videoPreviewWindow
= new QMainWindow();
394 m_videoPreviewWindow
->setWindowTitle("You");
395 m_videoPreviewWindow
->setCentralWidget(_videoPreviewWidget
.data());
396 m_videoPreviewWindow
->show();
399 void SessionView::onVideoAvailable(QGst::ElementPtr videoOutElemPtr
) {
401 _videoWidget
= new QGst::Ui::VideoWidget
;
402 _videoWidget
.data()->setVideoSink(videoOutElemPtr
);
405 qWarning() << "video window is already opened!";
409 m_videoWindow
= new QMainWindow();
410 m_videoWindow
->setWindowTitle("Video of " + sessionId());
411 m_videoWindow
->setCentralWidget(_videoWidget
.data());
412 m_videoWindow
->show();
415 void SessionView::onVideoPreviewRemoved(QGst::ElementPtr videoOutElemPtr
) {
416 if (!m_videoPreviewWindow
)
419 m_videoPreviewWindow
->hide();
420 m_videoPreviewWindow
->deleteLater();
421 m_videoPreviewWindow
= NULL
;
422 _videoPreviewWidget
.clear();
425 void SessionView::onVideoRemoved(QGst::ElementPtr videoOutElemPtr
) {
429 m_videoWindow
->hide();
430 m_videoWindow
->deleteLater();
431 m_videoWindow
= NULL
;
432 _videoWidget
.clear();
435 //FIXME This has to be adapted to Tp!!!!
438 void SessionView::fileTransfer(FileTransfer *ft)
440 FileTransfer *transfer = ft;
444 text = "<b>" + transfer->peer().bare()+"</b> Incoming file '" + transfer->fileName() +"'";
446 m_chatoutput->incomingMessage(text);
448 connect(transfer, SIGNAL(readyRead(const QByteArray &)), this, SLOT(transferRead(const QByteArray &)));
452 m_ftstream = new FTStream(m_testbuffer, transfer->fileSize(), this);
454 mediap = new MediaPlayer(this);
456 mediap->setCurrentSource(m_ftstream);
458 //mediap->setBuffer(m_testbuffer);
461 //player->load(m_testbuffer);
468 void SessionView::infoMessage(const QString
&text
) {
469 m_chatoutput
->infoMessage(text
);
474 void SessionView::showHideChat() {
475 QList
<int> l
= m_leftSplitter
->sizes();
478 l
[1] = settings
.value("m_leftSplitter_size").toInt();
481 settings
.setValue("m_leftSplitter_size", l
[1]);
484 m_leftSplitter
->setSizes(l
);
487 bool SessionView::closeRequest() {
488 //TODO create const char* for the message
489 if (QMessageBox::question(this, "Makneto",
490 tr("Do you really want to close the tab?"),
491 QMessageBox::Yes
| QMessageBox::No
) == QMessageBox::Yes
) {
492 //FIXME m_session->leaveGroupChat
500 void SessionView::modeChanged(WbWidget::Mode mode
) {
502 case WbWidget::Select
:
503 actionSelect
->setChecked(true);
505 case WbWidget::DrawText
:
506 //actionDrawText->setChecked(true);
516 void SessionView::transferRead(const QByteArray &a)
519 // std::cout << "a.size=" << a.size() << std::endl;
520 bytes=bytes+a.size();
522 // std::cout << "written=" << m_testbuffer->write(a.data()) << std::endl;
523 // m_testbuffer->waitForBytesWritten(1000);
524 // std::cout << "buffer.size()=" << m_testbuffer->size() << std::endl;
525 // std::cout << "bytes=" << bytes << std::endl;
526 // std::cout << "ba.size()=" << ba->size() << std::endl;
528 // if (bytes==183173120)
530 // m_testbuffer->open(QIODevice::ReadOnly);
531 // //m_testbuffer->seek(0);
532 // mediap->setCurrentSource(m_testbuffer);
537 mediap->setCurrentSource(m_ftstream);
543 //TODO if there is time, implement
545 void SessionView::actionSendFileTriggered() {
546 QString fileName
= QFileDialog::getOpenFileName(this, tr("Choose file to send"));
547 qDebug() << "SessionView: File to send: " << fileName
;
548 m_session
->startFileTransfer(fileName
);
551 void SessionView::onIncomingFileTransfer(const QString
& filename
) {
552 if (QMessageBox::question(this,
554 QString("Incoming file transfer from " + m_session
->getName() + ".\nFile: " + filename
+ "\nAccept?"),
555 QMessageBox::Yes
| QMessageBox::No
) == QMessageBox::Yes
) {
556 QString localFileName
= QFileDialog::getSaveFileName(this, tr("Save file"));
557 m_session
->onAcceptFileTransfer(true, localFileName
);
559 m_session
->onAcceptFileTransfer(false);
568 void SessionView::setEnabled(bool enabled
) {
569 m_sendmsg
->setEnabled(enabled
);
575 void SessionView::setMode(QAction
*action
) {
576 m_wbwidget
->setMode(WbWidget::Mode(action
->data().toInt()));
577 // If user selects freehand pen, we should disable the brush
578 if (WbWidget::Mode(action
->data().toInt()) == WbWidget::DrawPath
)
579 m_wbwidget
->setFillColor(Qt::transparent
);
581 m_wbwidget
->setFillColor(m_paletteWidget
->bgColor());
587 void SessionView::fgColorChanged(const QColor
&c
) {
588 m_wbwidget
->setStrokeColor(c
);
594 void SessionView::bgColorChanged(const QColor
&c
) {
595 m_wbwidget
->setFillColor(c
);
600 void SessionView::penSizeChanged(int size
) {
601 m_wbwidget
->setStrokeWidth(size
);
607 void SessionView::actionCreatePollTriggered() {
609 PollPlugin
*plugin
= new PollPlugin();
610 if (!plugin
->getQuestions())
613 WbForeign
*wbf
= new WbForeign(plugin
, dom
, m_wbwidget
->scene
->newId(), m_wbwidget
->scene
->newIndex(), QString("root"), static_cast<QGraphicsScene
*> (m_wbwidget
->scene
));
614 //scene->update(wbf->graphicsItem()->boundingRect());
615 m_wbwidget
->scene
->queueNew(wbf
->id(), wbf
->index(), wbf
->svg());
616 m_wbwidget
->scene
->addWbItem(wbf
);
617 plugin
->graphicsItem()->ensureVisible(QRectF(), 0, 0);
618 setMode(actionSelect
);
619 actionSelect
->setChecked(true);