QTfrontend/ui/widget/chatwidget.cpp
changeset 6222 96d10dcd6d84
parent 6221 f3ac3e51418b
child 6227 ce60b734fff1
equal deleted inserted replaced
6221:f3ac3e51418b 6222:96d10dcd6d84
    21 #include <QTextBrowser>
    21 #include <QTextBrowser>
    22 #include <QLineEdit>
    22 #include <QLineEdit>
    23 #include <QAction>
    23 #include <QAction>
    24 #include <QTextDocument>
    24 #include <QTextDocument>
    25 #include <QFile>
    25 #include <QFile>
       
    26 #include <QList>
    26 #include <QSettings>
    27 #include <QSettings>
    27 #include <QTextStream>
    28 #include <QTextStream>
    28 #include <QMenu>
    29 #include <QMenu>
    29 #include <QCursor>
    30 #include <QCursor>
    30 #include <QScrollBar>
    31 #include <QScrollBar>
   273     connect(chatNicks, SIGNAL(currentRowChanged(int)),
   274     connect(chatNicks, SIGNAL(currentRowChanged(int)),
   274         this, SLOT(chatNickSelected(int)));
   275         this, SLOT(chatNickSelected(int)));
   275 
   276 
   276     mainLayout.addWidget(chatNicks, 0, 1, 3, 1);
   277     mainLayout.addWidget(chatNicks, 0, 1, 3, 1);
   277 
   278 
       
   279     // the userData is used to flag things that are even available when user
       
   280     // is offline
   278     acInfo = new QAction(QAction::tr("Info"), chatNicks);
   281     acInfo = new QAction(QAction::tr("Info"), chatNicks);
   279     acInfo->setIcon(QIcon(":/res/info.png"));
   282     acInfo->setIcon(QIcon(":/res/info.png"));
       
   283     acInfo->setData(QVariant(false));
   280     connect(acInfo, SIGNAL(triggered(bool)), this, SLOT(onInfo()));
   284     connect(acInfo, SIGNAL(triggered(bool)), this, SLOT(onInfo()));
   281     acKick = new QAction(QAction::tr("Kick"), chatNicks);
   285     acKick = new QAction(QAction::tr("Kick"), chatNicks);
   282     acKick->setIcon(QIcon(":/res/kick.png"));
   286     acKick->setIcon(QIcon(":/res/kick.png"));
       
   287     acKick->setData(QVariant(false));
   283     connect(acKick, SIGNAL(triggered(bool)), this, SLOT(onKick()));
   288     connect(acKick, SIGNAL(triggered(bool)), this, SLOT(onKick()));
   284     acBan = new QAction(QAction::tr("Ban"), chatNicks);
   289     acBan = new QAction(QAction::tr("Ban"), chatNicks);
   285     acBan->setIcon(QIcon(":/res/ban.png"));
   290     acBan->setIcon(QIcon(":/res/ban.png"));
       
   291     acBan->setData(QVariant(true));
   286     connect(acBan, SIGNAL(triggered(bool)), this, SLOT(onBan()));
   292     connect(acBan, SIGNAL(triggered(bool)), this, SLOT(onBan()));
   287     acFollow = new QAction(QAction::tr("Follow"), chatNicks);
   293     acFollow = new QAction(QAction::tr("Follow"), chatNicks);
   288     acFollow->setIcon(QIcon(":/res/follow.png"));
   294     acFollow->setIcon(QIcon(":/res/follow.png"));
       
   295     acFollow->setData(QVariant(false));
   289     connect(acFollow, SIGNAL(triggered(bool)), this, SLOT(onFollow()));
   296     connect(acFollow, SIGNAL(triggered(bool)), this, SLOT(onFollow()));
   290     acIgnore = new QAction(QAction::tr("Ignore"), chatNicks);
   297     acIgnore = new QAction(QAction::tr("Ignore"), chatNicks);
   291     acIgnore->setIcon(QIcon(":/res/ignore.png"));
   298     acIgnore->setIcon(QIcon(":/res/ignore.png"));
       
   299     acIgnore->setData(QVariant(true));
   292     connect(acIgnore, SIGNAL(triggered(bool)), this, SLOT(onIgnore()));
   300     connect(acIgnore, SIGNAL(triggered(bool)), this, SLOT(onIgnore()));
   293     acFriend = new QAction(QAction::tr("Add friend"), chatNicks);
   301     acFriend = new QAction(QAction::tr("Add friend"), chatNicks);
   294     acFriend->setIcon(QIcon(":/res/addfriend.png"));
   302     acFriend->setIcon(QIcon(":/res/addfriend.png"));
       
   303     acFriend->setData(QVariant(true));
   295     connect(acFriend, SIGNAL(triggered(bool)), this, SLOT(onFriend()));
   304     connect(acFriend, SIGNAL(triggered(bool)), this, SLOT(onFriend()));
   296 
   305 
   297     chatNicks->insertAction(0, acFriend);
   306     chatNicks->insertAction(0, acFriend);
   298     chatNicks->insertAction(0, acInfo);
   307     chatNicks->insertAction(0, acInfo);
   299     chatNicks->insertAction(0, acIgnore);
   308     chatNicks->insertAction(0, acIgnore);
   311     if (link.scheme() == "http")
   320     if (link.scheme() == "http")
   312         QDesktopServices::openUrl(link);
   321         QDesktopServices::openUrl(link);
   313     if (link.scheme() == "hwnick")
   322     if (link.scheme() == "hwnick")
   314     {
   323     {
   315         // decode nick
   324         // decode nick
   316         const QString& nick = QString::fromUtf8(QByteArray::fromBase64(link.encodedQuery()));
   325         QString nick = QString::fromUtf8(QByteArray::fromBase64(link.encodedQuery()));
   317         QList<QListWidgetItem *> items = chatNicks->findItems(nick, Qt::MatchExactly);
   326         QList<QListWidgetItem *> items = chatNicks->findItems(nick, Qt::MatchExactly);
   318         if (items.size() < 1)
   327 
   319             return;
   328         bool isOffline = (items.size() < 1);
       
   329 
   320         QMenu * popup = new QMenu(this);
   330         QMenu * popup = new QMenu(this);
   321         // selecting an item will automatically scroll there, so let's save old position
   331 
   322         QScrollBar * scrollBar = chatNicks->verticalScrollBar();
   332         if (isOffline)
   323         int oldScrollPos = scrollBar->sliderPosition();
   333         {
   324         // select the nick which we want to see the actions for
   334             m_clickedNick = nick;
   325         chatNicks->setCurrentItem(items[0], QItemSelectionModel::Clear);
   335             chatNickSelected(0); // update friend and ignore entry
   326         // selecting an item will automatically scroll there, so let's save old position
   336             chatNicks->setCurrentItem(NULL, QItemSelectionModel::Clear);
   327         scrollBar->setSliderPosition(oldScrollPos);
   337         }
       
   338         else
       
   339         {
       
   340             // selecting an item will automatically scroll there, so let's save old position
       
   341             QScrollBar * scrollBar = chatNicks->verticalScrollBar();
       
   342             int oldScrollPos = scrollBar->sliderPosition();
       
   343             // select the nick which we want to see the actions for
       
   344             chatNicks->setCurrentItem(items[0], QItemSelectionModel::Clear);
       
   345             // selecting an item will automatically scroll there, so let's save old position
       
   346             scrollBar->setSliderPosition(oldScrollPos);
       
   347         }
       
   348 
   328         // load actions
   349         // load actions
   329         popup->addActions(chatNicks->actions());
   350         QList<QAction *> actions = chatNicks->actions();
       
   351 
       
   352         foreach(QAction * action, actions)
       
   353         {
       
   354             if ((!isOffline) || (action->data().toBool()))
       
   355                 popup->addAction(action);
       
   356         }
       
   357 
   330         // display menu popup at mouse cursor position
   358         // display menu popup at mouse cursor position
   331         popup->popup(QCursor::pos());
   359         popup->popup(QCursor::pos());
   332     }
   360     }
   333 }
   361 }
   334 
   362 
   450             emit chatLine(line);
   478             emit chatLine(line);
   451     }
   479     }
   452     chatEditLine->clear();
   480     chatEditLine->clear();
   453 }
   481 }
   454 
   482 
       
   483 // "link" nick, but before that encode it in base64 to make sure it can't
       
   484 // intefere with html/url syntax the nick is put as querystring as putting
       
   485 // it as host would convert it to it's lower case variant
       
   486 QString HWChatWidget::linkedNick(const QString & nickName)
       
   487 {
       
   488     if (nickName != m_userNick)
       
   489         return QString("<a href=\"hwnick://?%1\" class=\"nick\">%2</a>").arg(
       
   490                     QString(nickName.toUtf8().toBase64())).arg(nickName);
       
   491     else
       
   492         return QString("<span class=\"nick\">%1</span>").arg(nickName);
       
   493 }
       
   494 
   455 
   495 
   456 void HWChatWidget::onChatString(const QString& str)
   496 void HWChatWidget::onChatString(const QString& str)
   457 {
   497 {
   458     onChatString("", str);
   498     onChatString("", str);
   459 }
   499 }
   474 
   514 
   475     QString formattedStr = Qt::escape(str.mid(1));
   515     QString formattedStr = Qt::escape(str.mid(1));
   476     // make hedgewars.org urls actual links
   516     // make hedgewars.org urls actual links
   477     formattedStr = formattedStr.replace(URLREGEXP, "<a href=\"http://\\3\">\\3</a>");
   517     formattedStr = formattedStr.replace(URLREGEXP, "<a href=\"http://\\3\">\\3</a>");
   478 
   518 
   479     // "link" nick, but before that encode it in base64 to make sure it can't intefere with html/url syntax
   519     // link the nick
   480     // the nick is put as querystring as putting it as host would convert it to it's lower case variant
       
   481     if(!nick.isEmpty())
   520     if(!nick.isEmpty())
   482     {
   521         formattedStr.replace("|nick|", linkedNick(nick));
   483         if (nick != m_userNick)
       
   484             formattedStr.replace("|nick|",QString("<a href=\"hwnick://?%1\" class=\"nick\">%2</a>").arg(QString(nick.toUtf8().toBase64())).arg(nick));
       
   485         else
       
   486             formattedStr.replace("|nick|", QString("<span class=\"nick\">%1</span>").arg(nick));
       
   487     }
       
   488 
   522 
   489     QString cssClass("msg_UserChat");
   523     QString cssClass("msg_UserChat");
   490 
   524 
   491     // check first character for color code and set color properly
   525     // check first character for color code and set color properly
   492     char c = str[0].toAscii();
   526     char c = str[0].toAscii();
   677 }
   711 }
   678 
   712 
   679 void HWChatWidget::onIgnore()
   713 void HWChatWidget::onIgnore()
   680 {
   714 {
   681     QListWidgetItem * curritem = chatNicks->currentItem();
   715     QListWidgetItem * curritem = chatNicks->currentItem();
   682     if(!curritem)
   716     QString nick = "";
   683         return;
   717     if(curritem != NULL)
   684 
   718         nick = curritem->text();
   685     if(ignoreList.contains(curritem->text(), Qt::CaseInsensitive)) // already on list - remove him
   719     else
   686     {
   720         nick = m_clickedNick;
   687         ignoreList.removeAll(curritem->text().toLower());
   721 
   688         chatEditLine->addNickname(curritem->text());
   722     if(ignoreList.contains(nick, Qt::CaseInsensitive)) // already on list - remove him
   689         displayNotice(tr("%1 has been removed from your ignore list").arg(curritem->text()));
   723     {
       
   724         ignoreList.removeAll(nick.toLower());
       
   725         chatEditLine->addNickname(nick);
       
   726         displayNotice(tr("%1 has been removed from your ignore list").arg(linkedNick(nick)));
   690     }
   727     }
   691     else // not on list - add
   728     else // not on list - add
   692     {
   729     {
   693         // don't consider ignored people friends
   730         // don't consider ignored people friends
   694         if(friendsList.contains(curritem->text(), Qt::CaseInsensitive))
   731         if(friendsList.contains(nick, Qt::CaseInsensitive))
   695             emit onFriend();
   732             emit onFriend();
   696 
   733 
   697         // scroll down on first ignore added so that people see where that nick went to
   734         // scroll down on first ignore added so that people see where that nick went to
   698         if (ignoreList.isEmpty())
   735         if (ignoreList.isEmpty())
   699             chatNicks->scrollToBottom();
   736             chatNicks->scrollToBottom();
   700 
   737 
   701         ignoreList << curritem->text().toLower();
   738         ignoreList << nick.toLower();
   702         chatEditLine->removeNickname(curritem->text());
   739         chatEditLine->removeNickname(nick);
   703         displayNotice(tr("%1 has been added to your ignore list").arg(curritem->text()));
   740         displayNotice(tr("%1 has been added to your ignore list").arg(linkedNick(nick)));
   704     }
   741     }
   705     updateNickItem(curritem); // update icon/sort order/etc
   742 
   706     chatNicks->sortItems();
   743     if(curritem != NULL)
   707     chatNickSelected(0); // update context menu
   744     {
       
   745         updateNickItem(curritem); // update icon/sort order/etc
       
   746         chatNicks->sortItems();
       
   747         chatNickSelected(0); // update context menu
       
   748     }
   708 }
   749 }
   709 
   750 
   710 void HWChatWidget::onFriend()
   751 void HWChatWidget::onFriend()
   711 {
   752 {
   712     QListWidgetItem * curritem = chatNicks->currentItem();
   753     QListWidgetItem * curritem = chatNicks->currentItem();
   713     if(!curritem)
   754     QString nick = "";
   714         return;
   755     if(curritem != NULL)
   715 
   756         nick = curritem->text();
   716     if(friendsList.contains(curritem->text(), Qt::CaseInsensitive)) // already on list - remove him
   757     else
   717     {
   758         nick = m_clickedNick;
   718         friendsList.removeAll(curritem->text().toLower());
   759 
   719         displayNotice(tr("%1 has been removed from your friends list").arg(curritem->text()));
   760     if(friendsList.contains(nick, Qt::CaseInsensitive)) // already on list - remove him
       
   761     {
       
   762         friendsList.removeAll(nick.toLower());
       
   763         displayNotice(tr("%1 has been removed from your friends list").arg(linkedNick(nick)));
   720     }
   764     }
   721     else // not on list - add
   765     else // not on list - add
   722     {
   766     {
   723         // don't ignore the new friend
   767         // don't ignore the new friend
   724         if(ignoreList.contains(curritem->text(), Qt::CaseInsensitive))
   768         if(ignoreList.contains(nick, Qt::CaseInsensitive))
   725             emit onIgnore();
   769             emit onIgnore();
   726 
   770 
   727         // scroll up on first friend added so that people see where that nick went to
   771         // scroll up on first friend added so that people see where that nick went to
   728         if (friendsList.isEmpty())
   772         if (friendsList.isEmpty())
   729             chatNicks->scrollToTop();
   773             chatNicks->scrollToTop();
   730 
   774 
   731         friendsList << curritem->text().toLower();
   775         friendsList << nick.toLower();
   732         displayNotice(tr("%1 has been added to your friends list").arg(curritem->text()));
   776         displayNotice(tr("%1 has been added to your friends list").arg(linkedNick(nick)));
   733     }
   777     }
   734     updateNickItem(curritem); // update icon/sort order/etc
   778 
   735     chatNicks->sortItems();
   779     if(curritem != NULL)
   736     chatNickSelected(0); // update context menu
   780     {
       
   781         updateNickItem(curritem); // update icon/sort order/etc
       
   782         chatNicks->sortItems();
       
   783         chatNickSelected(0); // update context menu
       
   784     }
   737 }
   785 }
   738 
   786 
   739 void HWChatWidget::chatNickDoubleClicked(QListWidgetItem * item)
   787 void HWChatWidget::chatNickDoubleClicked(QListWidgetItem * item)
   740 {
   788 {
   741     Q_UNUSED(item);
   789     if (item != NULL)
   742 
   790         m_clickedNick = item->text();
       
   791     else
       
   792         m_clickedNick = "";
   743     QList<QAction *> actions = chatNicks->actions();
   793     QList<QAction *> actions = chatNicks->actions();
   744     actions.first()->activate(QAction::Trigger);
   794     actions.first()->activate(QAction::Trigger);
   745 }
   795 }
   746 
   796 
   747 void HWChatWidget::chatNickSelected(int index)
   797 void HWChatWidget::chatNickSelected(int index)
   748 {
   798 {
   749     Q_UNUSED(index);
   799     Q_UNUSED(index);
   750 
   800 
   751     QListWidgetItem* item = chatNicks->currentItem();
   801     QListWidgetItem* item = chatNicks->currentItem();
   752     if (!item)
   802     QString nick = "";
   753         return;
   803     if (item != NULL)
       
   804         nick = item->text();
       
   805     else
       
   806         nick = m_clickedNick;
   754 
   807 
   755     // update context menu labels according to possible action
   808     // update context menu labels according to possible action
   756     if(ignoreList.contains(item->text(), Qt::CaseInsensitive))
   809     if(ignoreList.contains(nick, Qt::CaseInsensitive))
   757     {
   810     {
   758         acIgnore->setText(QAction::tr("Unignore"));
   811         acIgnore->setText(QAction::tr("Unignore"));
   759         acIgnore->setIcon(QIcon(":/res/unignore.png"));
   812         acIgnore->setIcon(QIcon(":/res/unignore.png"));
   760     }
   813     }
   761     else
   814     else
   762     {
   815     {
   763         acIgnore->setText(QAction::tr("Ignore"));
   816         acIgnore->setText(QAction::tr("Ignore"));
   764         acIgnore->setIcon(QIcon(":/res/ignore.png"));
   817         acIgnore->setIcon(QIcon(":/res/ignore.png"));
   765     }
   818     }
   766 
   819 
   767     if(friendsList.contains(item->text(), Qt::CaseInsensitive))
   820     if(friendsList.contains(nick, Qt::CaseInsensitive))
   768     {
   821     {
   769         acFriend->setText(QAction::tr("Remove friend"));
   822         acFriend->setText(QAction::tr("Remove friend"));
   770         acFriend->setIcon(QIcon(":/res/remfriend.png"));
   823         acFriend->setIcon(QIcon(":/res/remfriend.png"));
   771     }
   824     }
   772     else
   825     else