PageRenderTime 30ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/src/schat/schatwindow.cpp

http://schat.googlecode.com/
C++ | 1555 lines | 1206 code | 181 blank | 168 comment | 180 complexity | 799cf60895fad41183173adf06fedb77 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. /* $Id: schatwindow.cpp 3267 2012-11-05 11:55:42Z IMPOMEZIA $
  2. * IMPOMEZIA Simple Chat
  3. * Copyright Š 2008-2011 IMPOMEZIA <schat@impomezia.com>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <QDesktopServices>
  19. #include <QDesktopWidget>
  20. #include <QKeyEvent>
  21. #include <QMenuBar>
  22. #include <QProcess>
  23. #include <QToolBar>
  24. #include <QToolButton>
  25. #include <QVBoxLayout>
  26. #include "3rdparty/qtwin.h"
  27. #include "aboutdialog.h"
  28. #include "abstractprofile.h"
  29. #include "channellog.h"
  30. #include "chatwindow/chatview.h"
  31. #include "clientservice.h"
  32. #include "mainchannel.h"
  33. #include "popup/popupmanager.h"
  34. #include "privatetab.h"
  35. #include "schatwindow.h"
  36. #include "schatwindow_p.h"
  37. #include "settings.h"
  38. #include "settingsdialog.h"
  39. #include "simplechatapp.h"
  40. #include "soundaction.h"
  41. #include "text/PlainTextFilter.h"
  42. #include "trayicon.h"
  43. #include "widget/connectionstatus.h"
  44. #include "widget/sendwidget.h"
  45. #include "widget/statusmenu.h"
  46. #include "widget/userview.h"
  47. #if defined(Q_WS_WIN)
  48. #include <qt_windows.h>
  49. #define WM_DWMCOMPOSITIONCHANGED 0x031E // Composition changed window message
  50. #endif
  51. QMap<QString, QString> SChatWindowPrivate::cmds;
  52. /*!
  53. * \brief ??????????? ?????? SChatWindowPrivate.
  54. */
  55. SChatWindowPrivate::SChatWindowPrivate(SChatWindow *parent)
  56. : motd(true),
  57. q(parent),
  58. send(0)
  59. {
  60. }
  61. SChatWindowPrivate::~SChatWindowPrivate()
  62. {
  63. }
  64. /*!
  65. * ????????? ??????.
  66. */
  67. bool SChatWindowPrivate::parseCmd(AbstractTab *tab, const QString &message)
  68. {
  69. QString text = PlainTextFilter::filter(message);
  70. QString textFull = text;
  71. text = text.toLower();
  72. /// /away
  73. if (text == "/away") {
  74. if (profile->status() == schat::StatusAway)
  75. sendStatus(schat::StatusNormal);
  76. else
  77. sendStatus(schat::StatusAway);
  78. }
  79. /// /bye
  80. else if (text == "/bye") {
  81. clientService->quit();
  82. }
  83. else if (text.startsWith("/bye ")) {
  84. clientService->sendByeMsg(textFull.mid(textFull.indexOf(QChar(' '))));
  85. clientService->quit();
  86. }
  87. /// /clear
  88. else if (text == "/clear") {
  89. tab->clear();
  90. }
  91. else if (text == "/dnd") {
  92. if (profile->status() == schat::StatusDnD)
  93. sendStatus(schat::StatusNormal);
  94. else
  95. sendStatus(schat::StatusDnD);
  96. }
  97. /// /exit
  98. else if (text == "/exit" || text == "/quit") {
  99. closeChat();
  100. }
  101. else if (text.startsWith("/google ")) {
  102. QString query = textFull.mid(textFull.indexOf(' ')).simplified().left(1000);
  103. sendMsg("<b style='color:#0039b6'>G</b><b style='color:#c41200'>o</b>"
  104. "<b style='color:#f3c518'>o</b><b style='color:#0039b6'>g</b>"
  105. "<b style='color:#30a72f'>l</b><b style='color:#c41200'>e</b>: "
  106. "<b><a href='http://www.google.com/search?q=" + QUrl::toPercentEncoding(query)
  107. + "'>" + Qt::escape(query) + "</a></b>", false);
  108. }
  109. /// /help
  110. else if (text == "/help") {
  111. cmdHelp(tab, "");
  112. }
  113. else if (text.startsWith("/help ")) {
  114. cmdHelp(tab, textFull.mid(textFull.indexOf(' ')).trimmed());
  115. }
  116. /// /log
  117. else if (text == "/log") {
  118. QDesktopServices::openUrl(QUrl::fromLocalFile(SimpleSettings->path(Settings::LogPath).at(0)));
  119. }
  120. /// /nick
  121. else if (text.startsWith("/nick ")) {
  122. QString newNick = textFull.mid(textFull.indexOf(' '));
  123. if (AbstractProfile::isValidNick(newNick) && profile->nick() != newNick) {
  124. profile->setNick(newNick);
  125. clientService->sendNewProfile();
  126. }
  127. }
  128. else if (text == "/ping") {
  129. pingTime.start();
  130. return false;
  131. }
  132. else
  133. return false;
  134. send->clear();
  135. return true;
  136. }
  137. /*!
  138. * ????????? ????????????? ????? ??? ???????? ???????.
  139. */
  140. bool SChatWindowPrivate::sendStatus(quint32 status)
  141. {
  142. if (clientService->isReady())
  143. return clientService->sendUniversal(schat::UniStatus, QList<quint32>() << status, QStringList());
  144. else {
  145. profile->setStatus(status);
  146. return true;
  147. }
  148. }
  149. /*!
  150. * ??? ????????????? ???????? ??????????? ? ????? ?????????.
  151. * ???????? ??????????? ???????????, ???? ????? ??????? ??????? ?? ????? ?????? ???????
  152. * ? ???????????? ??? ???? ???? ?????????.
  153. *
  154. * ??????? ?????????? ??? ????????? ?????? ????????? ? ??????? ?????? ??? ??? ????????? ?????????.
  155. *
  156. * \param index ????? ???????, ? ??????? ???? ????? ?????????.
  157. * \param key ???? ??? ????????? ???????????.
  158. *
  159. * \return \a true ???? ???????? ??????????? ???????.
  160. */
  161. bool SChatWindowPrivate::startNotice(int index, const QString &key)
  162. {
  163. if (index == -1)
  164. return false;
  165. bool notice = (tabs->currentIndex() != index || !q->isActiveChatWindow());
  166. if ((notice || pref->getBool("Sound/AlwaysPlay")) && !soundAction->isMute())
  167. tray->playSound(key, true);
  168. if (notice) {
  169. AbstractTab *tab = static_cast<AbstractTab *>(tabs->widget(index));
  170. if (!tab->notice()) {
  171. tab->notice(true);
  172. tabs->setTabIcon(index, QIcon(":/images/balloon.png"));
  173. tray->notice(true);
  174. }
  175. return true;
  176. }
  177. return false;
  178. }
  179. /*!
  180. * ?????????? ?????????? ?????????.
  181. */
  182. QString SChatWindowPrivate::channel()
  183. {
  184. AbstractTab *tab = static_cast<AbstractTab *>(tabs->currentWidget());
  185. if (tab->type() == AbstractTab::Private)
  186. return tabs->tabText(tabs->currentIndex());
  187. else
  188. return "";
  189. }
  190. QString SChatWindowPrivate::colorizedPing() const
  191. {
  192. int ms = pingTime.elapsed();
  193. #ifdef Q_WS_WIN
  194. if (ms == 0)
  195. ms = 8;
  196. #endif
  197. QString color = "6bb521";
  198. if (ms > 200 && ms < 500)
  199. color = "ff9900";
  200. else if (ms >= 500)
  201. color = "da251d";
  202. return SChatWindow::tr("Ping to server") + " <b style='color:#" + color + ";'>" + QString::number(ms) + SChatWindow::tr(" ms") + "</b>";
  203. }
  204. /*!
  205. * ?????????? ????????? ?? ????????.
  206. */
  207. void SChatWindowPrivate::cmdHelp(AbstractTab *tab, const QString &cmd)
  208. {
  209. if (cmds.isEmpty()) {
  210. cmds.insert("all", SChatWindow::tr("Personal message to all users."));
  211. cmds.insert("away", SChatWindow::tr("turns on/off <b>Away</b> status."));
  212. cmds.insert("bye", SChatWindow::tr("disconnects from server/network, optionally an alternative quit message can be set."));
  213. cmds.insert("clear", SChatWindow::tr("chat window clearing."));
  214. cmds.insert("dnd", SChatWindow::tr("turns on/off <b>Do Not Disturb</b> status."));
  215. cmds.insert("exit", SChatWindow::tr("exit from chat."));
  216. cmds.insert("google", SChatWindow::tr("forms the link with a given text for search in Google."));
  217. cmds.insert("help", SChatWindow::tr("displays command tip."));
  218. cmds.insert("log", SChatWindow::tr("opens folder with chat logs."));
  219. cmds.insert("me", SChatWindow::tr("about yourself in the third person, e.g. about what you’re doing now."));
  220. cmds.insert("motd", SChatWindow::tr("display of <i>Message Of The Day</i> server message."));
  221. cmds.insert("nick", SChatWindow::tr("allows to set a new nickname."));
  222. cmds.insert("ping", SChatWindow::tr("calculate time of delay to server."));
  223. cmds.insert("server", SChatWindow::tr("view server information."));
  224. }
  225. if (cmd.isEmpty()) {
  226. QString out = "<b class='info'>" + SChatWindow::tr("Available commands:") + "</b><br />";
  227. QMapIterator<QString, QString> i(cmds);
  228. while (i.hasNext()) {
  229. i.next();
  230. out += ("<b class='info'>/" + i.key() + "</b> — " + i.value() + "<br />");
  231. }
  232. tab->msg(out);
  233. return;
  234. }
  235. QString command = cmd.toLower();
  236. if (command.startsWith('/')) {
  237. command = command.mid(1);
  238. }
  239. if (cmds.contains(command)) {
  240. tab->msg("<b class='info'>/" + command + "</b> — " + cmds.value(command));
  241. }
  242. else
  243. tab->msg("<span class='statusUnknownCmd'>" + SChatWindow::tr("Unknown command: <b>%1</b>").arg(command) + "</span>");
  244. }
  245. /*!
  246. * ?????????? ?????? ?????????.
  247. */
  248. void SChatWindowPrivate::closeChat(bool update)
  249. {
  250. #ifdef SCHAT_NO_UPDATE
  251. Q_UNUSED(update)
  252. #endif
  253. profile->setNick(clientService->safeNick());
  254. clientService->quit();
  255. saveGeometry();
  256. pref->write();
  257. #ifndef SCHAT_NO_UPDATE
  258. if (update)
  259. Settings::install();
  260. #endif
  261. QApplication::quit();
  262. }
  263. void SChatWindowPrivate::createStatusBar()
  264. {
  265. statusMenu = new StatusMenu(profile->isMale(), q);
  266. connectionStatus = new ConnectionStatus(statusMenu, q);
  267. q->setStatusBar(connectionStatus);
  268. }
  269. /*!
  270. * ?????????????? ????????? ?????????? ????.
  271. *
  272. * \note ??? Windows Mobile ?? ?????????? ???????? ???? ????,
  273. * ?????? ????? ????????? ???? ??????????.
  274. */
  275. void SChatWindowPrivate::createTrayIcon()
  276. {
  277. #ifndef Q_OS_WINCE
  278. QMenu *menu = new QMenu(q);
  279. #else
  280. QMenuBar *menu = q->menuBar();
  281. #endif
  282. menu->addAction(send->aboutAction());
  283. menu->addAction(settingsAction);
  284. statusAction = menu->addMenu(statusMenu);
  285. statusAction->setIcon(statusMenu->icon(StatusMenu::StatusOffline));
  286. #ifdef Q_WS_WIN
  287. if (QFile::exists(QApplication::applicationDirPath() + "/schatd-ui.exe")) {
  288. #else
  289. if (QFile::exists(QApplication::applicationDirPath() + "/schatd-ui")) {
  290. #endif
  291. menu->addSeparator();
  292. menu->addAction(daemonAction);
  293. }
  294. menu->addSeparator();
  295. menu->addAction(send->quitAction());
  296. tray = new TrayIcon(q);
  297. #ifndef Q_OS_WINCE
  298. tray->setContextMenu(menu);
  299. #endif
  300. QTimer::singleShot(0, tray, SLOT(show()));
  301. }
  302. /*!
  303. * ?????????? ? ?????? ???????? ???????.
  304. * ????????? HTML ?????? ? ??????????? ?? ??????? ? ???? ??? ??????????? ? ??????.
  305. * ???? ?????????? ????????? ???????????? ???????, ?? ????????? ???????????
  306. * ?? ??? ???????? ???????, ????? ?????????? ????? ??????? ? ???????? ? ?
  307. * ?????? ?????? ????????? ??????????? ???? ? ?????????? ??????????
  308. * ??????????? ?????????.
  309. *
  310. * \param status ??????.
  311. * \param nick ??? ????????????.
  312. */
  313. void SChatWindowPrivate::displayStatus(quint32 status, const QString &nick)
  314. {
  315. if (!users->isUser(nick))
  316. return;
  317. if (!pref->getBool("ServiceMessages"))
  318. return;
  319. QString html;
  320. html = QString("<span class='away'><a href='nick:%1'>%2</a> ").arg(QLatin1String(nick.toUtf8().toHex())).arg(Qt::escape(nick));
  321. if (users->profile(nick).isFemale())
  322. html += SChatWindow::tr("changed status to:", "Female");
  323. else
  324. html += SChatWindow::tr("changed status to:", "Male");
  325. html += " <b>";
  326. if (status == schat::StatusAutoAway || status == schat::StatusAway)
  327. html += SChatWindow::tr("Away");
  328. else if (status == schat::StatusDnD)
  329. html += SChatWindow::tr("DND");
  330. else
  331. html += SChatWindow::tr("Online");
  332. html += "</b></span>";
  333. if (nick != profile->nick()) {
  334. PrivateTab *tab = users->privateTab(nick, false);
  335. if (tab) {
  336. tab->msg(html);
  337. }
  338. }
  339. else
  340. msgToAllPrivateTabs(html);
  341. }
  342. /*!
  343. * ???????? ???? ????.
  344. */
  345. void SChatWindowPrivate::hideChat()
  346. {
  347. saveGeometry();
  348. if (settingsDialog)
  349. settingsDialog->hide();
  350. if (about)
  351. about->hide();
  352. q->hide();
  353. }
  354. /*!
  355. * ????????? ????????? ?? ??? ???????? ???????.
  356. */
  357. void SChatWindowPrivate::msgToAllPrivateTabs(const QString &msg)
  358. {
  359. int count = tabs->count();
  360. if (count > 0)
  361. for (int i = 0; i < count; ++i) {
  362. AbstractTab *tab = static_cast<AbstractTab *>(tabs->widget(i));
  363. if (tab->type() == AbstractTab::Private)
  364. tab->msg(msg);
  365. }
  366. }
  367. /*!
  368. * ????????? ????????? ????.
  369. */
  370. void SChatWindowPrivate::saveGeometry()
  371. {
  372. if (!q->isMaximized() && q->size().height()) {
  373. pref->setPos(q->pos());
  374. pref->setSize(q->size());
  375. }
  376. pref->setBool("Maximized", q->isMaximized());
  377. }
  378. /*!
  379. * ????????? ???????? ?????????.
  380. * ?????????? ???????????? ? ??????????? ?? ???? ???????.
  381. *
  382. * \param msg ?????????.
  383. * \param cmd ???????? ????????? ??????.
  384. */
  385. void SChatWindowPrivate::sendMsg(const QString &msg, bool cmd)
  386. {
  387. AbstractTab *tab = static_cast<AbstractTab *>(tabs->currentWidget());
  388. if (cmd)
  389. if (parseCmd(tab, msg))
  390. return;
  391. if (exitAwayOnSend) { /// \todo ???????? ???????? ?????.
  392. if (profile->status() != schat::StatusNormal)
  393. sendStatus(schat::StatusNormal);
  394. }
  395. if (clientService->sendMessage(channel(), msg))
  396. send->clear();
  397. }
  398. void SChatWindowPrivate::setAwayOptions()
  399. {
  400. autoAway = pref->getBool("AutoAway");
  401. exitAwayOnSend = pref->getBool("ExitAwayOnSend");
  402. autoAwayTime = pref->getInt("AutoAwayTime");
  403. if (autoAwayTime < 1)
  404. autoAwayTime = 1;
  405. if (autoAway) {
  406. if (!idleDetector.isActive())
  407. idleDetector.start();
  408. }
  409. else if (idleDetector.isActive())
  410. idleDetector.stop();
  411. }
  412. /*!
  413. * ????? ???? ????.
  414. */
  415. void SChatWindowPrivate::showChat()
  416. {
  417. q->setWindowState(q->windowState() & ~Qt::WindowMinimized);
  418. if (pref->getBool("Maximized"))
  419. q->showMaximized();
  420. else
  421. q->show();
  422. q->activateWindow();
  423. if (about)
  424. about->show();
  425. if (settingsDialog)
  426. settingsDialog->show();
  427. }
  428. /*!
  429. * ??????????? ????????? ????????? ??????????? ? ???????/????.
  430. */
  431. void SChatWindowPrivate::statusAccessGranted(const QString &network, const QString &server)
  432. {
  433. connectionStatus->setState(ConnectionStatus::ConnectedState, server, network);
  434. main->msg("<span class='ready'>" + connectionStatus->echoText() + "</span>");
  435. updateStatus(StatusMenu::StatusOnline);
  436. send->setInputFocus();
  437. if (network.isEmpty()) {
  438. q->setWindowTitle(QApplication::applicationName());
  439. }
  440. else {
  441. q->setWindowTitle(QApplication::applicationName() + " — " + network);
  442. }
  443. if (enableMotd && motd) {
  444. motd = false;
  445. clientService->sendMessage("", "/motd");
  446. }
  447. if (autoAway && profile->status() == schat::StatusNormal && !idleDetector.isActive())
  448. idleDetector.start();
  449. }
  450. /*!
  451. * ??????????? ????????? ??????????? ? ???????/????.
  452. */
  453. void SChatWindowPrivate::statusConnecting(const QString &server, bool network)
  454. {
  455. if (network)
  456. connectionStatus->setState(ConnectionStatus::ConnectingState, "", server);
  457. else
  458. connectionStatus->setState(ConnectionStatus::ConnectingState, server);
  459. updateStatus(StatusMenu::StatusOffline);
  460. main->displayChoiceServer(false);
  461. main->displayWelcome(false);
  462. }
  463. /*!
  464. * ??????????? ????????? ?????????? ??????????? ? ???????/????.
  465. */
  466. void SChatWindowPrivate::statusUnconnected(bool echo)
  467. {
  468. connectionStatus->setState(ConnectionStatus::UnconnectedState);
  469. updateStatus(StatusMenu::StatusOffline);
  470. users->clear();
  471. soundAction->mute();
  472. if (echo)
  473. main->msg("<span class='disconnect'>" + connectionStatus->echoText() + "</span>");
  474. }
  475. /*!
  476. * ????????? ????????? ??????? ?????????????.
  477. *
  478. * - ???? ??????????? ???, ?????????? ? \p data2, ?? ????????????? ? ??????? ??????.
  479. * - ????????? ?????? ?????????????.
  480. * - ???? ???????? ???, ?? ????????? ??????? displayAway(quint32 status, const QString &nick)
  481. * ??? ??????? ????.
  482. * - ????? ?????????? ?????????? ??????????? ????????? ????????.
  483. */
  484. void SChatWindowPrivate::universalStatus(const QList<quint32> &data1, const QStringList &data2)
  485. {
  486. quint32 status = data1.at(0);
  487. // ???????? ??????? ???????????? ???? ? ?????? data2.
  488. if (data2.contains(profile->nick())) {
  489. soundAction->mute();
  490. profile->setStatus(data1.at(0));
  491. if (status == schat::StatusAutoAway || status == schat::StatusAway)
  492. updateStatus(StatusMenu::StatusAway);
  493. else if (status == schat::StatusDnD) {
  494. updateStatus(StatusMenu::StatusDnD);
  495. if (pref->getBool("Sound/MuteInDnD") && soundAction->data().toBool())
  496. soundAction->mute(true);
  497. }
  498. else
  499. updateStatus(StatusMenu::StatusOnline);
  500. if (autoAway && status == schat::StatusNormal && !idleDetector.isActive())
  501. idleDetector.start();
  502. }
  503. // ?????????? ?????? ?????????????.
  504. users->setStatus(status, data2);
  505. if (data1.size() > 1 && data1.at(1)) {
  506. if (users->isUser(data2.at(0))) {
  507. displayStatus(status, data2.at(0));
  508. return;
  509. }
  510. }
  511. }
  512. /*!
  513. * ?????????? ?????????? ?????????? ? ???????.
  514. */
  515. void SChatWindowPrivate::updateStatus(int status)
  516. {
  517. connectionStatus->setUserStatus(status);
  518. statusAction->setIcon(statusMenu->icon(static_cast<StatusMenu::Status>(status)));
  519. }
  520. /*!
  521. * ??????? ??????.
  522. */
  523. #ifndef Q_OS_WINCE
  524. void SChatWindowPrivate::createToolButtons()
  525. {
  526. toolBar->setIconSize(QSize(16, 16));
  527. #if !defined(Q_OS_MAC)
  528. toolBar->setStyleSheet("QToolBar { margin:0px; border:0px; }");
  529. #endif
  530. #if QT_VERSION < 0x040500
  531. toolBar->addAction(QIcon(":/images/tab_close.png"), SChatWindow::tr("Close tab"), q, SLOT(closeTab()));
  532. toolBar->addSeparator();
  533. #endif
  534. QToolButton *settingsButton = send->settingsButton();
  535. if (settingsButton)
  536. toolBar->addWidget(settingsButton)->setVisible(true);
  537. if (send->soundAction().second)
  538. toolBar->addAction(soundAction);
  539. toolBar->addAction(send->aboutAction());
  540. tabs->setCornerWidget(toolBar);
  541. }
  542. #endif
  543. /*!
  544. * \brief ??????????? ?????? SChatWindow.
  545. */
  546. SChatWindow::SChatWindow(QWidget *parent)
  547. : QMainWindow(parent), d(new SChatWindowPrivate(this))
  548. {
  549. d->pref = new Settings(Settings::isUnixLike(), this);
  550. d->profile = d->pref->profile();
  551. d->pref->read();
  552. d->enableMotd = d->pref->getBool("MotdEnable");
  553. d->send = new SendWidget(this);
  554. d->central = new QWidget(this);
  555. d->tabs = new QTabWidget(this);
  556. d->tabs->installEventFilter(this);
  557. #if defined(Q_OS_MAC)
  558. d->tabs->setDocumentMode(true);
  559. #endif
  560. d->users = new UserView(d->profile, d->tabs, this);
  561. d->mainLay = new QVBoxLayout(d->central);
  562. #ifndef SCHAT_WINCE
  563. d->toolBar = new QToolBar(this);
  564. #endif
  565. /// \note ??? Windows Mobile ???? ???????? ????????? ??????,
  566. /// ??? ?????????????? ??? ?????????? ??????????? ???????????.
  567. #ifdef SCHAT_WINCE
  568. d->mainLay->addWidget(d->send);
  569. d->mainLay->setContentsMargins(0, 0, 0, 0);
  570. d->mainLay->setContentsMargins(3, 3, 3, 0);
  571. #endif
  572. d->mainLay->addWidget(d->tabs);
  573. #ifndef SCHAT_WINCE
  574. d->mainLay->addWidget(d->send);
  575. #if defined(Q_OS_MAC)
  576. d->mainLay->setContentsMargins(0, 0, 0, 0);
  577. #else
  578. if (QtWin::isCompositionEnabled()) {
  579. d->mainLay->setContentsMargins(0, 0, 0, 0);
  580. QtWin::extendFrameIntoClientArea(this);
  581. }
  582. else {
  583. d->mainLay->setContentsMargins(3, 3, 3, 0);
  584. }
  585. #endif
  586. #endif
  587. d->mainLay->setSpacing(0);
  588. d->mainLay->setStretchFactor(d->tabs, 999);
  589. d->mainLay->setStretchFactor(d->send, 1);
  590. setCentralWidget(d->central);
  591. d->createStatusBar();
  592. connect(d->statusMenu, SIGNAL(statusChanged(int)), SLOT(statusChangedByUser(int)));
  593. d->popupManager = new PopupManager(this);
  594. connect(d->popupManager, SIGNAL(openChat(const QString &, bool, bool)), SLOT(openChat(const QString &, bool, bool)));
  595. setWindowTitle(QApplication::applicationName());
  596. d->tabs->setElideMode(Qt::ElideRight);
  597. #if QT_VERSION >= 0x040500
  598. d->tabs->setTabsClosable(true);
  599. d->tabs->setMovable(true);
  600. connect(d->tabs, SIGNAL(tabCloseRequested(int)), SLOT(closeTab(int)));
  601. #endif
  602. createActions();
  603. createMenu();
  604. #ifndef SCHAT_WINCE
  605. d->createToolButtons();
  606. #endif
  607. createService();
  608. connect(d->send, SIGNAL(sendMsg(const QString &)), SLOT(sendMsg(const QString &)));
  609. connect(d->send, SIGNAL(needCopy()), SLOT(copy()));
  610. connect(d->send, SIGNAL(about()), SLOT(about()));
  611. connect(d->send, SIGNAL(closeChat()), SLOT(closeChat()));
  612. connect(d->send, SIGNAL(showSettingsPage(int)), SLOT(showSettingsPage(int)));
  613. connect(d->users, SIGNAL(addTab(const QString &)), SLOT(addTab(const QString &)));
  614. connect(d->users, SIGNAL(insertNick(const QString &)), d->send, SLOT(insertHtml(const QString &)));
  615. connect(d->users, SIGNAL(showSettings()), SLOT(showSettingsPage()));
  616. connect(d->users, SIGNAL(emoticonsClicked(const QString &)), d->send, SLOT(insertHtml(const QString &)));
  617. connect(d->users, SIGNAL(popupMsg(const QString &, const QString &, const QString &, bool)), d->popupManager, SLOT(popupMsg(const QString &, const QString &, const QString &, bool)));
  618. connect(d->tabs, SIGNAL(currentChanged(int)), SLOT(stopNotice(int)));
  619. connect(d->pref, SIGNAL(changed(int)), SLOT(settingsChanged(int)));
  620. d->createTrayIcon();
  621. connect(d->tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
  622. #ifndef SCHAT_NO_UPDATE
  623. connect(d->tray, SIGNAL(messageClicked()), SLOT(messageClicked()));
  624. #endif
  625. d->main = new MainChannel(QIcon(":/images/main.png"), d->users, d->tabs);
  626. connect(d->main, SIGNAL(nickClicked(const QString &)), d->users, SLOT(nickClicked(const QString &)));
  627. connect(d->main, SIGNAL(emoticonsClicked(const QString &)), d->send, SLOT(insertHtml(const QString &)));
  628. connect(d->main, SIGNAL(popupMsg(const QString &, const QString &, const QString &, bool)), d->popupManager, SLOT(popupMsg(const QString &, const QString &, const QString &, bool)));
  629. qsrand(QDateTime(QDateTime::currentDateTime()).toTime_t());
  630. if (Settings::isNewYear())
  631. setWindowIcon(QIcon(":/images/schat-ny.png"));
  632. #ifndef Q_WS_WIN
  633. else
  634. setWindowIcon(QIcon(":/images/schat.png"));
  635. #endif
  636. if (!d->pref->getBool("HideWelcome") || d->pref->getBool("FirstRun")) {
  637. d->main->displayWelcome(true);
  638. }
  639. else
  640. d->clientService->connectToHost();
  641. connect(&d->idleDetector, SIGNAL(secondsIdle(int)), SLOT(onSecondsIdle(int)));
  642. d->setAwayOptions();
  643. if (d->pref->getBool("Updates/Enable") && d->pref->getBool("Updates/CheckOnStartup"))
  644. QTimer::singleShot(0, d->pref, SLOT(updatesCheck()));
  645. }
  646. SChatWindow::~SChatWindow()
  647. {
  648. delete d;
  649. }
  650. bool SChatWindow::isActiveChatWindow()
  651. {
  652. if (isMinimized() || isHidden())
  653. return false;
  654. # if defined(Q_OS_WIN32)
  655. if (isActiveWindow()) {
  656. HWND active = GetForegroundWindow();
  657. if (active == (HWND) window()->internalWinId() || ::IsChild(active, (HWND) window()->internalWinId()))
  658. return true;
  659. else
  660. return false;
  661. }
  662. else
  663. return false;
  664. # else
  665. return isActiveWindow();
  666. # endif
  667. }
  668. void SChatWindow::showChat()
  669. {
  670. d->showChat();
  671. }
  672. /*!
  673. * ????????? ???????.
  674. */
  675. bool SChatWindow::event(QEvent *event)
  676. {
  677. if (event->type() == QEvent::WindowActivate)
  678. stopNotice(d->tabs->currentIndex());
  679. if (event->type() == QEvent::WindowStateChange) {
  680. if (windowState() & Qt::WindowMinimized)
  681. d->saveGeometry();
  682. }
  683. #if defined(Q_WS_WIN)
  684. if (event->type() == QEvent::ApplicationPaletteChange) {
  685. if (d->send)
  686. d->send->setStyleSheet();
  687. }
  688. #endif
  689. return QMainWindow::event(event);
  690. }
  691. void SChatWindow::changeEvent(QEvent *event)
  692. {
  693. if (event->type() == QEvent::LanguageChange)
  694. retranslateUi();
  695. else if (event->type() == QEvent::ActivationChange)
  696. d->activationChanged = QTime::currentTime();
  697. QMainWindow::changeEvent(event);
  698. }
  699. /*!
  700. * \brief ????????? ??????? ???????? ????.
  701. */
  702. void SChatWindow::closeEvent(QCloseEvent *event)
  703. {
  704. saveGeometry();
  705. d->pref->write();
  706. d->hideChat();
  707. QMainWindow::closeEvent(event);
  708. }
  709. void SChatWindow::keyPressEvent(QKeyEvent *event)
  710. {
  711. if (event->key() == Qt::Key_Escape)
  712. d->hideChat();
  713. else
  714. QMainWindow::keyPressEvent(event);
  715. }
  716. /*!
  717. * ????????? ??????? ?????? ????.
  718. *
  719. * ???? ? ?????????? ??????? ?????????? ??????? ????, ?? ???? ???????????? ? ??? ???????.
  720. * ???? ??????? ???? ?? ???????? ?? ????????? ??????? ??????, ?? ?????????? ?????? ????,
  721. * ??? ???????? ?? ????????? ??????? ????, ?????? ???????? ????? ???? ????? ????????? ?? ????????? ??????.
  722. */
  723. void SChatWindow::showEvent(QShowEvent *event)
  724. {
  725. if (!d->pref->getBool("Maximized")) {
  726. QPoint windowPos = d->pref->pos();
  727. QDesktopWidget desktop;
  728. QRect availableGeometry = desktop.availableGeometry(windowPos);
  729. QSize windowSize = d->pref->size();
  730. if (availableGeometry.width() >= windowSize.width() && availableGeometry.height() >= windowSize.height())
  731. resize(windowSize);
  732. if (availableGeometry.contains(windowPos))
  733. move(windowPos);
  734. }
  735. QMainWindow::showEvent(event);
  736. }
  737. #if defined(Q_WS_WIN)
  738. bool SChatWindow::winEvent(MSG *message, long *result)
  739. {
  740. if (message && message->message == WM_DWMCOMPOSITIONCHANGED) {
  741. if (QtWin::isCompositionEnabled()) {
  742. d->mainLay->setContentsMargins(0, 0, 0, 0);
  743. QtWin::extendFrameIntoClientArea(this);
  744. }
  745. else {
  746. d->mainLay->setContentsMargins(3, 3, 3, 0);
  747. }
  748. }
  749. return QMainWindow::winEvent(message, result);
  750. }
  751. #endif
  752. /** [private slots]
  753. *
  754. */
  755. void SChatWindow::about()
  756. {
  757. if (isHidden())
  758. show();
  759. if (!d->about) {
  760. d->about = new AboutDialog(this);
  761. d->about->show();
  762. }
  763. d->about->activateWindow();
  764. }
  765. void SChatWindow::accessDenied(quint16 reason)
  766. {
  767. bool notify = true;
  768. switch (reason) {
  769. case ErrorOldClientProtocol:
  770. d->main->msg("<span class='disconnect'>" + tr("Your chat is using an old version of protocol, connection is not established, please update your program.") + "</span>");
  771. break;
  772. case ErrorOldServerProtocol:
  773. d->main->msg("<span class='disconnect'>" + tr("Server is using an old version of protocol, connection is not established.") + "</span>");
  774. break;
  775. case ErrorBadNickName:
  776. d->main->msg("<span class='disconnect'>" + tr("Chosen nickname: <b>%1</b> forbidden in the chat, choose another one").arg(Qt::escape(d->profile->nick())) + "</span>");
  777. break;
  778. case ErrorUsersLimitExceeded:
  779. case ErrorLinksLimitExceeded:
  780. case ErrorMaxUsersPerIpExceeded:
  781. notify = false;
  782. break;
  783. default:
  784. d->main->msg("<span class='disconnect'>" + tr("Critical error with code: <b>%1</b> occurred at connection").arg(reason) + "</span>");
  785. break;
  786. }
  787. if (notify)
  788. unconnected(false);
  789. }
  790. /*!
  791. * ???? ?????????? ???? \a d->clientService ???????? ????? ? ??????? \a OpcodeAccessGranted,
  792. * ??? ???????? ???????? ??????????? ? ???????/????.
  793. */
  794. void SChatWindow::accessGranted(const QString &network, const QString &server, quint16 level)
  795. {
  796. Q_UNUSED(level)
  797. d->statusAccessGranted(network, server);
  798. }
  799. /*!
  800. * ???????? ?????? ??????? ?? ?????????? ?????????? ????????????.
  801. * ?????? ??????????????? ?? ???? ??????.
  802. *
  803. * \param nick ??? ?????????? ????????????.
  804. */
  805. void SChatWindow::addTab(const QString &nick)
  806. {
  807. PrivateTab *tab = d->users->privateTab(nick);
  808. if (tab)
  809. d->tabs->setCurrentIndex(d->tabs->indexOf(tab));
  810. }
  811. /*!
  812. * ?????????? ?????? ?????????.
  813. */
  814. void SChatWindow::closeChat(bool update)
  815. {
  816. d->closeChat(update);
  817. }
  818. /*!
  819. * ????????? ???????? ???????.
  820. *
  821. * ???? ??????? ???????? ???????? ???????, ?? ?????????? ???????????,
  822. * ????? ??? ??????? ?????????? ????????,
  823. * ???????-??????? ??????????? ? ?????????.
  824. *
  825. * \param tab ?????? ???????, ??????? ????? ???????, ?? ????????? -1.
  826. */
  827. void SChatWindow::closeTab(int tab)
  828. {
  829. int index = tab;
  830. if (index == -1)
  831. index = d->tabs->currentIndex();
  832. QWidget *widget = d->tabs->widget(index);
  833. if (widget != d->main) {
  834. d->tabs->removeTab(index);
  835. QTimer::singleShot(0, widget, SLOT(deleteLater()));
  836. }
  837. else {
  838. d->clientService->quit();
  839. d->tabs->setCurrentIndex(index);
  840. }
  841. }
  842. /*!
  843. * ???? ?????????? ????? d->clientService ???????? ??????????? ? ???????.
  844. *
  845. * \param server ???????? ???? ???? network = true, ???? ????? ???????.
  846. * \param network ??????????? ? ???? \a true ???? ? ??????? \a false.
  847. */
  848. void SChatWindow::connecting(const QString &server, bool network)
  849. {
  850. d->statusConnecting(server, network);
  851. }
  852. void SChatWindow::copy()
  853. {
  854. AbstractTab *tab = static_cast<AbstractTab *>(d->tabs->currentWidget());
  855. if (!tab->copy())
  856. d->send->copy();
  857. }
  858. /*!
  859. * ?????? ????????? ?????????? ????????.
  860. */
  861. void SChatWindow::daemonUi()
  862. {
  863. #ifdef Q_WS_WIN
  864. QProcess::startDetached('"' + QApplication::applicationDirPath() + "/schatd-ui.exe\"", QStringList() << "-show");
  865. #else
  866. QProcess::startDetached(QApplication::applicationDirPath() + "/schatd-ui", QStringList() << "-show");
  867. #endif
  868. }
  869. void SChatWindow::fatal()
  870. {
  871. d->main->displayChoiceServer(true);
  872. }
  873. void SChatWindow::handleMessage(const QString &message)
  874. {
  875. QStringList args = message.split(", ");
  876. if (args.contains("-exit")) {
  877. closeChat();
  878. return;
  879. }
  880. d->showChat();
  881. }
  882. void SChatWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
  883. {
  884. switch (reason) {
  885. case QSystemTrayIcon::Trigger:
  886. case QSystemTrayIcon::MiddleClick:
  887. if (isHidden() || isMinimized()) {
  888. d->showChat();
  889. return;
  890. }
  891. if (isActiveChatWindow() || qAbs(d->activationChanged.msecsTo(QTime::currentTime())) < QApplication::doubleClickInterval())
  892. d->hideChat();
  893. else
  894. d->showChat();
  895. default:
  896. break;
  897. }
  898. }
  899. void SChatWindow::linkLeave(quint8 /*numeric*/, const QString &network, const QString &name)
  900. {
  901. d->main->msg("<span class='linkLeave'>" + tr("Server <b>%1</b> disconnected from network <b>%2</b>").arg(Qt::escape(name)).arg(Qt::escape(network)) + "</span>");
  902. }
  903. /*!
  904. * ????????? ????????? ? ???????? ?????.
  905. *
  906. * \param sender ??? ???????????.
  907. * \param msg ?????????.
  908. */
  909. void SChatWindow::message(const QString &sender, const QString &msg)
  910. {
  911. bool selfMsg = d->profile->nick() == sender;
  912. d->main->addMsg(sender, msg,
  913. (selfMsg ? ChatView::MsgSend : ChatView::MsgRecived) | ChatView::MsgPublic,
  914. selfMsg ? false : d->startNotice(d->tabs->indexOf(d->main), "Message"));
  915. }
  916. void SChatWindow::newLink(quint8 /*numeric*/, const QString &network, const QString &name)
  917. {
  918. d->main->msg("<span class='newLink'>" + tr("Server <b>%1</b> connected to network <b>%2</b>").arg(Qt::escape(name)).arg(Qt::escape(network)) + "</span>");
  919. }
  920. /*!
  921. * ????????? ????????? ???? ????????????.
  922. */
  923. void SChatWindow::newNick(quint8 gender, const QString &nick, const QString &newNick, const QString &name)
  924. {
  925. if (!d->users->isUser(nick))
  926. return;
  927. d->users->update(nick, newNick, name, gender);
  928. d->main->msg(ChatView::statusChangedNick(gender, nick, newNick));
  929. }
  930. /*!
  931. * ????????? ????????? ??????? ????????????.
  932. * ??? ??????? ???????????? ? ?????? ??????? ????????? ?????????? ? ????????????,
  933. * ? ????? ???? ??????? ???????? ???????, ?? ??????? ????? ???????????.
  934. *
  935. * \param gender ????? ??? ????????????.
  936. * \param nick ??? ????????????.
  937. * \param name ????? ?????? ???.
  938. */
  939. void SChatWindow::newProfile(quint8 gender, const QString &nick, const QString &name)
  940. {
  941. if (d->users->isUser(nick))
  942. d->users->update(nick, nick, name, gender);
  943. }
  944. /*!
  945. * ?????????? ?????? ????????????.
  946. *
  947. * ???? ?? ??????? ???????? ???????????? ? \a d->users, ?? ??????? ?? ???????.
  948. * ???? ??? ????? ?????? ???????????? ????, ?? ????????????? ????????? ???.
  949. * ???? ???????? ???, ????????? ? ???????? ????? ? ???????, ????????? ? ????? ?????????
  950. * ? ???? ???? ???????? ?????? ??????? ????? ???????????.
  951. *
  952. * ???? ?????????? ?? ??????? ? \a d->clientService.
  953. *
  954. * \param list ??????????? ??????, ?????????? ? ???? ?????? ?????? ????????????.
  955. * \param echo ????????????? ???????? ? ????? ??????????? ? ????? ???????????? ??? echo == 1.
  956. * \param numeric ?? ????????????.
  957. */
  958. void SChatWindow::newUser(const QStringList &list, quint8 echo, quint8 /*numeric*/)
  959. {
  960. AbstractProfile profile(list);
  961. QString nick = profile.nick();
  962. if (!d->users->add(profile, echo))
  963. return;
  964. if (d->profile->nick() != nick && echo == 1)
  965. d->main->addNewUser(profile.genderNum(), nick);
  966. }
  967. void SChatWindow::onSecondsIdle(int seconds)
  968. {
  969. // if activity is detected
  970. if (seconds == 0) {
  971. if (d->profile->status() == schat::StatusAutoAway)
  972. d->sendStatus(schat::StatusNormal);
  973. }
  974. if (seconds == d->autoAwayTime * 60)
  975. d->sendStatus(schat::StatusAutoAway);
  976. }
  977. /*!
  978. * ????????? ?? ?????????? ??????? ?? ????? ???? ????.
  979. */
  980. void SChatWindow::openChat(const QString &nick, bool pub, bool open)
  981. {
  982. if (!pub) {
  983. PrivateTab *tab = d->users->privateTab(nick, false);
  984. if (tab) {
  985. if (open)
  986. d->tabs->setCurrentIndex(d->tabs->indexOf(tab));
  987. else
  988. stopNotice(d->tabs->indexOf(tab));
  989. }
  990. }
  991. else {
  992. if (open)
  993. d->tabs->setCurrentWidget(d->main);
  994. else
  995. stopNotice(d->tabs->indexOf(d->main));
  996. }
  997. if (open)
  998. d->showChat();
  999. }
  1000. /*!
  1001. * ????????? ?? ??????????? ??????? ?????? ?????????? ?????????.
  1002. *
  1003. * \param flag ???? ???, ???? ????? \a 1 ?? ??? ??????????? ?????????.
  1004. * \param nick ??? ????????????, ? ??????? ???? ????????.
  1005. * \param msg ?????????.
  1006. */
  1007. void SChatWindow::privateMessage(quint8 flag, const QString &nick, const QString &msg)
  1008. {
  1009. PrivateTab *tab = d->users->privateTab(nick);
  1010. if (tab) {
  1011. if (flag == 1)
  1012. tab->addMsg(d->profile->nick(), msg);
  1013. else
  1014. tab->addMsg(nick, msg, ChatView::MsgRecived, d->startNotice(d->tabs->indexOf(tab), "PrivateMessage"));
  1015. }
  1016. }
  1017. void SChatWindow::sendMsg(const QString &msg)
  1018. {
  1019. d->sendMsg(msg, true);
  1020. }
  1021. /*!
  1022. * ????? ?????????????? ????????? ?? ???????.
  1023. *
  1024. * \param msg ?????????.
  1025. */
  1026. void SChatWindow::serverMessage(const QString &msg)
  1027. {
  1028. AbstractTab *tab = static_cast<AbstractTab *>(d->tabs->currentWidget());
  1029. if (msg == "/pong") {
  1030. tab->msg(d->colorizedPing());
  1031. return;
  1032. }
  1033. tab->addFilteredMsg(msg);
  1034. }
  1035. /*!
  1036. * ?????????? ????????? ???????? ????????.
  1037. */
  1038. void SChatWindow::showSettingsPage(int page)
  1039. {
  1040. if (isHidden())
  1041. show();
  1042. if (!d->settingsDialog) {
  1043. d->settingsDialog = new SettingsDialog(this);
  1044. d->settingsDialog->show();
  1045. }
  1046. d->settingsDialog->setPage(page);
  1047. d->settingsDialog->activateWindow();
  1048. }
  1049. /*!
  1050. * ????????? ????????? ??????? ?????????????.
  1051. */
  1052. void SChatWindow::statusChangedByUser()
  1053. {
  1054. QAction *action = qobject_cast<QAction *>(sender());
  1055. if (action)
  1056. statusChangedByUser(action->data().toInt());
  1057. }
  1058. /*!
  1059. * ????????? ????????? ??????? ?????????????.
  1060. */
  1061. void SChatWindow::statusChangedByUser(int index)
  1062. {
  1063. quint32 status = d->profile->status();
  1064. if (index == StatusMenu::StatusOffline) {
  1065. d->clientService->quit();
  1066. return;
  1067. }
  1068. if (index == StatusMenu::StatusAway) {
  1069. if (status == schat::StatusAway)
  1070. return;
  1071. d->idleDetector.stop();
  1072. d->sendStatus(schat::StatusAway);
  1073. }
  1074. else if (index == StatusMenu::StatusDnD) {
  1075. if (status == schat::StatusDnD)
  1076. return;
  1077. d->idleDetector.stop();
  1078. d->sendStatus(schat::StatusDnD);
  1079. }
  1080. else if (d->profile->status() != schat::StatusNormal)
  1081. d->sendStatus(schat::StatusNormal);
  1082. if (!d->clientService->isReady())
  1083. d->clientService->connectToHost();
  1084. }
  1085. /*!
  1086. * ????????? ????????? ???????? ? ?????? ???????.
  1087. */
  1088. void SChatWindow::settingsChanged(int notify)
  1089. {
  1090. switch (notify) {
  1091. case Settings::NetworkSettingsChanged:
  1092. case Settings::ServerChanged:
  1093. d->motd = true;
  1094. d->clientService->connectToHost();
  1095. break;
  1096. case Settings::ProfileSettingsChanged:
  1097. d->clientService->setSafeNick(d->profile->nick());
  1098. d->clientService->sendNewProfile();
  1099. d->connectionStatus->setGender(d->profile->isMale());
  1100. d->statusAction->setIcon(d->statusMenu->icon(d->statusMenu->status()));
  1101. break;
  1102. case Settings::ByeMsgChanged:
  1103. d->clientService->sendByeMsg();
  1104. break;
  1105. case Settings::AwaySettingsChanged:
  1106. d->setAwayOptions();
  1107. break;
  1108. default:
  1109. break;
  1110. }
  1111. }
  1112. /*!
  1113. * ??? ????????????? ?????????? ??????????? ? ??????? ??????? ? ????? ??????????? ? ????.
  1114. * ???? ??? ?? ????? ??????? ? ??????????? ? ????? ?????????, ?? ?????????? ??????????? ? ????.
  1115. *
  1116. * ???? ?????????? ??? ????????? ??????? ??????? ? ??? ??????? QEvent::WindowActivate.
  1117. *
  1118. * \param index ????? ??????? ???????.
  1119. */
  1120. void SChatWindow::stopNotice(int index)
  1121. {
  1122. if (index == -1)
  1123. return;
  1124. AbstractTab *tab = static_cast<AbstractTab *>(d->tabs->widget(index));
  1125. if (tab->notice()) {
  1126. d->tabs->setTabIcon(index, tab->icon());
  1127. tab->notice(false);
  1128. }
  1129. int count = d->tabs->count();
  1130. for (int i = 0; i < count; ++i) {
  1131. AbstractTab *t = static_cast<AbstractTab *>(d->tabs->widget(i));
  1132. if (t->notice())
  1133. return;
  1134. }
  1135. d->tray->notice(false);
  1136. }
  1137. /*!
  1138. * ????????? ?????????? ????????????? ?????? ?????????????.
  1139. * ??? ????????????? ?????????? ??????.
  1140. */
  1141. void SChatWindow::syncUsersEnd()
  1142. {
  1143. if (d->profile->status()) {
  1144. d->sendStatus(d->profile->status());
  1145. d->profile->setStatus(schat::StatusNormal);
  1146. }
  1147. if (!d->users->isUser(d->clientService->safeNick())) {
  1148. d->profile->setNick(d->clientService->safeNick());
  1149. QTimer::singleShot(0, d->clientService, SLOT(sendNewProfile()));
  1150. }
  1151. }
  1152. /*!
  1153. * ???? ?????????? ????? ? `d->clientService` ??? ????????? ???????????.
  1154. */
  1155. void SChatWindow::unconnected(bool echo)
  1156. {
  1157. d->statusUnconnected(echo);
  1158. }
  1159. /*!
  1160. * ????????? ?????????????? ??????.
  1161. */
  1162. void SChatWindow::universal(quint16 sub, const QList<quint32> &data1, const QStringList &data2)
  1163. {
  1164. if (sub == schat::UniStatusList && !data1.isEmpty() && !data2.isEmpty())
  1165. d->universalStatus(data1, data2);
  1166. }
  1167. /*!
  1168. * ????? ?????????? ???????????? ?? ????.
  1169. *
  1170. * \param nick ??? ????????????.
  1171. * \param bye ???????????? ????????? ??? ??????.
  1172. * \param echo ???? ???, ? ?????? ???? ????? \a 1, ?? ?????????
  1173. * ? ?????? ????? ????????? ? ???????? ????? ? ? ??????.
  1174. */
  1175. void SChatWindow::userLeave(const QString &nick, const QString &bye, quint8 echo)
  1176. {
  1177. if (d->users->isUser(nick)) {
  1178. if (echo == 1 && d->pref->getBool("ServiceMessages")) {
  1179. AbstractProfile profile(d->users->profile(nick));
  1180. PrivateTab *tab = d->users->privateTab(nick, false);
  1181. if (tab)
  1182. tab->msg(ChatView::statusUserLeft(profile.genderNum(), nick, bye));
  1183. d->main->addUserLeft(profile.genderNum(), nick, bye);
  1184. }
  1185. d->users->remove(nick);
  1186. }
  1187. }
  1188. /*!
  1189. * ????????? ?????? ???? ?? ????????? ? ????.
  1190. */
  1191. #ifndef SCHAT_NO_UPDATE
  1192. void SChatWindow::messageClicked()
  1193. {
  1194. if (d->tray->message() == TrayIcon::UpdateReady)
  1195. closeChat(true);
  1196. }
  1197. #endif
  1198. /*!
  1199. * ?????? ???????.
  1200. *
  1201. * \todo ???????? ??????????? ????, ??? ?????????? ???????.
  1202. */
  1203. bool SChatWindow::eventFilter(QObject *object, QEvent *event)
  1204. {
  1205. if (d->tabs == object) {
  1206. if (event->type() == QEvent::MouseButtonRelease) {
  1207. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  1208. int index = -1;
  1209. QTabBar *tabBar = qFindChild<QTabBar*>(d->tabs);
  1210. for (int i = 0; i < tabBar->count(); ++i) {
  1211. if (tabBar->tabRect(i).contains(mouseEvent->pos())) {
  1212. index = i;
  1213. break;
  1214. }
  1215. }
  1216. if (index > -1 && (mouseEvent->button() == Qt::MidButton)) {
  1217. closeTab(index);
  1218. return true;
  1219. }
  1220. }
  1221. }
  1222. return QMainWindow::eventFilter(object, event);
  1223. }
  1224. /*!
  1225. * ???????? ???? ??? Mac OS X.
  1226. */
  1227. void SChatWindow::createMenu()
  1228. {
  1229. #if !defined(SCHAT_NO_MENU)
  1230. menuBar()->addMenu(d->statusMenu);
  1231. menuBar()->addAction("about", this, SLOT(about()));
  1232. QMenu *helpMenu = menuBar()->addMenu("Help");
  1233. helpMenu->addAction("about", this, SLOT(about()));
  1234. helpMenu->addAction("config", this, SLOT(showSettingsPage()));
  1235. helpMenu->addAction("quit", this, SLOT(closeChat(bool)));
  1236. #endif
  1237. }
  1238. /*!
  1239. * ???????? ????????.
  1240. */
  1241. void SChatWindow::createActions()
  1242. {
  1243. // ?????????...
  1244. d->settingsAction = new QAction(QIcon(":/images/configure.png"), "", this);
  1245. d->settingsAction->setData(SettingsDialog::ProfilePage);
  1246. connect(d->settingsAction, SIGNAL(triggered()), SLOT(showSettingsPage()));
  1247. // ????????/????????? ????
  1248. d->soundAction = d->send->soundAction().first;
  1249. // ?????????? ????????...
  1250. d->daemonAction = new QAction(QIcon(":/images/network.png"), "", this);
  1251. connect(d->daemonAction, SIGNAL(triggered()), SLOT(daemonUi()));
  1252. }
  1253. /*!
  1254. * ??????? ?????????? ??????.
  1255. */
  1256. void SChatWindow::createService()
  1257. {
  1258. d->pref->setApplicationProxy();
  1259. d->clientService = new ClientService(d->profile, &d->pref->network, this);
  1260. connect(d->clientService, SIGNAL(connecting(const QString &, bool)), SLOT(connecting(const QString &, bool)));
  1261. connect(d->clientService, SIGNAL(unconnected(bool)), SLOT(unconnected(bool)));
  1262. connect(d->clientService, SIGNAL(newUser(const QStringList &, quint8, quint8)), SLOT(newUser(const QStringList &, quint8, quint8)));
  1263. connect(d->clientService, SIGNAL(accessGranted(const QString &, const QString &, quint16)), SLOT(accessGranted(const QString &, const QString &, quint16)));
  1264. connect(d->clientService, SIGNAL(userLeave(const QString &, const QString &, quint8)), SLOT(userLeave(const QString &, const QString &, quint8)));
  1265. connect(d->clientService, SIGNAL(accessDenied(quint16)), SLOT(accessDenied(quint16)));
  1266. connect(d->clientService, SIGNAL(message(const QString &, const QString &)), SLOT(message(const QString &, const QString &)));
  1267. connect(d->clientService, SIGNAL(privateMessage(quint8, const QString &, const QString &)), SLOT(privateMessage(quint8, const QString &, const QString &)));
  1268. connect(d->clientService, SIGNAL(fatal()), SLOT(fatal()));
  1269. connect(d->clientService, SIGNAL(syncUsersEnd()), SLOT(syncUsersEnd()));
  1270. connect(d->clientService, SIGNAL(serverMessage(const QString &)), SLOT(serverMessage(const QString &)));
  1271. connect(d->clientService, SIGNAL(newNick(quint8, const QString &, const QString &, const QString &)), SLOT(newNick(quint8, const QString &, const QString &, const QString &)));
  1272. connect(d->clientService, SIGNAL(newProfile(quint8, const QString &, const QString &)), SLOT(newProfile(quint8, const QString &, const QString &)));
  1273. connect(d->clientService, SIGNAL(newLink(quint8, const QString &, const QString &)), SLOT(newLink(quint8, const QString &, const QString &)));
  1274. connect(d->clientService, SIGNAL(linkLeave(quint8, const QString &, const QString &)), SLOT(linkLeave(quint8, const QString &, const QString &)));
  1275. connect(d->clientService, SIGNAL(universal(quint16, const QList<quint32> &, const QStringList &)), SLOT(universal(quint16, const QList<quint32> &, const QStringList &)));
  1276. }
  1277. void SChatWindow::retranslateUi()
  1278. {
  1279. d->settingsAction->setText(tr("Preferences..."));
  1280. d->daemonAction->setText(tr("Manage server..."));
  1281. d->cmds.clear();
  1282. }