some UI changes for usability
[makneto-zunavac1.git] / src / ui-kde / sessionview.cpp
blobdb39a70a77eb393ca1ddc130b52c60c5daf4e91d
1 /*
2 * sessionview.cpp
4 * Copyright (C) 2007 Jaroslav Reznik <rezzabuh@gmail.com>
5 */
7 #include "sessionview.h"
8 #include "mediaplayer.h"
9 #include "kiconloader.h"
10 #include "klocale.h"
11 #include "wbwidget.h"
12 #include "ktoolbar.h"
13 #include "kaction.h"
14 //#include "ftstream.h"
15 #include "maknetoview.h"
16 //#include "mucview.h"
18 #include <iostream>
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"
40 #include "makneto.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>
49 //vtheman
50 #include "call-window.h"
52 SessionView::SessionView(QWidget *parent, MaknetoBackend::Session *session)
53 : QWidget(parent),
54 m_session(session),
55 m_videoWindow(NULL),
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
73 createToolBar();
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);
134 connect(m_wbwidget,
135 SIGNAL(newWb(QDomElement)),
136 SLOT(sendWhiteboard(QDomElement))); //TODO look into this
138 connect(m_wbwidget,
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!!!
168 ba = new QByteArray;
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)));
197 //IS OK
199 SessionView::~SessionView() {
200 m_session->deleteLater();
201 QSettings settings;
202 settings.setValue("m_topSplitter", m_topSplitter->saveState());
206 //IS OK
208 void SessionView::createToolBar() {
209 // wb toolbar
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()));
284 //VTHEMAN
286 void SessionView::sendClicked() {
287 QString text = m_chatinput->toPlainText();
288 if (text == QString())
289 return;
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) {
313 QDomDocument doc;
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();
317 if (!e.isNull())
318 m_wbwidget->processWb(e);
319 else {
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) {
329 QString message;
331 QTextStream ts(&message);
332 wb.save(ts, 0);
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();
349 } else {
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) {
377 return true;
378 } else
379 return false;
381 return true;
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!";
390 return;
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);
404 if (m_videoWindow) {
405 qWarning() << "video window is already opened!";
406 return;
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)
417 return;
419 m_videoPreviewWindow->hide();
420 m_videoPreviewWindow->deleteLater();
421 m_videoPreviewWindow = NULL;
422 _videoPreviewWidget.clear();
425 void SessionView::onVideoRemoved(QGst::ElementPtr videoOutElemPtr) {
426 if (!m_videoWindow)
427 return;
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;
442 QString text;
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 &)));
450 transfer->accept();
452 m_ftstream = new FTStream(m_testbuffer, transfer->fileSize(), this);
454 mediap = new MediaPlayer(this);
455 mediap->show();
456 mediap->setCurrentSource(m_ftstream);
458 //mediap->setBuffer(m_testbuffer);
460 bytes = 0;
461 //player->load(m_testbuffer);
462 //player->play();
468 void SessionView::infoMessage(const QString &text) {
469 m_chatoutput->infoMessage(text);
472 //IS OK
474 void SessionView::showHideChat() {
475 QList<int> l = m_leftSplitter->sizes();
476 if (l[1] == 0) {
477 QSettings settings;
478 l[1] = settings.value("m_leftSplitter_size").toInt();
479 } else {
480 QSettings settings;
481 settings.setValue("m_leftSplitter_size", l[1]);
482 l[1] = 0;
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
493 return true;
494 } else {
495 return false;
497 return true;
500 void SessionView::modeChanged(WbWidget::Mode mode) {
501 switch (mode) {
502 case WbWidget::Select:
503 actionSelect->setChecked(true);
504 break;
505 case WbWidget::DrawText:
506 //actionDrawText->setChecked(true);
507 break;
508 default:
509 break;
514 //FIXME adapt to Tp
516 void SessionView::transferRead(const QByteArray &a)
518 ba->append(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)
529 // {
530 // m_testbuffer->open(QIODevice::ReadOnly);
531 // //m_testbuffer->seek(0);
532 // mediap->setCurrentSource(m_testbuffer);
533 // mediap->show();
534 // }
536 if (bytes==4456448)
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,
553 "Makneto",
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);
558 } else {
559 m_session->onAcceptFileTransfer(false);
566 //IS OK
568 void SessionView::setEnabled(bool enabled) {
569 m_sendmsg->setEnabled(enabled);
573 //IS OK
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);
580 else
581 m_wbwidget->setFillColor(m_paletteWidget->bgColor());
585 //IS OK
587 void SessionView::fgColorChanged(const QColor &c) {
588 m_wbwidget->setStrokeColor(c);
592 //IS OK
594 void SessionView::bgColorChanged(const QColor &c) {
595 m_wbwidget->setFillColor(c);
598 //IS OK
600 void SessionView::penSizeChanged(int size) {
601 m_wbwidget->setStrokeWidth(size);
605 //Seems to be ok
607 void SessionView::actionCreatePollTriggered() {
608 QDomElement dom;
609 PollPlugin *plugin = new PollPlugin();
610 if (!plugin->getQuestions())
611 return;
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);