1 //////////////////////////////////////////////////////////////////////
2 //
3 // BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi
4 //
5 // BeeBEEP is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // BeeBEEP 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 BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
19 //
20 // $Id: GuiMain.cpp 1476 2021-01-07 10:43:54Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23 
24 #include "AudioManager.h"
25 #include "Core.h"
26 #include "BeeApplication.h"
27 #include "BeeUtils.h"
28 #include "ChatManager.h"
29 #include "EmoticonManager.h"
30 #include "FileDialog.h"
31 #include "FileShare.h"
32 #include "GuiAddUser.h"
33 #include "GuiAskPassword.h"
34 #include "GuiChat.h"
35 #include "GuiChatList.h"
36 #include "GuiCreateGroup.h"
37 #include "GuiCreateMessage.h"
38 #include "GuiConfig.h"
39 #include "GuiEditVCard.h"
40 #include "GuiFileSharing.h"
41 #include "GuiFloatingChat.h"
42 #include "GuiGroupList.h"
43 #include "GuiHome.h"
44 #include "GuiLanguage.h"
45 #include "GuiLog.h"
46 #include "GuiNetworkTest.h"
47 #include "GuiPluginManager.h"
48 #include "GuiRefusedChat.h"
49 #include "GuiSavedChat.h"
50 #include "GuiSavedChatList.h"
51 #include "GuiScreenShot.h"
52 #include "GuiNetwork.h"
53 #include "GuiShareBox.h"
54 #ifdef BEEBEEP_USE_SHAREDESKTOP
55   #include "GuiShareDesktop.h"
56   #include "ImageOptimizer.h"
57 #endif
58 #include "GuiShareLocal.h"
59 #include "GuiShareNetwork.h"
60 #include "GuiShortcut.h"
61 #include "GuiSystemTray.h"
62 #include "GuiFileTransfer.h"
63 #include "GuiUserList.h"
64 #include "GuiMain.h"
65 #include "GuiVCard.h"
66 #ifdef BEEBEEP_USE_WEBENGINE
67   #include "GuiWebView.h"
68 #endif
69 #include "GuiWizard.h"
70 #include "GuiWorkgroups.h"
71 #include "IconManager.h"
72 #include "NetworkManager.h"
73 #include "PluginManager.h"
74 #include "Protocol.h"
75 #include "MessageManager.h"
76 #include "Settings.h"
77 #include "ShortcutManager.h"
78 #include "SpellChecker.h"
79 #include "UserManager.h"
80 #ifdef BEEBEEP_USE_VOICE_CHAT
81   #include "VoicePlayer.h"
82   #include "GuiRecordVoiceMessageSettings.h"
83 #endif
84 #ifdef Q_OS_WIN
85   #include <Windows.h>
86 #endif
87 
88 
GuiMain(QWidget * parent)89 GuiMain::GuiMain( QWidget *parent )
90  : QMainWindow( parent ), m_floatingChats()
91 {
92   setObjectName( "GuiMainWindow" );
93   setWindowIcon( IconManager::instance().icon( "beebeep.png" ) );
94 
95   // Create a status bar before the actions and the menu
96   (void) statusBar();
97 
98   mp_tabMain = new QTabWidget( this );
99   mp_tabMain->setObjectName( "GuiTabMain" );
100   mp_tabMain->setTabPosition( QTabWidget::South );
101   setCentralWidget( mp_tabMain );
102 
103   mp_fileSharing = Q_NULLPTR;
104   mp_screenShot = Q_NULLPTR;
105   mp_log = Q_NULLPTR;
106   mp_networkTest = Q_NULLPTR;
107   m_unreadActivities = 0;
108 
109   mp_barMain = addToolBar( tr( "Show the main tool bar" ) );
110   mp_barMain->setObjectName( "GuiMainToolBar" );
111   mp_barMain->setIconSize( Settings::instance().mainBarIconSize() );
112   mp_barMain->toggleViewAction()->setVisible( false );
113 
114   mp_trayIcon = new GuiSystemTray( this );
115 
116   m_lastUserStatus = User::Online;
117   m_forceShutdown = false;
118   m_autoConnectOnInterfaceUp = false;
119   m_prevActivatedState = true;
120   m_coreIsConnecting = false;
121   m_changeTabToUserListOnFirstConnected = false;
122 
123   m_useFusionStyle = false;
124 
125   createActions();
126   createMainWidgets();
127   createMenus();
128   createToolAndMenuBars();
129   updadePluginMenu();
130 
131   connect( mp_tabMain, SIGNAL( currentChanged( int ) ), this, SLOT( onMainTabChanged( int ) ) );
132 
133   connect( beeCore, SIGNAL( connected() ), this, SLOT( onCoreConnected() ) );
134   connect( beeCore, SIGNAL( disconnected() ), this, SLOT( onCoreDisconnected() ) );
135   connect( beeCore, SIGNAL( newChatMessage( const Chat&, const ChatMessage& ) ), this, SLOT( onNewChatMessage( const Chat&, const ChatMessage& ) ) );
136   connect( beeCore, SIGNAL( fileDownloadRequest( const User&, const FileInfo& ) ), this, SLOT( downloadFile( const User&, const FileInfo& ) ) );
137   connect( beeCore, SIGNAL( folderDownloadRequest( const User&, const QString&, const QList<FileInfo>& ) ), this, SLOT( downloadFolder( const User&, const QString&, const QList<FileInfo>& ) ) );
138   connect( beeCore, SIGNAL( userChanged( const User& ) ), this, SLOT( onUserChanged( const User& ) ) );
139   connect( beeCore, SIGNAL( userRemoved( const User& ) ), this, SLOT( onUserRemoved( const User& ) ) );
140   connect( beeCore, SIGNAL( userIsWriting( const User&, VNumber ) ), this, SLOT( showWritingUser( const User&, VNumber ) ) );
141   connect( beeCore, SIGNAL( fileTransferProgress( VNumber, const User&, const FileInfo&, FileSizeType, qint64 ) ), this, SLOT( onFileTransferProgress( VNumber, const User&, const FileInfo&, FileSizeType, qint64 ) ) );
142   connect( beeCore, SIGNAL( fileTransferMessage( VNumber, const User&, const FileInfo&, const QString&, FileTransferPeer::TransferState ) ), this, SLOT( onFileTransferMessage( VNumber, const User&, const FileInfo&, const QString&, FileTransferPeer::TransferState ) ) );
143   connect( beeCore, SIGNAL( fileShareAvailable( const User& ) ), this, SLOT( showSharesForUser( const User& ) ) );
144   connect( beeCore, SIGNAL( chatChanged( const Chat& ) ), this, SLOT( onChatChanged( const Chat& ) ) );
145   connect( beeCore, SIGNAL( chatRemoved( const Chat& ) ), this, SLOT( onChatRemoved( const Chat& ) ) );
146   connect( beeCore, SIGNAL( savedChatListAvailable() ), this, SLOT( loadSavedChatsCompleted() ) );
147   connect( beeCore, SIGNAL( userConnectionStatusChanged( const User& ) ), this, SLOT( showConnectionStatusChanged( const User& ) ) );
148   connect( beeCore, SIGNAL( networkInterfaceIsDown() ), this, SLOT( onNetworkInterfaceDown() ) );
149   connect( beeCore, SIGNAL( networkInterfaceIsUp() ), this, SLOT( onNetworkInterfaceUp() ) );
150   connect( beeCore, SIGNAL( chatReadByUser( const Chat&, const User& ) ), this, SLOT( onChatReadByUser( const Chat&, const User& ) ) );
151   connect( beeCore, SIGNAL( localUserIsBuzzedBy( const User& ) ), this, SLOT( showBuzzFromUser( const User& ) ) );
152   connect( beeCore, SIGNAL( newSystemStatusMessage( const QString&, int ) ), this, SLOT( showMessage( const QString&, int ) ) );
153   connect( beeCore, SIGNAL( newsAvailable( const QString& ) ), this, SLOT( onNewsAvailable( const QString& ) ) );
154   connect( beeCore, SIGNAL( offlineMessageSentToUser( const User& ) ), this, SLOT( updateUser( const User& ) ) );
155 #ifdef BEEBEEP_USE_SHAREDESKTOP
156   connect( beeCore, SIGNAL( shareDesktopImageAvailable( const User&, const QImage&, const QString&, QRgb ) ), this, SLOT( onShareDesktopImageAvailable( const User&, const QImage&, const QString&, QRgb ) ) );
157   connect( beeCore, SIGNAL( shareDesktopUpdate( const User& ) ), this, SLOT( onShareDesktopUpdate( const User& ) ) );
158 #endif
159 #ifdef BEEBEEP_USE_MULTICAST_DNS
160   connect( beeCore, SIGNAL( multicastDnsChanged() ), this, SLOT( showDefaultServerPortInMenu() ) );
161 #endif
162 #ifdef BEEBEEP_USE_VOICE_CHAT
163   connect( beeCore->voicePlayer(), SIGNAL( openWithExternalPlayer( const QUrl&, VNumber ) ), this, SLOT( openUrlFromChat( const QUrl&, VNumber ) ) );
164 #endif
165 
166   connect( mp_fileTransfer, SIGNAL( transferCanceled( VNumber ) ), beeCore, SLOT( cancelFileTransfer( VNumber ) ) );
167   connect( mp_fileTransfer, SIGNAL( transferPaused( VNumber ) ), beeCore, SLOT( pauseFileTransfer( VNumber ) ) );
168   connect( mp_fileTransfer, SIGNAL( openFileCompleted( const QUrl& ) ), this, SLOT( openUrl( const QUrl& ) ) );
169   connect( mp_fileTransfer, SIGNAL( resumeTransfer( VNumber, const FileInfo& ) ), this, SLOT( resumeFileTransfer( VNumber, const FileInfo& ) ) );
170 
171   connect( mp_userList, SIGNAL( chatSelected( VNumber ) ), this, SLOT( showChat( VNumber ) ) );
172   connect( mp_userList, SIGNAL( userSelected( VNumber ) ), this, SLOT( checkUserSelected( VNumber ) ) );
173   connect( mp_userList, SIGNAL( showVCardRequest( VNumber ) ), this, SLOT( showVCard( VNumber ) ) );
174   connect( mp_userList, SIGNAL( sendFilesToChatRequest( VNumber, const QStringList& ) ), this, SLOT( sendFilesFromChat( VNumber, const QStringList& ) ) );
175 
176   connect( mp_groupList, SIGNAL( openChatForGroupRequest( VNumber ) ), this, SLOT( showChat( VNumber ) ) );
177   connect( mp_groupList, SIGNAL( createGroupRequest() ), this, SLOT( createGroupChat() ) );
178   connect( mp_groupList, SIGNAL( editGroupRequest( VNumber ) ), this, SLOT( editGroupChat( VNumber ) ) );
179   connect( mp_groupList, SIGNAL( showVCardRequest( VNumber ) ), this, SLOT( showVCard( VNumber ) ) );
180 
181   connect( mp_chatList, SIGNAL( chatSelected( VNumber ) ), this, SLOT( showChat( VNumber ) ) );
182   connect( mp_chatList, SIGNAL( chatToClear( VNumber ) ), this, SLOT( clearChat( VNumber ) ) );
183   connect( mp_chatList, SIGNAL( chatToEdit( VNumber ) ), this, SLOT( editGroupChat( VNumber ) ) );
184   connect( mp_chatList, SIGNAL( createNewChatRequest() ), this, SLOT( createGroupChat() ) );
185   connect( mp_chatList, SIGNAL( createNewMessageRequest() ), this, SLOT( createMessage() ) );
186   connect( mp_chatList, SIGNAL( hideEmptyChatsRequest() ), this, SLOT( onHideEmptyChatsRequest() ) );
187 
188   connect( mp_trayIcon, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), this, SLOT( trayIconClicked( QSystemTrayIcon::ActivationReason ) ) );
189   connect( mp_trayIcon, SIGNAL( messageClicked() ), this, SLOT( trayMessageClicked() ) );
190 
191   connect( mp_savedChatList, SIGNAL( savedChatSelected( const QString& ) ), this, SLOT( showSavedChatSelected( const QString& ) ) );
192   connect( mp_savedChatList, SIGNAL( savedChatRemoved( const QString& ) ), this, SLOT( removeSavedChat( const QString& ) ) );
193   connect( mp_savedChatList, SIGNAL( savedChatLinkRequest( const QString& ) ), this, SLOT( linkSavedChat( const QString& ) ) );
194 
195   connect( statusBar(), SIGNAL( messageChanged( const QString& ) ), this, SLOT( onStatusBarMessageChanged( const QString& ) ) );
196 
197   initShortcuts();
198   initGuiItems();
199   updateShortcuts();
200 }
201 
initShortcuts()202 void GuiMain::initShortcuts()
203 {
204   mp_scMinimizeAllChats = new QShortcut( this );
205   mp_scMinimizeAllChats->setContext( Qt::ApplicationShortcut );
206   connect( mp_scMinimizeAllChats, SIGNAL( activated() ), this, SLOT( minimizeAllChats() ) );
207 #ifdef BEEBEEP_USE_QXT
208   mp_scShowAllChats = new QxtGlobalShortcut( this );
209   connect( mp_scShowAllChats, SIGNAL( activated() ), this, SLOT( showAllChats() ) );
210 #endif
211   mp_scShowNextUnreadMessage = new QShortcut( this );
212   mp_scShowNextUnreadMessage->setContext( Qt::ApplicationShortcut );
213   connect( mp_scShowNextUnreadMessage, SIGNAL( activated() ), this, SLOT( showNextChat() ) );
214 }
215 
setupChatConnections(GuiChat * gui_chat)216 void GuiMain::setupChatConnections( GuiChat* gui_chat )
217 {
218   connect( gui_chat, SIGNAL( newMessage( VNumber, const QString& ) ), this, SLOT( sendMessage( VNumber, const QString& ) ) );
219   connect( gui_chat, SIGNAL( writing( VNumber ) ), beeCore, SLOT( sendWritingMessage( VNumber ) ) );
220   connect( gui_chat, SIGNAL( nextChat() ), this, SLOT( showNextChat() ) );
221   connect( gui_chat, SIGNAL( openUrl( const QUrl&, VNumber ) ), this, SLOT( openUrlFromChat( const QUrl&, VNumber ) ) );
222   connect( gui_chat, SIGNAL( sendFileFromChatRequest( VNumber, const QString& ) ), this, SLOT( sendFileFromChat( VNumber, const QString& ) ) );
223   connect( gui_chat, SIGNAL( sendFilesFromChatRequest( VNumber, const QStringList& ) ), this, SLOT( sendFilesFromChat( VNumber, const QStringList& ) ) );
224   connect( gui_chat, SIGNAL( editGroupRequest( VNumber ) ), this, SLOT( editGroupChat( VNumber ) ) );
225   connect( gui_chat, SIGNAL( chatToClear( VNumber ) ), this, SLOT( clearChat( VNumber ) ) );
226   connect( gui_chat, SIGNAL( clearSystemMessagesRequestFromChat( VNumber ) ), this, SLOT( clearSystemMessagesInChat( VNumber ) ) );
227   connect( gui_chat, SIGNAL( showChatMenuRequest() ), this, SLOT( showChatSettingsMenu() ) );
228 #ifdef BEEBEEP_USE_SHAREDESKTOP
229   connect( gui_chat, SIGNAL( shareDesktopToChatRequest( VNumber, bool ) ), this, SLOT( onShareDesktopRequestFromChat( VNumber, bool ) ) );
230   connect( gui_chat, SIGNAL( screenshotToChatRequest( VNumber ) ), this, SLOT( sendScreenshotToChat( VNumber ) ) );
231 #endif
232 }
233 
checkWindowFlagsAndShow()234 void GuiMain::checkWindowFlagsAndShow()
235 {
236   if( !mp_trayIcon->isVisible() )
237   {
238     mp_trayIcon->show();
239 #ifdef Q_OS_LINUX
240     qApp->processEvents();
241     mp_trayIcon->hide();
242     qApp->processEvents();
243     mp_trayIcon->show();
244 #endif
245   }
246 
247   if( mp_tabMain->currentWidget() != mp_home )
248     mp_tabMain->setCurrentWidget( mp_home );
249 
250   if( !Settings::instance().enableMaximizeButton() )
251     setWindowFlags( windowFlags() & ~Qt::WindowMaximizeButtonHint );
252 
253   Bee::setWindowStaysOnTop( this, Settings::instance().stayOnTop() );
254 
255   if( !isVisible() )
256     show();
257 
258   if( Settings::instance().resetGeometryAtStartup() || Settings::instance().guiGeometry().isEmpty() )
259     resetGeometryAndState();
260   else
261     restoreGeometryAndState();
262 
263   checkViewActions();
264 
265 #ifdef Q_OS_WIN
266   beeApp->setSessionNotificationForWindow( reinterpret_cast<HWND>( winId() ) );
267 #endif
268 
269   if( Settings::instance().loadOnTrayAtStartup() && QSystemTrayIcon::isSystemTrayAvailable() )
270   {
271     QMetaObject::invokeMethod( this, "hideToTrayIcon", Qt::QueuedConnection );
272     return;
273   }
274 
275   if( Settings::instance().showMinimizedAtStartup() )
276     QMetaObject::invokeMethod( this, "showMinimized", Qt::QueuedConnection );
277 }
278 
showUp()279 void GuiMain::showUp()
280 {
281   Bee::showUp( this );
282 }
283 
raiseOnTop()284 void GuiMain::raiseOnTop()
285 {
286   Bee::raiseOnTop( this );
287 }
288 
updateWindowTitle()289 void GuiMain::updateWindowTitle()
290 {
291   setWindowTitle( QString( "%1 - %2" ).arg( Bee::userNameToShow( Settings::instance().localUser(), false ), Settings::instance().programName() ) );
292 }
293 
RemoveMenuStringFromTooltip(const QString & s)294 static QString RemoveMenuStringFromTooltip( const QString& s )
295 {
296   return s.isEmpty() ? QString( "" ) : s.split( QString( "\n" ), QString::KeepEmptyParts ).first();
297 }
298 
updateTabTitles()299 void GuiMain::updateTabTitles()
300 {
301   int tab_index = mp_tabMain->indexOf( mp_home );
302   int current_value = m_unreadActivities;
303   mp_tabMain->setTabText( tab_index, current_value > 0 ? QString::number( current_value ) : "" );
304   if( current_value > 0 )
305     mp_tabMain->setTabToolTip( tab_index, QString( "%1: %2 %3" ).arg( RemoveMenuStringFromTooltip( mp_home->mainToolTip() ) ).arg( current_value ).arg( tr( "news" ) ) );
306   else
307     mp_tabMain->setTabToolTip( tab_index, RemoveMenuStringFromTooltip( mp_home->mainToolTip() ) );
308 
309   tab_index = mp_tabMain->indexOf( mp_userList );
310   current_value = beeCore->connectedUsers();
311   int other_value = UserManager::instance().userList().size();
312   mp_tabMain->setTabText( tab_index, current_value > 0 ? QString::number( current_value ) : (other_value > 0 ? QString::number( other_value ) : "" ) );
313   if( current_value > 0 )
314     mp_tabMain->setTabToolTip( tab_index, QString( "%1: %2 %3" ).arg( RemoveMenuStringFromTooltip( mp_userList->mainToolTip() ) ).arg( current_value ).arg( tr( "connected" ) ) );
315   else
316     mp_tabMain->setTabToolTip( tab_index, RemoveMenuStringFromTooltip( mp_userList->mainToolTip() ) );
317 
318   tab_index = mp_tabMain->indexOf( mp_chatList );
319   current_value = ChatManager::instance().countNotEmptyChats( false );
320   mp_tabMain->setTabText( tab_index, current_value > 0 ? QString::number( current_value ) : "" );
321 
322   tab_index = mp_tabMain->indexOf( mp_groupList );
323   current_value = ChatManager::instance().countGroupChats();
324   mp_tabMain->setTabText( tab_index, current_value > 0 ? QString::number( current_value ) : "" );
325 
326   tab_index = mp_tabMain->indexOf( mp_savedChatList );
327   current_value = ChatManager::instance().constHistoryMap().size();
328   mp_tabMain->setTabText( tab_index, current_value > 0 ? QString::number( current_value ) : "" );
329 }
330 
keyPressEvent(QKeyEvent * e)331 void GuiMain::keyPressEvent( QKeyEvent* e )
332 {
333   if( e->key() == Qt::Key_Escape )
334   {
335     if( Settings::instance().keyEscapeMinimizeInTray() )
336       QTimer::singleShot( 0, this, SLOT( hideToTrayIcon() ) );
337     else
338       QTimer::singleShot( 0, this, SLOT( showMinimized() ) );
339     e->accept();
340     return;
341   }
342 
343   QMainWindow::keyPressEvent( e );
344 }
345 
changeEvent(QEvent * e)346 void GuiMain::changeEvent( QEvent* e )
347 {
348   QMainWindow::changeEvent( e );
349 }
350 
closeEvent(QCloseEvent * e)351 void GuiMain::closeEvent( QCloseEvent* e )
352 {
353   if( beeCore->isConnected() )
354   {
355     if( !m_forceShutdown )
356     {
357       if( Settings::instance().closeMinimizeInTray() && QSystemTrayIcon::isSystemTrayAvailable() )
358       {
359         QTimer::singleShot( 0, this, SLOT( hideToTrayIcon() ) );
360         e->ignore();
361         return;
362       }
363 
364       if( Settings::instance().promptOnCloseEvent() )
365       {
366         if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you want to quit %1?" ).arg( Settings::instance().programName() ),
367                                tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
368         {
369           e->ignore();
370           return;
371         }
372       }
373     }
374 
375     beeCore->stop();
376   }
377 
378   if( Settings::instance().saveGeometryOnExit() )
379 #if QT_VERSION == 0x050906
380   {
381     if( isVisible() )
382     {
383       Settings::instance().setGuiGeometry( saveGeometry() );
384       Settings::instance().save();
385     }
386   }
387 #else
388     saveGeometryAndState();
389 #endif
390 
391   QSettings* sets = Settings::instance().objectSettings();
392   sets->deleteLater();
393 
394   if( !m_forceShutdown )
395   {
396     if( !sets->isWritable() )
397     {
398       if( QMessageBox::warning( this, Settings::instance().programName(),
399                               QString( "%1<br>%2<br>%3<br>%4<br>%5" ).arg( tr( "<b>Settings can not be saved</b>. Path:" ) )
400                                                                      .arg( sets->fileName() )
401                                                                      .arg( tr( "<b>is not writable</b> by user:" ) )
402                                                                      .arg( Settings::instance().localUser().accountName() )
403                                                                      .arg( tr( "Do you want to close anyway?" ) ),
404                               tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
405       {
406         e->ignore();
407         return;
408       }
409     }
410 
411     if( Settings::instance().chatAutoSave() )
412     {
413       if( !MessageManager::instance().chatMessageCanBeSaved() )
414       {
415         if( QMessageBox::warning( this, Settings::instance().programName(),
416                               QString( "%1<br>%2<br>%3<br>%4<br>%5" ).arg( tr( "<b>Chat messages can not be saved</b>. Path:" ) )
417                                                                      .arg( Settings::instance().savedChatsFilePath() )
418                                                                      .arg( tr( "<b>is not writable</b> by user:" ) )
419                                                                      .arg( Settings::instance().localUser().accountName() )
420                                                                      .arg( tr( "Do you want to close anyway?" ) ),
421                               tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
422         {
423           e->ignore();
424           return;
425         }
426       }
427     }
428   }
429 
430   if( mp_fileSharing )
431     mp_fileSharing->close();
432 
433   if( mp_screenShot )
434     mp_screenShot->close();
435 
436   if( mp_networkTest )
437     mp_networkTest->close();
438 
439 #ifdef BEEBEEP_USE_WEBENGINE
440   if( mp_webView )
441     mp_webView->close();
442 #endif
443 
444 #ifdef BEEBEEP_USE_VOICE_CHAT
445   if( !beeCore->voicePlayer()->isStopped() )
446     beeCore->voicePlayer()->stop();
447 #endif
448 
449   if( mp_log )
450     mp_log->close();
451 
452   foreach( QWidget* w, qApp->allWidgets() )
453   {
454     GuiSavedChat* gsv = qobject_cast<GuiSavedChat*>( w );
455     if( gsv )
456       gsv->close();
457   }
458 
459   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
460     fl_chat->close();
461 
462   if( mp_menuMain && mp_menuMain->isVisible() )
463     mp_menuMain->close();
464   if( mp_menuSettings && mp_menuSettings->isVisible() )
465     mp_menuSettings->close();
466   if( mp_menuInfo && mp_menuInfo->isVisible() )
467     mp_menuInfo->close();
468   if( mp_menuStatus && mp_menuStatus->isVisible() )
469     mp_menuStatus->close();
470   if( mp_menuUsersSettings && mp_menuUsersSettings->isVisible() )
471     mp_menuUsersSettings->close();
472 
473   mp_trayIcon->hide();
474 
475   if( mp_dockFileTransfers->isFloating() && mp_dockFileTransfers->isVisible() )
476     mp_dockFileTransfers->hide();
477 
478 #ifdef Q_OS_WIN
479   beeApp->resetSessionNotificationForWindow();
480 #endif
481   // quit now on last window closed
482   qApp->setQuitOnLastWindowClosed( true );
483 
484   e->accept();
485 }
486 
showNextChat()487 void GuiMain::showNextChat()
488 {
489 #ifdef BEEBEEP_DEBUG
490   qDebug() << "Show next chat in list with unread messages";
491 #endif
492   Chat c = ChatManager::instance().firstChatWithUnreadMessages();
493   if( c.isValid() )
494   {
495     showChat( c.id() );
496     GuiFloatingChat* fl_chat = floatingChat( c.id() );
497     if( fl_chat && !fl_chat->isActiveWindow() )
498       fl_chat->setFocusInChat();
499   }
500   else
501     showMessage( tr( "No new message available" ), 5000 );
502 }
503 
forceShutdown()504 void GuiMain::forceShutdown()
505 {
506   qDebug() << "Shutdown...";
507   m_forceShutdown = true;
508   if( beeCore->isConnected() )
509     beeCore->stop();
510   close();
511 }
512 
onWakeUpRequest()513 void GuiMain::onWakeUpRequest()
514 {
515 #ifdef BEEBEEP_DEBUG
516   qDebug() << "Main window wakes up from sleep";
517 #endif
518   initGuiItems();
519 }
520 
onSleepRequest()521 void GuiMain::onSleepRequest()
522 {
523 #ifdef BEEBEEP_DEBUG
524   qDebug() << "Main window goes to sleep";
525 #endif
526   if( beeCore->isConnected() )
527   {
528     m_autoConnectOnInterfaceUp = true;
529     stopCore();
530   }
531 }
532 
onCoreConnected()533 void GuiMain::onCoreConnected()
534 {
535   m_coreIsConnecting = false;
536   initGuiItems();
537 #ifdef BEEBEEP_USE_WEBENGINE
538   QTimer::singleShot( 0, mp_webView, SLOT( loadNews() ) );
539 #endif
540 }
541 
onCoreDisconnected()542 void GuiMain::onCoreDisconnected()
543 {
544   if( m_coreIsConnecting )
545     m_coreIsConnecting = false;
546   initGuiItems();
547 }
548 
startCore()549 void GuiMain::startCore()
550 {
551   if( beeCore->isConnected() || m_coreIsConnecting )
552     return;
553 
554   mp_home->resetNews();
555   m_coreIsConnecting = true;
556 
557   if( Settings::instance().askChangeUserAtStartup() )
558   {
559     if( !showWizard() )
560     {
561       m_coreIsConnecting = false;
562       return;
563     }
564   }
565 
566   if( Settings::instance().firstTime() )
567   {
568     Settings::instance().setFirstTime( false );
569     Settings::instance().setAskChangeUserAtStartup( false );
570   }
571 
572   if( Settings::instance().askPassword() )
573   {
574     if( !promptConnectionPassword() )
575     {
576       m_coreIsConnecting = false;
577       return;
578     }
579   }
580 
581   if( beeCore->start() )
582   {
583     m_autoConnectOnInterfaceUp = true;
584     if( Settings::instance().showChatsOnConnection() )
585     {
586       mp_tabMain->setCurrentWidget( mp_chatList );
587       m_changeTabToUserListOnFirstConnected = false;
588     }
589     else if( Settings::instance().showUsersOnConnection() )
590     {
591       mp_tabMain->setCurrentWidget( mp_userList );
592       m_changeTabToUserListOnFirstConnected = false;
593     }
594     else
595       m_changeTabToUserListOnFirstConnected = true;
596   }
597   else
598     QMetaObject::invokeMethod( beeCore, "checkNetworkInterface", Qt::QueuedConnection );
599 }
600 
promptConnectionPassword()601 bool GuiMain::promptConnectionPassword()
602 {
603   GuiAskPassword gap( this );
604   gap.setModal( true );
605   gap.loadData();
606   gap.show();
607   gap.setFixedSize( gap.size() );
608   if( gap.exec() == QDialog::Rejected )
609     return false;
610   mp_actPromptPassword->setChecked( Settings::instance().askPasswordAtStartup() );
611   if( beeCore->isConnected() )
612     showRestartConnectionAlertMessage();
613   return true;
614 }
615 
disconnectFromNetwork()616 void GuiMain::disconnectFromNetwork()
617 {
618   m_autoConnectOnInterfaceUp = false;
619   stopCore();
620 }
621 
stopCore()622 void GuiMain::stopCore()
623 {
624   if( isFileTransferInProgress() )
625     return;
626 
627   if( mp_tabMain->currentWidget() != mp_home )
628     mp_tabMain->setCurrentWidget( mp_home );
629 
630 #ifdef BEEBEEP_USE_SHAREDESKTOP
631   foreach( GuiShareDesktop* gsd, m_desktops )
632     gsd->close();
633 #endif
634 
635   beeCore->stop();
636 }
637 
restartCore()638 void GuiMain::restartCore()
639 {
640   if( !beeCore->isConnected() && !m_coreIsConnecting )
641   {
642     startCore();
643     return;
644   }
645 
646   if( isFileTransferInProgress() )
647     return;
648 
649 #ifdef BEEBEEP_USE_SHAREDESKTOP
650   foreach( GuiShareDesktop* gsd, m_desktops )
651     gsd->close();
652 #endif
653 
654   mp_home->resetNews();
655   m_coreIsConnecting = true;
656   beeCore->restart();
657 }
658 
isFileTransferInProgress()659 bool GuiMain::isFileTransferInProgress()
660 {
661   if( m_forceShutdown )
662     return false;
663 
664   if( !NetworkManager::instance().isMainInterfaceUp() )
665     return false;
666 
667   if( beeApp->isInSleepMode() )
668     return false;
669 
670   if( beeCore->hasFileTransferInProgress() )
671   {
672     if( QMessageBox::warning( this, Settings::instance().programName(),
673         tr( "There are still files that have not been transferred and will be interrupted. Do you want to disconnect anyway?" ),
674         tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
675       return true;
676   }
677   return false;
678 }
679 
initGuiItems()680 void GuiMain::initGuiItems()
681 {
682   mp_userList->updateUsers();
683   mp_chatList->updateChats();
684   mp_groupList->updateGroups();
685   mp_savedChatList->updateSavedChats();
686   updateStatusIcon();
687   updateNewMessageAction();
688   checkViewActions();
689 }
690 
checkViewActions()691 void GuiMain::checkViewActions()
692 {
693   bool is_connected = beeCore->isConnected();
694   int connected_users = beeCore->connectedUsers();
695   bool file_transfer_is_active = beeCore->isFileTransferActive();
696 
697   mp_actConnect->setEnabled( !m_coreIsConnecting && !is_connected );
698   mp_actDisconnect->setEnabled( is_connected );
699   mp_actBroadcast->setEnabled( is_connected );
700   mp_actCreateMessage->setEnabled( is_connected && !Settings::instance().disableCreateMessage() );
701   mp_actCreateGroupChat->setEnabled( UserManager::instance().userList().size() > 1 );
702   mp_actViewFileTransfer->setEnabled( Settings::instance().enableFileTransfer() );
703   mp_actViewFileSharing->setEnabled( file_transfer_is_active && Settings::instance().enableFileSharing() && !Settings::instance().disableFileSharing() );
704   if( mp_menuFileTransferSettings->isEnabled() )
705   {
706     foreach( QAction* act, mp_menuFileTransferSettings->actions() )
707     {
708       if( act->data().toInt() == 12 )
709         continue;
710       act->setEnabled( Settings::instance().enableFileTransfer() );
711     }
712   }
713   mp_actEnableFileSharing->setEnabled( Settings::instance().enableFileTransfer() && !Settings::instance().disableFileSharing() );
714 
715 #ifdef BEEBEEP_USE_VOICE_CHAT
716   mp_menuVoiceMessage->setEnabled( Settings::instance().enableFileTransfer() );
717 #endif
718 
719   showDefaultServerPortInMenu();
720 
721   if( !m_floatingChats.isEmpty() )
722   {
723     foreach( GuiFloatingChat* fl_chat, m_floatingChats )
724       fl_chat->updateActions( is_connected, connected_users, file_transfer_is_active );
725   }
726 
727   if( mp_fileSharing )
728   {
729     if( mp_actViewFileSharing->isEnabled() )
730       mp_fileSharing->checkViewActions();
731     else
732       mp_fileSharing->close();
733   }
734 
735   updateWindowTitle();
736   updateTabTitles();
737 }
738 
showAbout()739 void GuiMain::showAbout()
740 {
741 #ifdef Q_OS_MAC
742   QMessageBox::about( Q_NULLPTR, Settings::instance().programName(),
743 #else
744   QMessageBox::about( this, Settings::instance().programName(),
745 #endif
746                       QString( "<b>%1</b> - Free Office Messenger<br><br>%2<br>%3 %4 %5<br><br>%6 %7<br>%8<br>" )
747                         .arg( Settings::instance().programName() )
748                         .arg( Settings::instance().isDevelopmentVersion() ? tr( "Development version") : tr( "Version" ) )
749                         .arg( Settings::instance().version( true, true, true ) )
750                         .arg( tr( "for" ) )
751                         .arg( Settings::instance().operatingSystem( true ) )
752                         .arg( tr( "developed by" ) )
753                         .arg( QString( "<a href='%1'>Marco Mastroddi</a>" ).arg( Settings::instance().developerWebSite() ) )
754                         .arg( QString( "e-mail: <a href='mailto://marco.mastroddi@gmail.com'>marco.mastroddi@gmail.com</a><br>web: <a href='%1'>www.beebeep.net</a>" ).arg( Settings::instance().officialWebSite() ) )
755                       );
756 }
757 
showLicense()758 void GuiMain::showLicense()
759 {
760   QString license_txt = QLatin1String(
761   "BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi <br><br>"
762   "BeeBEEP is free software: you can redistribute it and/or modify "
763   "it under the terms of the GNU General Public License as published "
764   "by the Free Software Foundation, either version 3 of the License "
765   "or (at your option) any later version. <br><br>"
766   "BeeBEEP is distributed in the hope that it will be useful, "
767   "but WITHOUT ANY WARRANTY; without even the implied warranty "
768   "of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. <br><br>"
769   "See the GNU General Public License for more details. <br><br>" );
770 #ifdef Q_OS_MAC
771   QMessageBox::about( Q_NULLPTR, Settings::instance().programName(), license_txt );
772 #else
773   QMessageBox::about( this, Settings::instance().programName(), license_txt );
774 #endif
775 }
776 
showAboutQt()777 void GuiMain::showAboutQt()
778 {
779 #ifdef Q_OS_MAC
780   QMessageBox::aboutQt( Q_NULLPTR, Settings::instance().programName() );
781 #else
782   QMessageBox::aboutQt( this, Settings::instance().programName() );
783 #endif
784 }
785 
createActions()786 void GuiMain::createActions()
787 {
788   mp_actConnect = new QAction( IconManager::instance().icon( "connection.png" ), tr( "Connect" ), this );
789   connect( mp_actConnect, SIGNAL( triggered() ), this, SLOT( startCore() ) );
790 
791   mp_actDisconnect = new QAction( IconManager::instance().icon( "disconnection.png" ), tr( "Disconnect" ), this );
792   connect( mp_actDisconnect, SIGNAL( triggered() ), this, SLOT( disconnectFromNetwork() ) );
793 
794   mp_actBroadcast = new QAction( IconManager::instance().icon( "broadcast.png" ), tr( "Search users" ), this );
795   connect( mp_actBroadcast, SIGNAL( triggered() ), this, SLOT( sendBroadcastMessage() ) );
796 
797   mp_actConfigureNetwork = new QAction( IconManager::instance().icon( "network.png"), tr( "Configure network..."), this );
798   connect( mp_actConfigureNetwork, SIGNAL( triggered() ), this, SLOT( searchUsers() ) );
799 
800   mp_actQuit = new QAction( IconManager::instance().icon( "quit.png" ), tr( "Quit" ), this );
801   mp_actQuit->setShortcuts( QKeySequence::Quit );
802   mp_actQuit->setMenuRole( QAction::QuitRole );
803   connect( mp_actQuit, SIGNAL( triggered() ), this, SLOT( forceShutdown() ) );
804 
805   mp_actVCard = new QAction( IconManager::instance().icon( "profile-edit.png"), tr( "Edit your profile..." ), this );
806   connect( mp_actVCard, SIGNAL( triggered() ), this, SLOT( changeVCard() ) );
807 
808   mp_actAbout = new QAction( IconManager::instance().icon( "beebeep.png" ), tr( "About %1..." ).arg( Settings::instance().programName() ), this );
809   mp_actAbout->setMenuRole( QAction::AboutRole );
810   connect( mp_actAbout, SIGNAL( triggered() ), this, SLOT( showAbout() ) );
811 
812   mp_actCreateGroupChat = new QAction( IconManager::instance().icon( "group-create.png" ), tr( "Create new group chat" ), this );
813   connect( mp_actCreateGroupChat, SIGNAL( triggered() ), this, SLOT( createGroupChat() ) );
814 
815   mp_actViewNewMessage = new QAction( IconManager::instance().icon( "beebeep-message.png" ), tr( "Show new message" ), this );
816   connect( mp_actViewNewMessage, SIGNAL( triggered() ), this, SLOT( showNextChat() ) );
817 
818   mp_actViewFileSharing = new QAction( IconManager::instance().icon( "file-sharing.png" ), tr( "Show file sharing window" ), this );
819   connect( mp_actViewFileSharing, SIGNAL( triggered() ), this, SLOT( showFileSharingWindow() ) );
820 
821   mp_actViewLog = new QAction( IconManager::instance().icon( "log.png" ), tr( "Show the %1 log" ).arg( Settings::instance().programName() )+QString("..."), this );
822   connect( mp_actViewLog, SIGNAL( triggered() ), this, SLOT( showLogWindow() ) );
823 
824   mp_actViewScreenShot = new QAction( IconManager::instance().icon( "screenshot.png" ), tr( "Make a screenshot" ), this );
825   connect( mp_actViewScreenShot, SIGNAL( triggered() ), this, SLOT( showScreenShotWindow() ) );
826 
827   mp_actCreateMessage = new QAction( IconManager::instance().icon( "message-create" ), tr( "Write a message" ), this );
828   connect( mp_actCreateMessage, SIGNAL( triggered() ), this, SLOT( createMessage() ) );
829   if( Settings::instance().disableCreateMessage() )
830     mp_actCreateMessage->setToolTip( tr( "The option has been disabled by your system administrator.") );
831 
832 #ifdef BEEBEEP_USE_WEBENGINE
833   mp_actWebView = new QAction( IconManager::instance().icon( "network.png" ), tr( "News" ), this );
834   connect( mp_actWebView, SIGNAL( triggered() ), this, SLOT( showWebView() ) );
835   mp_actWebView->setDisabled( true );
836 #endif
837 }
838 
createMenus()839 void GuiMain::createMenus()
840 {
841   /* Plugins Menu */
842   mp_menuPlugins = new QMenu( tr( "Plugins" ) + QString( "..." ), this );
843   mp_menuPlugins->setIcon( IconManager::instance().icon( "plugin.png" ) );
844 
845   /* Main Menu */
846   mp_menuMain = new QMenu( tr( "Main" ), this );
847   mp_menuMain->addAction( mp_actConnect );
848   mp_menuMain->addAction( mp_actDisconnect );
849   mp_menuMain->addSeparator();
850   mp_menuMain->addAction( mp_actBroadcast );
851   mp_menuMain->addSeparator();
852   mp_menuMain->addAction( mp_actVCard );
853   mp_menuMain->addSeparator();
854   if( Settings::instance().resourceFolder() != Settings::instance().dataFolder() )
855     mp_menuMain->addAction( IconManager::instance().icon( "resource-folder.png" ), tr( "Open your resource folder" )+QString("..."), this, SLOT( openResourceFolder() ) );
856   mp_menuMain->addAction( IconManager::instance().icon( "data-folder.png" ), tr( "Open your data folder" )+QString("..."), this, SLOT( openDataFolder() ) );
857   mp_menuMain->addAction( IconManager::instance().icon( "download-folder.png" ), tr( "Open your download folder" )+QString("..."), this, SLOT( openDownloadFolder() ) );
858   mp_menuMain->addSeparator();
859   mp_menuMain->addAction( IconManager::instance().icon( "network-test.png" ), tr( "Test your network" )+QString("..."), this, SLOT( showNetworkTest() ) );
860   mp_menuMain->addSeparator();
861   mp_menuMain->addAction( mp_actViewLog );
862 #ifdef BEEBEEP_USE_WEBENGINE
863   mp_menuMain->addSeparator();
864   mp_menuMain->addAction( mp_actWebView );
865 #endif
866   mp_menuMain->addSeparator();
867   mp_menuMain->addMenu( mp_menuPlugins );
868   mp_menuMain->addSeparator();
869   mp_menuMain->addAction( mp_actQuit );
870 
871   QAction* act;
872   /* Chat Menu */
873   mp_menuChat = new QMenu( tr( "Chat" ), this );
874 
875   /* System Menu */
876   mp_menuSettings = new QMenu( tr( "Settings" ), this );
877   mp_menuInterfaceSettings = new QMenu( tr( "Interface" ), this );
878   mp_menuInterfaceSettings->setIcon( IconManager::instance().icon( "interface.png" ) );
879   mp_menuSettings->addMenu( mp_menuInterfaceSettings );
880   act = mp_menuInterfaceSettings->addAction( tr( "Use the dark theme" ), this, SLOT( settingsChanged() ) );
881   act->setCheckable( true );
882   act->setChecked( Settings::instance().useDarkStyle() );
883   act->setData( 77 );
884 #if QT_VERSION < 0x050000
885   act->setEnabled( false );
886 #endif
887   act = mp_menuInterfaceSettings->addAction( tr( "Reset minimum width for applied style" ), this, SLOT( settingsChanged() ) );
888   act->setCheckable( true );
889   act->setChecked( Settings::instance().resetMinimumWidthForStyle() );
890   act->setData( 103 );
891   mp_menuInterfaceSettings->addSeparator();
892   act = mp_menuInterfaceSettings->addAction( tr( "Escape key minimize to tray icon" ), this, SLOT( settingsChanged() ) );
893   act->setCheckable( true );
894   act->setChecked( Settings::instance().keyEscapeMinimizeInTray() );
895   act->setData( 29 );
896   act = mp_menuInterfaceSettings->addAction( tr( "Close button minimize to tray icon" ), this, SLOT( settingsChanged() ) );
897   act->setCheckable( true );
898   act->setChecked( Settings::instance().closeMinimizeInTray() );
899   act->setData( 11 );
900 #ifdef Q_OS_MAC
901   // Close button on MacOSX must quit the app
902   act->setDisabled( true );
903 #endif
904   act = mp_menuInterfaceSettings->addAction( tr( "Enable maximize button" ), this, SLOT( settingsChanged() ) );
905   act->setCheckable( true );
906   act->setChecked( Settings::instance().enableMaximizeButton() );
907   act->setData( 28 );
908   mp_menuInterfaceSettings->addSeparator();
909   mp_menuInterfaceSettings->addAction( IconManager::instance().icon( "shortcut.png" ), tr( "Shortcuts" ) + QString( "..." ), this, SLOT( editShortcuts() ) );
910   mp_menuInterfaceSettings->addAction( IconManager::instance().icon( "language.png" ), tr( "Select language" ) + QString( "..." ), this, SLOT( selectLanguage() ) );
911   mp_menuInterfaceSettings->addAction( IconManager::instance().icon( "theme.png" ), tr( "Select icon theme" ) + QString( "..." ), this, SLOT( selectIconSourcePath() ) );
912   mp_menuInterfaceSettings->addSeparator();
913   mp_menuInterfaceSettings->addAction( IconManager::instance().icon( "update.png" ), tr( "Restore the colors to the default ones" ), this, SLOT( resetAllColors() ) );
914   mp_menuInterfaceSettings->addAction( IconManager::instance().icon( "reset-window.png" ), tr( "Reset geometry of all windows" ), this, SLOT( askResetGeometryAndState() ) );
915 
916   mp_menuStartupSettings = new QMenu( tr( "On start" ), this );
917   mp_menuStartupSettings->setIcon( IconManager::instance().icon( "settings-start.png" ) );
918   mp_menuSettings->addMenu( mp_menuStartupSettings );
919   act = mp_menuStartupSettings->addAction( tr( "Show minimized" ), this, SLOT( settingsChanged() ) );
920   act->setCheckable( true );
921   act->setChecked( Settings::instance().showMinimizedAtStartup() );
922   act->setData( 35 );
923   act = mp_menuStartupSettings->addAction( tr( "Show only on system tray" ), this, SLOT( settingsChanged() ) );
924   act->setCheckable( true );
925   act->setChecked( Settings::instance().loadOnTrayAtStartup() );
926   act->setData( 24 );
927   act = mp_menuStartupSettings->addAction( tr( "Reset window geometry" ), this, SLOT( settingsChanged() ) );
928   act->setCheckable( true );
929   act->setChecked( Settings::instance().resetGeometryAtStartup() );
930   act->setData( 26 );
931   act = mp_menuStartupSettings->addAction( tr( "Check for new version" ), this, SLOT( settingsChanged() ) );
932   act->setCheckable( true );
933   act->setChecked( Settings::instance().checkNewVersionAtStartup() );
934   act->setData( 43 );
935   mp_menuStartupSettings->addSeparator();
936   act = mp_menuStartupSettings->addAction( IconManager::instance().icon( "timer.png" ), tr( "Delay first connection" ) + QString( "..." ), this, SLOT( settingsChanged() ) );
937   act->setData( 65 );
938 
939   mp_menuCloseSettings = new QMenu( tr( "On close" ), this );
940   mp_menuCloseSettings->setIcon( IconManager::instance().icon( "settings-close.png" ) );
941   mp_menuSettings->addMenu( mp_menuCloseSettings );
942   act = mp_menuCloseSettings->addAction( tr( "Prompt on quit when connected" ), this, SLOT( settingsChanged() ) );
943   act->setCheckable( true );
944   act->setChecked( Settings::instance().promptOnCloseEvent() );
945   act->setData( 36 );
946   act = mp_menuCloseSettings->addAction( tr( "Save window's geometry" ), this, SLOT( settingsChanged() ) );
947   act->setCheckable( true );
948   act->setChecked( Settings::instance().saveGeometryOnExit() );
949   act->setData( 68 );
950 
951   mp_menuConnectionSettings = new QMenu( tr( "On connection" ), this );
952   mp_menuConnectionSettings->setIcon( IconManager::instance().icon( "connection.png" ) );
953   mp_menuSettings->addMenu( mp_menuConnectionSettings );
954   act = mp_menuConnectionSettings->addAction( tr( "Show the user list" ), this, SLOT( settingsChanged() ) );
955   act->setCheckable( true );
956   act->setChecked( Settings::instance().showUsersOnConnection() );
957   act->setData( 69 );
958   act = mp_menuConnectionSettings->addAction( tr( "Show the chat list" ), this, SLOT( settingsChanged() ) );
959   act->setCheckable( true );
960   act->setChecked( Settings::instance().showChatsOnConnection() );
961   act->setData( 79 );
962   mp_menuConnectionSettings->addSeparator();
963   act = mp_menuConnectionSettings->addAction( tr( "Prompts to change user" ), this, SLOT( settingsChanged() ) );
964   act->setCheckable( true );
965   act->setChecked( Settings::instance().askChangeUserAtStartup() );
966   act->setData( 45 );
967   mp_actPromptPassword = mp_menuConnectionSettings->addAction( tr( "Prompts to ask network password" ), this, SLOT( settingsChanged() ) );
968   mp_actPromptPassword->setCheckable( true );
969   mp_actPromptPassword->setChecked( Settings::instance().askPasswordAtStartup() );
970   mp_actPromptPassword->setData( 17 );
971 
972   mp_menuNetworkStatus = new QMenu( tr( "Network" ), this );
973   mp_menuNetworkStatus->setIcon( IconManager::instance().icon( "network.png" ) );
974   mp_menuSettings->addMenu( mp_menuNetworkStatus );
975   mp_menuNetworkStatus->addAction( mp_actConfigureNetwork );
976   mp_menuNetworkStatus->addSeparator();
977   mp_actEditWorkgroups = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "workgroup.png" ), tr( "Your workgroups" ) + QString( "..." ), this, SLOT( showWorkgroups() ) );
978   mp_menuNetworkStatus->addSeparator();
979   mp_actHostAddress = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "network.png" ), QString( "ip" ) );
980   mp_actPortBroadcast = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "broadcast.png" ), QString( "udp1" ) );
981   mp_actMulticastGroupAddress = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "multicast-group.png" ), QString( "multicast" ) );
982   mp_actPortListener = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "default-chat-online.png" ), QString( "tcp1" ) );
983   mp_actPortFileTransfer = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "network-scan.png" ), QString( "tcp2" ) );
984 #ifdef BEEBEEP_USE_MULTICAST_DNS
985   mp_actMulticastDns = mp_menuNetworkStatus->addAction( IconManager::instance().icon( "mdns.png" ), QString( "mdns" ) );
986 #endif
987   mp_menuNetworkStatus->addSeparator();
988   mp_actEncryptedConnectionByDefault = mp_menuNetworkStatus->addAction( Settings::instance().disableConnectionSocketEncryption() ? IconManager::instance().icon( "encryption-disabled.png" ) : IconManager::instance().icon( "encryption-enabled.png" ), QString( "End-to-end encryption" ) );
989   mp_actCompressedDataByDefault = mp_menuNetworkStatus->addAction( Settings::instance().disableConnectionSocketDataCompression() ? IconManager::instance().icon( "folder.png" ) : IconManager::instance().icon( "file-compressed.png" ), QString( "Data compression" ) );
990 
991   mp_menuUsersSettings = new QMenu( tr( "Users" ), this );
992   mp_menuUsersSettings->setIcon( IconManager::instance().icon( "user-list.png" ) );
993   mp_menuSettings->addMenu( mp_menuUsersSettings );
994 
995   QMenu* menu_recognize_users = mp_menuUsersSettings->addMenu( tr( "Recognize users" ) + QString( "..." ) );
996   menu_recognize_users->setIcon( IconManager::instance().icon( "user-list.png" ) );
997   mp_actGroupRecognizeUsers = new QActionGroup( this );
998   mp_actGroupRecognizeUsers->setExclusive( true );
999   act = menu_recognize_users->addAction( tr( "By nickname" ) + QString( " (%1)" ).arg( tr( "default" ) ) );
1000   act->setCheckable( true );
1001   act->setChecked( Settings::instance().userRecognitionMethod() == Settings::RecognizeByNickname );
1002   act->setData( 59 );
1003   mp_actGroupRecognizeUsers->addAction( act );
1004   act = menu_recognize_users->addAction( tr( "By account name and domain name" ) );
1005   act->setCheckable( true );
1006   act->setChecked( Settings::instance().userRecognitionMethod() == Settings::RecognizeByAccountAndDomain );
1007   act->setData( 57 );
1008   mp_actGroupRecognizeUsers->addAction( act );
1009   act = menu_recognize_users->addAction( tr( "By account name" ) );
1010   act->setCheckable( true );
1011   act->setChecked( Settings::instance().userRecognitionMethod() == Settings::RecognizeByAccount );
1012   act->setData( 58 );
1013   mp_actGroupRecognizeUsers->addAction( act );
1014   menu_recognize_users->addSeparator();
1015   connect( mp_actGroupRecognizeUsers, SIGNAL( triggered( QAction* ) ), this, SLOT( settingsChanged( QAction* ) ) );
1016   mp_menuUsersSettings->addSeparator();
1017   mp_actAddUsers = mp_menuUsersSettings->addAction( IconManager::instance().icon( "user-add.png" ), tr( "Add users" ) + QString( "..." ), this, SLOT( showAddUser() ) );
1018   mp_menuUsersSettings->addSeparator();
1019   mp_actSaveUserList = mp_menuUsersSettings->addAction( tr( "Save users" ), this, SLOT( settingsChanged() ) );
1020   mp_actSaveUserList->setCheckable( true );
1021   mp_actSaveUserList->setChecked( Settings::instance().saveUserList() );
1022   mp_actSaveUserList->setData( 32 );
1023   mp_actSaveGroupList = mp_menuUsersSettings->addAction( tr( "Save groups" ), this, SLOT( settingsChanged() ) );
1024   mp_actSaveGroupList->setCheckable( true );
1025   mp_actSaveGroupList->setChecked( Settings::instance().saveGroupList() );
1026   mp_actSaveGroupList->setData( 2 );
1027   mp_menuUsersSettings->addSeparator();
1028   mp_actShowUserFullName = mp_menuUsersSettings->addAction( tr( "Show the name and surname of the users" ) , this, SLOT( settingsChanged() ) );
1029   mp_actShowUserFullName->setCheckable( true );
1030   mp_actShowUserFullName->setChecked( Settings::instance().useUserFullName() );
1031   mp_actShowUserFullName->setDisabled( true );
1032   mp_actShowUserFirstNameFirstInFullName = mp_menuUsersSettings->addAction( tr( "Show surname before firstname of the users" ) , this, SLOT( settingsChanged() ) );
1033   mp_actShowUserFirstNameFirstInFullName->setCheckable( true );
1034   mp_actShowUserFirstNameFirstInFullName->setChecked( !Settings::instance().useUserFirstNameFirstInFullName() );
1035   mp_actShowUserFirstNameFirstInFullName->setData( 102 );
1036   mp_menuUsersSettings->addSeparator();
1037   mp_actRemoveInactiveUsers = mp_menuUsersSettings->addAction( "", this, SLOT( settingsChanged() ) );
1038   mp_actRemoveInactiveUsers->setCheckable( true );
1039   mp_actRemoveInactiveUsers->setChecked( Settings::instance().removeInactiveUsers() );
1040   mp_actRemoveInactiveUsers->setData( 33 );
1041   setMaxInactivityDaysInAction( mp_actRemoveInactiveUsers );
1042   mp_menuChatSettings = new QMenu( tr( "Chat" ), this );
1043   mp_menuChatSettings->setIcon( IconManager::instance().icon( "chat.png" ) );
1044   mp_menuSettings->addMenu( mp_menuChatSettings );
1045   mp_menuChatSaveSettings = new QMenu( tr( "Save messages" ) + QString( "..." ), this );
1046   mp_menuChatSaveSettings->setIcon( IconManager::instance().icon( "save-as.png" ) );
1047   mp_menuChatSettings->addMenu( mp_menuChatSaveSettings );
1048   act = mp_menuChatSaveSettings->addAction( tr( "Enable message saving" ), this, SLOT( settingsChanged() ) );
1049   act->setCheckable( true );
1050   act->setChecked( Settings::instance().chatAutoSave() );
1051   act->setData( 18 );
1052   mp_menuChatSaveSettings->addSeparator();
1053   act = mp_menuChatSaveSettings->addAction( tr( "Save unsent messages" ), this, SLOT( settingsChanged() ) );
1054   act->setCheckable( true );
1055   act->setChecked( Settings::instance().chatSaveUnsentMessages() );
1056   act->setData( 81 );
1057   mp_actSaveFileTransferMessages = mp_menuChatSaveSettings->addAction( tr( "Save file transfer messages" ), this, SLOT( settingsChanged() ) );
1058   mp_actSaveFileTransferMessages->setCheckable( true );
1059   mp_actSaveFileTransferMessages->setChecked( Settings::instance().chatSaveFileTransfers() );
1060   mp_actSaveFileTransferMessages->setData( 82 );
1061   mp_actSaveSystemMessages = mp_menuChatSaveSettings->addAction( tr( "Save system messages" ), this, SLOT( settingsChanged() ) );
1062   mp_actSaveSystemMessages->setCheckable( true );
1063   mp_actSaveSystemMessages->setChecked( Settings::instance().chatSaveSystemMessages() );
1064   mp_actSaveSystemMessages->setData( 83 );
1065   mp_menuChatSettings->addSeparator();
1066   act = mp_menuChatSaveSettings->addAction( "", this, SLOT( settingsChanged() ) );
1067   act->setCheckable( true );
1068   act->setData( 84 );
1069   setChatMaxLinesToSaveInAction( act );
1070   mp_menuChatSaveSettings->addSeparator();
1071   act = mp_menuChatSaveSettings->addAction( "", this, SLOT( settingsChanged() ) );
1072   act->setCheckable( true );
1073   act->setData( 85 );
1074   setClearCacheAfterDaysInAction( act );
1075   mp_menuChatSettings->addSeparator();
1076   act = mp_menuChatSettings->addAction( tr( "Open chats in a single window" ), this, SLOT( settingsChanged() ) );
1077   act->setCheckable( true );
1078   act->setChecked( Settings::instance().showChatsInOneWindow() );
1079   act->setData( 7 );
1080   act = mp_menuChatSettings->addAction( tr( "Clear all read messages on closing window" ), this, SLOT( settingsChanged() ) );
1081   act->setCheckable( true );
1082   act->setChecked( Settings::instance().chatClearAllReadMessages() );
1083   act->setData( 47 );
1084   act = mp_menuChatSettings->addAction( tr( "Use high resolution emoticons" ), this, SLOT( settingsChanged() ) );
1085   act->setCheckable( true );
1086   act->setChecked( Settings::instance().useHiResEmoticons() );
1087   act->setData( 105 );
1088 #if QT_VERSION < 0x050000
1089   act->setEnabled( false );
1090 #endif
1091   act = mp_menuChatSettings->addAction( tr( "Use font emoticons" ), this, SLOT( settingsChanged() ) );
1092   act->setCheckable( true );
1093   act->setChecked( Settings::instance().useFontEmoticons() );
1094   act->setData( 31 );
1095   act = mp_menuChatSettings->addAction( tr( "Show chat toolbar" ), this, SLOT( settingsChanged() ) );
1096   act->setCheckable( true );
1097   act->setChecked( Settings::instance().showChatToolbar() );
1098   act->setData( 42 );
1099   mp_menuChatSettings->addSeparator();
1100   act = mp_menuChatSettings->addAction( tr( "Send offline messages also to chat with all users" ), this, SLOT( settingsChanged() ) );
1101   act->setCheckable( true );
1102   act->setChecked( Settings::instance().sendOfflineMessagesToDefaultChat() );
1103   act->setData( 66 );
1104   act = mp_menuChatSettings->addAction( "", this, SLOT( settingsChanged() ) );
1105   act->setCheckable( true );
1106   setChatMessagesToShowInAction( act );
1107   act->setData( 27 );
1108   act = mp_menuChatSettings->addAction( "", this, SLOT( settingsChanged() ) );
1109   act->setCheckable( true );
1110   act->setData( 71 );
1111   setChatInactiveWindowOpacityLevelInAction( act );
1112   mp_menuChatSettings->addSeparator();
1113   QMenu* menu_on_sending_message = mp_menuChatSettings->addMenu( tr( "On sending message" ) + QString( "..." ) );
1114   menu_on_sending_message->setIcon( IconManager::instance().icon( "send.png" ) );
1115   mp_actGroupOnSendingMessage = new QActionGroup( this );
1116   mp_actGroupOnSendingMessage->setExclusive( true );
1117   act = menu_on_sending_message->addAction( tr( "Do nothing" ) + QString( " (%1)" ).arg( tr( "default" ) ) );
1118   act->setCheckable( true );
1119   act->setChecked( Settings::instance().chatOnSendingMessage() == Settings::SkipOnSendingMessage );
1120   act->setData( 91 );
1121   mp_actGroupOnSendingMessage->addAction( act );
1122   act = menu_on_sending_message->addAction( tr( "Minimize chat window" ) );
1123   act->setCheckable( true );
1124   act->setChecked( Settings::instance().chatOnSendingMessage() == Settings::MinimizeChatOnSendingMessage );
1125   act->setData( 92 );
1126   mp_actGroupOnSendingMessage->addAction( act );
1127   act = menu_on_sending_message->addAction( tr( "Close chat window" ) );
1128   act->setCheckable( true );
1129   act->setChecked( Settings::instance().chatOnSendingMessage() == Settings::CloseChatOnSendingMessage );
1130   act->setData( 93 );
1131   mp_actGroupOnSendingMessage->addAction( act );
1132   connect( mp_actGroupOnSendingMessage, SIGNAL( triggered( QAction* ) ), this, SLOT( settingsChanged( QAction* ) ) );
1133   mp_menuChatSettings->addSeparator();
1134   mp_menuChatColorSettings = new QMenu( tr( "Colors" ) + QString( "..." ), this );
1135   mp_menuChatColorSettings->setIcon( IconManager::instance().icon( "colors.png" ) );
1136   mp_menuChatSettings->addMenu( mp_menuChatColorSettings );
1137   act = mp_menuChatColorSettings->addAction( IconManager::instance().icon( "background-color.png" ), tr( "Select chat background color" ), this, SLOT( settingsChanged() ) );
1138   act->setData( 72 );
1139   act = mp_menuChatColorSettings->addAction( IconManager::instance().icon( "font-color.png" ), tr( "Select chat default text color" ), this, SLOT( settingsChanged() ) );
1140   act->setData( 73 );
1141   act = mp_menuChatColorSettings->addAction( IconManager::instance().icon( "log.png" ), tr( "Select chat system text color" ), this, SLOT( settingsChanged() ) );
1142   act->setData( 74 );
1143   act = mp_menuChatColorSettings->addAction( IconManager::instance().icon( "quote-text.png" ), tr( "Select quote text color" ), this, SLOT( settingsChanged() ) );
1144   act->setData( 89 );
1145   act = mp_menuChatColorSettings->addAction( IconManager::instance().icon( "quote-background.png" ), tr( "Select quote background color" ), this, SLOT( settingsChanged() ) );
1146   act->setData( 90 );
1147   mp_actSelectEmoticonSourcePath = mp_menuChatSettings->addAction( IconManager::instance().icon( "emoticon.png" ), tr( "Select emoticon theme" ) + QString( "..." ), this, SLOT( selectEmoticonSourcePath() ) );
1148   mp_actSelectEmoticonSourcePath->setEnabled( !Settings::instance().useFontEmoticons() );
1149   mp_menuChatSettings->addAction( IconManager::instance().icon( "dictionary.png" ), tr( "Dictionary" ) + QString( "..." ), this, SLOT( selectDictionatyPath() ) );
1150   mp_menuChatSettings->addSeparator();
1151   mp_menuChatSettings->addAction( IconManager::instance().icon( "refused-chat.png" ), tr( "Blocked chats" ) + QString( "..." ), this, SLOT( showRefusedChats() ) );
1152 
1153   mp_menuFileTransferSettings = new QMenu( tr( "File transfer" ), this );
1154   mp_menuFileTransferSettings->setIcon( IconManager::instance().icon( "file-transfer.png" ) );
1155   mp_menuFileTransferSettings->setDisabled( Settings::instance().disableFileTransfer() );
1156   mp_menuSettings->addMenu( mp_menuFileTransferSettings );
1157   act = mp_menuFileTransferSettings->addAction( tr( "Enable file transfer" ), this, SLOT( settingsChanged() ) );
1158   act->setCheckable( true );
1159   act->setChecked( Settings::instance().enableFileTransfer() );
1160   act->setData( 12 );
1161   mp_actEnableFileSharing = mp_menuFileTransferSettings->addAction( tr( "Enable file sharing" ), this, SLOT( settingsChanged() ) );
1162   mp_actEnableFileSharing->setCheckable( true );
1163   mp_actEnableFileSharing->setChecked( Settings::instance().enableFileSharing() );
1164   mp_actEnableFileSharing->setData( 5 );
1165   mp_actEnableFileSharing->setDisabled( Settings::instance().disableFileSharing() );
1166   mp_menuFileTransferSettings->addSeparator();
1167   mp_actConfirmDownload = mp_menuFileTransferSettings->addAction( tr( "Prompt before downloading file" ), this, SLOT( settingsChanged() ) );
1168   mp_actConfirmDownload->setCheckable( true );
1169   mp_actConfirmDownload->setChecked( Settings::instance().confirmOnDownloadFile() );
1170   mp_actConfirmDownload->setData( 30 );
1171   act = mp_menuFileTransferSettings->addAction( tr( "Always download files into the folder with the user's name" ), this, SLOT( settingsChanged() ) );
1172   act->setCheckable( true );
1173   act->setChecked( Settings::instance().downloadInUserFolder() );
1174   act->setData( 86 );
1175   mp_menuExistingFile = mp_menuFileTransferSettings->addMenu( tr( "If a file already exists" ) + QString( "..." ) );
1176   mp_actGroupExistingFile = new QActionGroup( this );
1177   mp_actGroupExistingFile->setExclusive( true );
1178   act = mp_menuExistingFile->addAction( tr( "Generate new file name" ) );
1179   act->setCheckable( true );
1180   act->setChecked( true );
1181   act->setData( (int)Settings::GenerateNewFileName );
1182   mp_actGroupExistingFile->addAction( act );
1183   act = mp_menuExistingFile->addAction( tr( "Skip" ) );
1184   act->setCheckable( true );
1185   act->setData( (int)Settings::SkipExistingFile );
1186   mp_actGroupExistingFile->addAction( act );
1187   act = mp_menuExistingFile->addAction( tr( "Overwrite" ) );
1188   act->setCheckable( true );
1189   act->setData( (int)Settings::OverwriteExistingFile );
1190   mp_actGroupExistingFile->addAction( act );
1191   act = mp_menuExistingFile->addAction( tr( "Overwrite older" ) );
1192   act->setCheckable( true );
1193   act->setData( (int)Settings::OverwriteOlderExistingFile );
1194   mp_actGroupExistingFile->addAction( act );
1195   foreach( QAction* act_to_select, mp_actGroupExistingFile->actions() )
1196   {
1197     if( act_to_select->data().toInt() == Settings::instance().onExistingFileAction() )
1198     {
1199       act_to_select->setChecked( true );
1200       break;
1201     }
1202   }
1203   connect( mp_actGroupExistingFile, SIGNAL( triggered( QAction* ) ), this, SLOT( onChangeSettingOnExistingFile( QAction* ) ) );
1204 
1205   act = mp_menuFileTransferSettings->addAction( tr( "Keep the original modification date of the transferred file" ), this, SLOT( settingsChanged() ) );
1206   act->setCheckable( true );
1207   act->setChecked( Settings::instance().keepModificationDateOnFileTransferred() );
1208   act->setData( 101 );
1209   mp_actResumeFileTransfer = mp_menuFileTransferSettings->addAction( tr( "Resume file transfer" ) + QString( " (%1)" ).arg( tr( "when possible" ) ), this, SLOT( settingsChanged() ) );
1210   mp_actResumeFileTransfer->setCheckable( true );
1211   mp_actResumeFileTransfer->setChecked( Settings::instance().resumeFileTransfer() );
1212   mp_actResumeFileTransfer->setData( 97 );
1213   act = mp_menuFileTransferSettings->addAction( "", this, SLOT( settingsChanged() ) );
1214   act->setCheckable( true );
1215   act->setData( 100 );
1216   setClearPartiallyDownloadedFilesAfterDaysInAction( act );
1217   mp_menuFileTransferSettings->addSeparator();
1218   act = mp_menuFileTransferSettings->addAction( "", this, SLOT( settingsChanged() ) );
1219   act->setCheckable( true );
1220   setMaxQueuedDownloadsInAction( act );
1221   act->setData( 88 );
1222   act = mp_menuFileTransferSettings->addAction( tr( "Always shows the progress of file transfer" ), this, SLOT( settingsChanged() ) );
1223   act->setCheckable( true );
1224   act->setChecked( Settings::instance().alwaysShowFileTransferProgress() );
1225   act->setData( 78 );
1226   mp_menuFileTransferSettings->addSeparator();
1227   act = mp_menuFileTransferSettings->addAction( tr( "Use native file dialogs" ), this, SLOT( settingsChanged() ) );
1228   act->setCheckable( true );
1229   act->setChecked( Settings::instance().useNativeDialogs() );
1230   act->setData( 4 );
1231   mp_menuFileTransferSettings->addSeparator();
1232   mp_actSelectDownloadFolder = mp_menuFileTransferSettings->addAction( IconManager::instance().icon( "download-folder.png" ), tr( "Select download folder" ) + QString( "..." ), this, SLOT( selectDownloadDirectory() ) );
1233 
1234 #ifdef BEEBEEP_USE_VOICE_CHAT
1235   mp_menuVoiceMessage = new QMenu( tr( "Voice message" ), this );
1236   mp_menuVoiceMessage->setIcon( IconManager::instance().icon( "microphone.png" ) );
1237   mp_menuVoiceMessage->setDisabled( Settings::instance().disableVoiceMessages() );
1238   mp_menuSettings->addMenu( mp_menuVoiceMessage );
1239   act = mp_menuVoiceMessage->addAction( IconManager::instance().icon( "audio-settings.png" ), tr( "Voice encoder" ) + QString( "..." ), this, SLOT( showVoiceEncoderSettings() ) );
1240   mp_menuVoiceMessage->addSeparator();
1241   act = mp_menuVoiceMessage->addAction( IconManager::instance().icon( "timer.png" ), tr( "Maximum duration" ) + QString( "..." ), this, SLOT( settingsChanged() ) );
1242   act->setData( 94 );
1243   mp_menuVoiceMessage->addSeparator();
1244   act = mp_menuVoiceMessage->addAction( tr( "Use the integrated voice message player" ) + QString( " (beta)" ), this, SLOT( settingsChanged() ) );
1245   act->setCheckable( true );
1246   act->setChecked( Settings::instance().useVoicePlayer() );
1247   act->setData( 95 );
1248 #endif
1249 
1250   mp_menuNotificationSettings = new QMenu( tr( "Notifications" ), this );
1251   mp_menuNotificationSettings->setIcon( IconManager::instance().icon( "bell.png" ) );
1252   mp_menuSettings->addMenu( mp_menuNotificationSettings );
1253   mp_actBeepOnNewMessage = mp_menuNotificationSettings->addAction( tr( "Enable BEEP alert" ), this, SLOT( settingsChanged() ) );
1254   mp_actBeepOnNewMessage->setCheckable( true );
1255   mp_actBeepOnNewMessage->setChecked( Settings::instance().beepOnNewMessageArrived() );
1256   mp_actBeepOnNewMessage->setData( 34 );
1257   act = mp_menuNotificationSettings->addAction( tr( "Enable Buzz sound" ), this, SLOT( settingsChanged() ) );
1258   act->setCheckable( true );
1259   act->setChecked( Settings::instance().playBuzzSound() );
1260   act->setData( 56 );
1261   act = mp_menuNotificationSettings->addAction( tr( "Enable notifications also for chat with all users" ), this, SLOT( settingsChanged() ) );
1262   act->setCheckable( true );
1263   act->setChecked( Settings::instance().enableDefaultChatNotifications() );
1264   act->setData( 75 );
1265   act = mp_menuNotificationSettings->addAction( tr( "Enable BEEP alert also for active chat windows" ), this, SLOT( settingsChanged() ) );
1266   act->setCheckable( true );
1267   act->setChecked( Settings::instance().beepInActiveWindowAlso() );
1268   act->setData( 98 );
1269   act = mp_menuNotificationSettings->addAction( tr( "Disable BEEP alert if your status is busy" ), this, SLOT( settingsChanged() ) );
1270   act->setCheckable( true );
1271   act->setChecked( Settings::instance().disableBeepInUserStatusBusy() );
1272   act->setData( 96 );
1273   mp_menuNotificationSettings->addSeparator();
1274   act = mp_menuNotificationSettings->addAction( tr( "Raise main window on new message" ), this, SLOT( settingsChanged() ) );
1275   act->setCheckable( true );
1276   act->setChecked( Settings::instance().raiseMainWindowOnNewMessageArrived() );
1277   act->setData( 80 );
1278   act = mp_menuNotificationSettings->addAction( tr( "Always open chat on new message" ), this, SLOT( settingsChanged() ) );
1279   act->setCheckable( true );
1280   act->setChecked( Settings::instance().alwaysOpenChatOnNewMessageArrived() );
1281   act->setData( 70 );
1282   act = mp_menuNotificationSettings->addAction( tr( "Raise previously opened chat on new message" ), this, SLOT( settingsChanged() ) );
1283   act->setCheckable( true );
1284   act->setChecked( Settings::instance().raiseOnNewMessageArrived() );
1285   act->setData( 15 );
1286   mp_menuNotificationSettings->addSeparator();
1287   mp_menuTrayIconSettings = new QMenu( tr( "System tray icon" ), this );
1288   mp_menuTrayIconSettings->setIcon( IconManager::instance().icon( "settings-tray-icon.png" ) );
1289   mp_menuNotificationSettings->addMenu( mp_menuTrayIconSettings );
1290   act = mp_menuTrayIconSettings->addAction( tr( "Enable tray icon notifications" ), this, SLOT( settingsChanged() ) );
1291   act->setCheckable( true );
1292   act->setChecked( Settings::instance().showNotificationOnTray()  );
1293   act->setData( 19 );
1294   act = mp_menuTrayIconSettings->addAction( tr( "Show only message notifications" ), this, SLOT( settingsChanged() ) );
1295   act->setCheckable( true );
1296   act->setChecked( Settings::instance().showOnlyMessageNotificationOnTray()  );
1297   act->setData( 40 );
1298   act = mp_menuTrayIconSettings->addAction( tr( "Show chat message preview" ), this, SLOT( settingsChanged() ) );
1299   act->setCheckable( true );
1300   act->setChecked( Settings::instance().showChatMessageOnTray() );
1301   act->setData( 46 );
1302   act = mp_menuTrayIconSettings->addAction( tr( "Show file notifications" ), this, SLOT( settingsChanged() ) );
1303   act->setCheckable( true );
1304   act->setChecked( Settings::instance().showFileTransferCompletedOnTray() );
1305   act->setData( 48 );
1306   mp_menuNotificationSettings->addSeparator();
1307   mp_menuNotificationSettings->addAction( IconManager::instance().icon( "file-beep.png" ), tr( "Select beep file..." ), this, SLOT( selectBeepFile() ) );
1308   mp_menuNotificationSettings->addAction( IconManager::instance().icon( "play.png" ), tr( "Play beep" ), this, SLOT( testBeepFile() ) );
1309 
1310 #ifdef BEEBEEP_USE_SHAREDESKTOP
1311   QMenu* menu_share_desktop = new QMenu( tr( "Desktop sharing" ), this );
1312   menu_share_desktop->setIcon( IconManager::instance().icon( "desktop-share.png" ) );
1313   menu_share_desktop->setDisabled( Settings::instance().disableDesktopSharing() );
1314   mp_menuSettings->addMenu( menu_share_desktop );
1315   act = menu_share_desktop->addAction( tr( "Enable desktop sharing" ), this, SLOT( settingsChanged() ) );
1316   act->setCheckable( true );
1317   act->setChecked( Settings::instance().enableShareDesktop() );
1318   act->setData( 60 );
1319   menu_share_desktop->addSeparator();
1320   act = menu_share_desktop->addAction( IconManager::instance().icon( "timer.png" ), tr( "Select screen capture interval" ) + QString( "..." ), this, SLOT( settingsChanged() ) );
1321   act->setData( 61 );
1322   act = menu_share_desktop->addAction( IconManager::instance().icon( "image-type.png" ), tr( "Select image type" ) + QString( "..." ), this, SLOT( settingsChanged() ) );
1323   act->setData( 62 );
1324   act = menu_share_desktop->addAction( IconManager::instance().icon( "image-quality.png" ), tr( "Select image quality" ) + QString( "..." ), this, SLOT( settingsChanged() ) );
1325   act->setData( 63 );
1326   menu_share_desktop->addSeparator();
1327   act = menu_share_desktop->addAction( tr( "Fit image to screen" ), this, SLOT( settingsChanged() ) );
1328   act->setCheckable( true );
1329   act->setChecked( Settings::instance().shareDesktopFitToScreen() );
1330   act->setData( 64 );
1331 #endif
1332 
1333   mp_menuSettings->addSeparator();
1334   act = mp_menuSettings->addAction( tr( "Always stay on top" ), this, SLOT( settingsChanged() ) );
1335   act->setCheckable( true );
1336   act->setChecked( Settings::instance().stayOnTop() );
1337   act->setData( 14 );
1338 #ifdef Q_OS_WIN
1339   act = mp_menuSettings->addAction( tr( "Start %1 automatically" ).arg( Settings::instance().programName() ), this, SLOT( settingsChanged() ) );
1340   act->setCheckable( true );
1341   act->setChecked( Settings::instance().hasStartOnSystemBoot() );
1342   act->setData( 16 );
1343 #endif
1344   mp_actSaveWindowGeometry = mp_menuSettings->addAction( IconManager::instance().icon( "save-window.png" ), tr( "Save window's geometry" ), this, SLOT( askSaveGeometryAndState() ) );
1345   mp_actSaveWindowGeometry->setDisabled( Settings::instance().resetGeometryAtStartup() );
1346 
1347   /* User List Menu */
1348   mp_menuUserList = new QMenu( tr( "Options" ), this );
1349   act = mp_menuUserList->addAction( tr( "Sort users in ascending order" ), this, SLOT( settingsChanged() ) );
1350   act->setCheckable( true );
1351   act->setChecked( Settings::instance().sortUsersAscending() );
1352   act->setData( 49 );
1353   QMenu* sorting_users_menu = mp_menuUserList->addMenu( tr( "Sorting mode" ) + QString( "..." ) );
1354   QActionGroup* sorting_users_action_group = new QActionGroup( this );
1355   sorting_users_action_group->setExclusive( true );
1356   act = sorting_users_menu->addAction( tr( "Default mode" ) );
1357   act->setCheckable( true );
1358   act->setChecked( Settings::instance().userSortingMode() < 1 || Settings::instance().userSortingMode() > 3 );
1359   act->setData( 50 );
1360   sorting_users_action_group->addAction( act );
1361   act = sorting_users_menu->addAction( tr( "By user name" ) );
1362   act->setCheckable( true );
1363   act->setChecked( Settings::instance().userSortingMode() == 1 );
1364   act->setData( 51 );
1365   sorting_users_action_group->addAction( act );
1366   act = sorting_users_menu->addAction( tr( "By user status" ) );
1367   act->setCheckable( true );
1368   act->setChecked( Settings::instance().userSortingMode() == 2 );
1369   act->setData( 52 );
1370   sorting_users_action_group->addAction( act );
1371   act = sorting_users_menu->addAction( tr( "By unread messages" ) );
1372   act->setCheckable( true );
1373   act->setChecked( Settings::instance().userSortingMode() == 3 );
1374   act->setData( 53 );
1375   sorting_users_action_group->addAction( act );
1376   connect( sorting_users_action_group, SIGNAL( triggered( QAction* ) ), this, SLOT( settingsChanged( QAction* ) ) );
1377   mp_menuUserList->addSeparator();
1378   mp_actShowOnlineUsersOnly = mp_menuUserList->addAction( tr( "Show online users only" ), this, SLOT( settingsChanged() ) );
1379   mp_actShowOnlineUsersOnly->setCheckable( true );
1380   mp_actShowOnlineUsersOnly->setChecked( Settings::instance().showOnlyOnlineUsers() );
1381   mp_actShowOnlineUsersOnly->setData( 6 );
1382   act = mp_menuUserList->addAction( tr( "Show users in their workgroups" ), this, SLOT( settingsChanged() ) );
1383   act->setCheckable( true );
1384   act->setChecked( Settings::instance().showUsersInWorkgroups() );
1385   act->setData( 87 );
1386   if( mp_actShowUserFullName->isChecked() )
1387     mp_menuUserList->addAction( mp_actShowUserFullName );
1388   mp_menuUserList->addAction( mp_actShowUserFirstNameFirstInFullName );
1389   mp_menuUserList->addSeparator();
1390   act = mp_menuUserList->addAction( tr( "Show the user's picture" ), this, SLOT( settingsChanged() ) );
1391   act->setCheckable( true );
1392   act->setChecked( Settings::instance().showUserPhoto() );
1393   act->setData( 21 );
1394   act = mp_menuUserList->addAction( tr( "Show the user's vCard on right click" ), this, SLOT( settingsChanged() ) );
1395   act->setCheckable( true );
1396   act->setChecked( Settings::instance().showVCardOnRightClick() );
1397   act->setData( 25 );
1398   act = mp_menuUserList->addAction( tr( "Show status color in background" ), this, SLOT( settingsChanged() ) );
1399   act->setCheckable( true );
1400   act->setChecked( Settings::instance().showUserStatusBackgroundColor() );
1401   act->setData( 38 );
1402   act = mp_menuUserList->addAction( tr( "Show the status description" ), this, SLOT( settingsChanged() ) );
1403   act->setCheckable( true );
1404   act->setChecked( Settings::instance().showUserStatusDescription() );
1405   act->setData( 37 );
1406   mp_menuUserList->addSeparator();
1407   mp_actEditAvatarIconSize = mp_menuUserList->addAction( IconManager::instance().icon( "icon-size.png" ), tr( "Change size of the user's picture" ), this, SLOT( changeAvatarSizeInList() ) );
1408   mp_userList->setMenuSettings( mp_menuUserList );
1409 
1410   /* Status Menu */
1411   mp_menuStatus = new QMenu( tr( "Status" ), this );
1412   mp_menuStatus->setIcon( IconManager::instance().icon( "user-status.png" ) );
1413   for( int i = User::Online; i < User::NumStatus; i++ )
1414   {
1415     act = mp_menuStatus->addAction( QIcon( Bee::menuUserStatusIconFileName( i ) ), Bee::userStatusToString( i ), this, SLOT( statusSelected() ) );
1416     act->setData( i );
1417     act->setIconVisibleInMenu( true );
1418   }
1419   mp_menuStatus->addSeparator();
1420   mp_actSetAutoAway = mp_menuStatus->addAction( tr( "Set your status to away automatically" ), this, SLOT( settingsChanged() ) );
1421   mp_actSetAutoAway->setCheckable( true );
1422   mp_actSetAutoAway->setChecked( Settings::instance().autoUserAway() );
1423   mp_actSetAutoAway->setData( 20 );
1424   mp_menuStatus->addSeparator();
1425   mp_menuUserStatusList = new QMenu( tr( "Recently used" ), this );
1426   act = mp_menuStatus->addMenu( mp_menuUserStatusList );
1427   act->setIcon( IconManager::instance().icon( "recent.png" ) );
1428   loadUserStatusRecentlyUsed();
1429   mp_actChangeStatusDescription = mp_menuStatus->addAction( IconManager::instance().icon( "user-status.png" ), tr( "Change your status description..." ), this, SLOT( changeStatusDescription() ) );
1430   mp_menuStatus->addAction( IconManager::instance().icon( "clear.png" ), tr( "Clear all status descriptions" ), this, SLOT( clearRecentlyUsedUserStatus() ) );
1431   mp_menuStatus->addSeparator();
1432   mp_menuStatus->addAction( mp_actEditWorkgroups );
1433   mp_menuStatus->addSeparator();
1434   act = mp_menuStatus->addAction( QIcon( Bee::menuUserStatusIconFileName( User::Offline ) ), Bee::userStatusToString( User::Offline ), this, SLOT( statusSelected() ) );
1435   act->setData( User::Offline );
1436   act->setIconVisibleInMenu( true );
1437   act = mp_menuStatus->menuAction();
1438   connect( act, SIGNAL( triggered() ), this, SLOT( showLocalUserVCard() ) );
1439 
1440   /* Context Menu for user list view */
1441   QMenu* context_menu_users = new QMenu( "Menu", this );
1442   if( mp_actShowUserFullName->isChecked() )
1443     context_menu_users->addAction( mp_actShowUserFullName );
1444   context_menu_users->addAction( mp_actShowUserFirstNameFirstInFullName );
1445   context_menu_users->addSeparator();
1446   context_menu_users->addAction( mp_actVCard );
1447   context_menu_users->addAction( mp_actChangeStatusDescription );
1448   context_menu_users->addSeparator();
1449   context_menu_users->addAction( mp_actSetAutoAway );
1450   context_menu_users->addSeparator();
1451   context_menu_users->addAction( mp_actConfigureNetwork );
1452   context_menu_users->addAction( mp_actAddUsers );
1453   context_menu_users->addSeparator();
1454   context_menu_users->addAction( mp_actEditAvatarIconSize );
1455   context_menu_users->addSeparator();
1456   context_menu_users->addAction( mp_actShowOnlineUsersOnly );
1457   mp_userList->setContextMenuUsers( context_menu_users );
1458 
1459   /* Help Menu */
1460   mp_menuInfo = new QMenu( tr("?" ), this );
1461   mp_menuInfo->addAction( IconManager::instance().icon( "donate.png" ), tr( "Donate for %1" ).arg( Settings::instance().programName() ) + QString( "..." ), this, SLOT( openDonationPage() ) );
1462   mp_menuInfo->addSeparator();
1463   mp_menuInfo->addAction( mp_actAbout );
1464   mp_menuInfo->addAction( IconManager::instance().icon( "license.png" ), tr( "Show %1's license..." ).arg( Settings::instance().programName() ), this, SLOT( showLicense() ) );
1465   act = mp_menuInfo->addAction( IconManager::instance().icon( "qt.png" ), tr( "Qt Library..." ), this, SLOT( showAboutQt() ) );
1466   act->setMenuRole( QAction::AboutQtRole );
1467   mp_menuInfo->addSeparator();
1468   mp_menuInfo->addAction( IconManager::instance().icon( "beebeep.png" ), tr( "Open %1 official website..." ).arg( Settings::instance().programName() ), this, SLOT( openWebSite() ) );
1469   mp_menuInfo->addAction( IconManager::instance().icon( "update.png" ), tr( "Check for new version..." ), this, SLOT( checkNewVersion() ) );
1470   mp_menuInfo->addAction( IconManager::instance().icon( "plugin.png" ), tr( "Download plugins..." ), this, SLOT( openDownloadPluginPage() ) );
1471   mp_menuInfo->addSeparator();
1472   mp_menuInfo->addAction( IconManager::instance().icon( "info.png" ), tr( "Help online..." ), this, SLOT( openHelpPage() ) );
1473   mp_menuInfo->addAction( IconManager::instance().icon( "tip.png" ), tr( "Show tips..." ), this, SLOT( showTipOfTheDay() ) );
1474   mp_menuInfo->addAction( IconManager::instance().icon( "chat-small.png" ), tr( "Read FAQ..." ), this, SLOT( showFaq() ) );
1475   mp_menuInfo->addAction( IconManager::instance().icon( "fact.png" ), tr( "Discover the fact of the day..." ), this, SLOT( showFactOfTheDay() ) );
1476   mp_menuInfo->addSeparator();
1477   mp_menuInfo->addAction( IconManager::instance().icon( "star.png" ), tr( "Information about %1..." ).arg( "Marco Mastroddi" ), this, SLOT( openDeveloperWebSite() ) );
1478 #ifdef BEEBEEP_DEBUG
1479   mp_menuInfo->addSeparator();
1480   act = mp_menuInfo->addAction( tr( "Add +1 user to anonymous usage statistics" ), this, SLOT( settingsChanged() ) );
1481   act->setCheckable( true );
1482   act->setChecked( Settings::instance().postUsageStatistics() );
1483   act->setData( 44 );
1484 #endif
1485 
1486   /* Tray icon menu */
1487   mp_menuTrayIcon = new QMenu( this );
1488   act = mp_menuTrayIcon->addAction( IconManager::instance().icon( "beebeep.png" ), tr( "Show" ), this, SLOT( showUp() ) );
1489   mp_menuTrayIcon->setDefaultAction( act );
1490   mp_menuTrayIcon->addSeparator();
1491   mp_menuTrayIcon->addAction( mp_menuStatus->menuAction() );
1492   mp_menuTrayIcon->addSeparator();
1493   mp_menuTrayIcon->addAction( mp_actViewNewMessage );
1494   mp_menuTrayIcon->addSeparator();
1495   mp_menuTrayIcon->addAction( IconManager::instance().icon( "quit.png" ), tr( "Quit" ), this, SLOT( forceShutdown() ) );
1496 
1497   mp_trayIcon->setContextMenu( mp_menuTrayIcon );
1498 }
1499 
createToolAndMenuBars()1500 void GuiMain::createToolAndMenuBars()
1501 {
1502   menuBar()->addMenu( mp_menuMain );
1503   if( Settings::instance().disableMenuSettings() )
1504     mp_menuSettings->setDisabled( true );
1505   menuBar()->addMenu( mp_menuSettings );
1506   menuBar()->addMenu( mp_menuInfo );
1507   QLabel *label_version = new QLabel( this );
1508   label_version->setTextFormat( Qt::RichText );
1509   label_version->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
1510   QString label_version_text = QString( "&nbsp;&nbsp;<b>%1%2</b> %3&nbsp;" )
1511                                 .arg( Settings::instance().version( Settings::instance().isDevelopmentVersion(), false, false ) )
1512                                 .arg( Settings::instance().isDevelopmentVersion() ? QString( "-dev" ) : "" )
1513                                 .arg( IconManager::instance().toHtml( Settings::instance().operatingSystemIconPath(), "*", 12, 12 ) );
1514                                 label_version->setText( label_version_text );
1515   label_version->setToolTip( QString( "BeeBEEP %1 %2%3" ).arg( Settings::instance().version( true, true, true ), Settings::instance().operatingSystem( true ),
1516                                                                Settings::instance().isDevelopmentVersion() ? QString( " (%1)" ).arg( tr("Development version") ) : "" ) );
1517   menuBar()->setCornerWidget( label_version );
1518 
1519   mp_barMain->addAction( mp_menuStatus->menuAction() );
1520   mp_barMain->addAction( mp_actVCard );
1521   mp_barMain->addSeparator();
1522   mp_barMain->addAction( mp_actBroadcast );
1523   mp_barMain->addSeparator();
1524   mp_barMain->addAction( mp_actViewNewMessage );
1525   mp_barMain->addAction( mp_actCreateMessage );
1526   mp_barMain->addAction( mp_actCreateGroupChat );
1527   mp_barMain->addSeparator();
1528   mp_barMain->addAction( mp_actViewFileTransfer );
1529   mp_barMain->addAction( mp_actViewFileSharing );
1530 }
1531 
createMainWidgets()1532 void GuiMain::createMainWidgets()
1533 {
1534   int tab_index;
1535   QString tooltip_right_button = tr( "Right click to open menu" );
1536 
1537   mp_home = new GuiHome( this );
1538   connect( mp_home, SIGNAL( openUrlRequest( const QUrl& ) ), this, SLOT( openUrl( const QUrl& ) ) );
1539   connect( mp_home, SIGNAL( clearSystemMessagesRequest( VNumber ) ), this, SLOT( clearSystemMessagesInChat( VNumber ) ) );
1540   tab_index = mp_tabMain->addTab( mp_home, IconManager::instance().icon( "activities.png" ), "" );
1541   mp_tabMain->setTabToolTip( tab_index, tr( "Activities" ) );
1542   mp_home->setMainToolTip( QString( "%1\n(%2)" ).arg( mp_tabMain->tabToolTip( tab_index ), tooltip_right_button ) );
1543 
1544   mp_userList = new GuiUserList( this );
1545   tab_index = mp_tabMain->addTab( mp_userList, IconManager::instance().icon( "user-list.png" ), "" );
1546   mp_tabMain->setTabToolTip( tab_index, tr( "Users" ) );
1547   mp_userList->setMainToolTip( QString( "%1\n(%2)" ).arg( mp_tabMain->tabToolTip( tab_index ), tooltip_right_button ) );
1548 
1549   mp_chatList = new GuiChatList( this );
1550   tab_index = mp_tabMain->addTab( mp_chatList, IconManager::instance().icon( "chat-list.png" ), "" );
1551   mp_tabMain->setTabToolTip( tab_index, tr( "Chats" ) );
1552   mp_chatList->setMainToolTip( QString( "%1\n(%2)" ).arg( mp_tabMain->tabToolTip( tab_index ), tooltip_right_button ) );
1553 
1554   mp_groupList = new GuiGroupList( this );
1555   tab_index = mp_tabMain->addTab( mp_groupList, IconManager::instance().icon( "group.png" ), "" );
1556   mp_tabMain->setTabToolTip( tab_index, tr( "Groups" ) );
1557   mp_groupList->setMainToolTip( QString( "%1\n(%2)" ).arg( mp_tabMain->tabToolTip( tab_index ), tooltip_right_button ) );
1558 
1559   mp_savedChatList = new GuiSavedChatList( this );
1560   tab_index = mp_tabMain->addTab( mp_savedChatList, IconManager::instance().icon( "saved-chat-list.png" ), "" );
1561   mp_tabMain->setTabToolTip( tab_index, tr( "Saved chats" ) );
1562   mp_savedChatList->setMainToolTip( QString( "%1\n(%2)" ).arg( mp_tabMain->tabToolTip( tab_index ), tooltip_right_button ) );
1563 
1564 #ifdef BEEBEEP_USE_WEBENGINE
1565   mp_webView = new GuiWebView();
1566   connect( mp_webView, SIGNAL( newsLoadFinished( bool ) ), this, SLOT( onNewsLoad( bool ) ) );
1567 #endif
1568 
1569   mp_dockFileTransfers = new QDockWidget( tr( "File Transfers" ), this );
1570   mp_dockFileTransfers->setObjectName( "GuiFileTransferDock" );
1571   mp_fileTransfer = new GuiFileTransfer( this );
1572   mp_dockFileTransfers->setWidget( mp_fileTransfer );
1573   mp_dockFileTransfers->setAllowedAreas( Qt::AllDockWidgetAreas );
1574   addDockWidget( Qt::BottomDockWidgetArea, mp_dockFileTransfers );
1575   mp_actViewFileTransfer = mp_dockFileTransfers->toggleViewAction();
1576   mp_actViewFileTransfer->setIcon( IconManager::instance().icon( "file-transfer.png" ) );
1577   mp_actViewFileTransfer->setText( tr( "Show the file transfer panel" ) );
1578   mp_actViewFileTransfer->setData( 99 );
1579   mp_dockFileTransfers->hide();
1580 }
1581 
startExternalApplicationFromActionData()1582 void GuiMain::startExternalApplicationFromActionData()
1583 {
1584   QAction* act = qobject_cast<QAction*>( sender() );
1585   if( !act )
1586     return;
1587 
1588   QString application_path = act->data().toString();
1589   qDebug() << "Starting external application:" << qPrintable( application_path );
1590   if( !QDesktopServices::openUrl( QUrl::fromLocalFile( application_path ) ) )
1591     QMessageBox::information( qApp->activeWindow(), Settings::instance().programName(), tr( "Unable to open %1" ).arg( application_path ), tr( "Ok" ) );
1592 }
1593 
settingsChanged()1594 void GuiMain::settingsChanged()
1595 {
1596   QAction* act = qobject_cast<QAction*>( sender() );
1597   if( act )
1598     settingsChanged( act );
1599 }
1600 
settingsChanged(QAction * act)1601 void GuiMain::settingsChanged( QAction* act )
1602 {
1603   bool refresh_users = false;
1604   bool refresh_chat = false;
1605   int settings_data_id = act->data().toInt();
1606   bool ok = false;
1607 
1608 #ifdef BEEBEEP_DEBUG
1609   if( act->isCheckable() )
1610     qDebug() << "Settings changed for action id" << settings_data_id << "to" << static_cast<int>(act->isChecked());
1611 #endif
1612 
1613   switch( settings_data_id )
1614   {
1615   case 1:
1616     Settings::instance().setChatCompact( act->isChecked() );
1617     refresh_chat = true;
1618     break;
1619   case 2:
1620     Settings::instance().setSaveGroupList( act->isChecked() );
1621     break;
1622   case 3:
1623     Settings::instance().setChatShowMessageTimestamp( act->isChecked() );
1624     refresh_chat = true;
1625     break;
1626   case 4:
1627     Settings::instance().setUseNativeDialogs( act->isChecked() );
1628     break;
1629   case 5:
1630     setFileSharingEnabled( act->isChecked() );
1631     break;
1632   case 6:
1633     Settings::instance().setShowOnlyOnlineUsers( act->isChecked() );
1634     refresh_users = true;
1635     refresh_chat = true;
1636     break;
1637   case 7:
1638     {
1639       Settings::instance().setShowChatsInOneWindow( act->isChecked() );
1640       if( Settings::instance().showChatsInOneWindow() )
1641       {
1642         foreach( GuiFloatingChat* fl_chat, m_floatingChats )
1643           fl_chat->close();
1644       }
1645     }
1646     break;
1647   case 8:
1648     Settings::instance().setChatUseHtmlTags( act->isChecked() );
1649     refresh_chat = true;
1650     break;
1651   case 9:
1652     Settings::instance().setChatUseClickableLinks( act->isChecked() );
1653     refresh_chat = true;
1654     break;
1655   case 10:
1656     Settings::instance().setShowEmoticons( act->isChecked() );
1657     refresh_chat = true;
1658     break;
1659   case 11:
1660     Settings::instance().setCloseMinimizeInTray( act->isChecked() );
1661     break;
1662   case 12:
1663     setFileTransferEnabled( act->isChecked() );
1664     break;
1665   case 13:
1666     Settings::instance().setShowMessagesGroupByUser( act->isChecked() );
1667     refresh_chat = true;
1668     break;
1669   case 14:
1670     {
1671       Settings::instance().setStayOnTop( act->isChecked() );
1672       Bee::setWindowStaysOnTop( this, act->isChecked() );
1673       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
1674         Bee::setWindowStaysOnTop( fl_chat, act->isChecked() );
1675       if( mp_fileSharing )
1676         Bee::setWindowStaysOnTop( mp_fileSharing, act->isChecked() );
1677       if( mp_log )
1678         Bee::setWindowStaysOnTop( mp_log, act->isChecked() );
1679       if( mp_screenShot )
1680         Bee::setWindowStaysOnTop( mp_screenShot, act->isChecked() );
1681       if( mp_networkTest )
1682         Bee::setWindowStaysOnTop( mp_networkTest, act->isChecked() );
1683     }
1684     break;
1685   case 15:
1686     Settings::instance().setRaiseOnNewMessageArrived( act->isChecked() );
1687     break;
1688   case 16:
1689     checkAutoStartOnBoot( act->isChecked() );
1690     break;
1691   case 17:
1692     {
1693       if( !act->isChecked() )
1694       {
1695         Settings::instance().setAskPasswordAtStartup( false );
1696         if( Settings::instance().askPassword() )
1697         {
1698           QMessageBox::information( this, Settings::instance().programName(), tr( "Please save the network password in the next dialog if you want to use password without prompt." ) );
1699           promptConnectionPassword();
1700           return;
1701         }
1702       }
1703       else
1704         Settings::instance().setAskPasswordAtStartup( true );
1705     }
1706     break;
1707   case 18:
1708     {
1709       Settings::instance().setChatAutoSave( act->isChecked() );
1710       if( !Settings::instance().chatAutoSave() && (Settings::instance().chatSaveFileTransfers() || !Settings::instance().chatSaveSystemMessages()) )
1711       {
1712         if( QMessageBox::warning( this, Settings::instance().programName(),
1713                                tr( "There will be no saving of 'system' and 'file transfer' messages if this option is disabled." ),
1714                                tr( "Ok" ), tr( "Cancel" ), QString(), 0, 1 ) )
1715         {
1716           Settings::instance().setChatSaveFileTransfers( false );
1717           Settings::instance().setChatSaveSystemMessages( false );
1718           mp_actSaveFileTransferMessages->setChecked( false );
1719           mp_actSaveSystemMessages->setChecked( false );
1720         }
1721       }
1722     }
1723     break;
1724   case 19:
1725     Settings::instance().setShowNotificationOnTray( act->isChecked() );
1726     break;
1727   case 20:
1728     {
1729       Settings::instance().setAutoUserAway( act->isChecked() );
1730       if( act->isChecked() )
1731       {
1732         int away_timeout = QInputDialog::getInt( this, Settings::instance().programName(),
1733                               tr( "How many minutes of idle %1 can wait before changing status to away?" ).arg( Settings::instance().programName() ),
1734                               Settings::instance().userAwayTimeout(), 1, 30, 1, &ok );
1735         if( ok && away_timeout > 0 )
1736           Settings::instance().setUserAwayTimeout( away_timeout );
1737 
1738         if( beeApp )
1739           beeApp->setIdleTimeout( Settings::instance().userAwayTimeout() );
1740       }
1741     }
1742     break;
1743   case 21:
1744     Settings::instance().setShowUserPhoto( act->isChecked() );
1745     refresh_users = true;
1746     break;
1747   case 23:
1748     {
1749       Settings::instance().setChatFont( QApplication::font() );
1750       updateChatFont();
1751     }
1752     break;
1753   case 24:
1754     Settings::instance().setLoadOnTrayAtStartup( act->isChecked() );
1755     break;
1756   case 25:
1757     Settings::instance().setShowVCardOnRightClick( act->isChecked() );
1758     break;
1759   case 26:
1760     {
1761       Settings::instance().setResetGeometryAtStartup( act->isChecked() );
1762       mp_actSaveWindowGeometry->setDisabled( Settings::instance().resetGeometryAtStartup() );
1763       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
1764         fl_chat->setSaveGeometryDisabled( Settings::instance().resetGeometryAtStartup() );
1765     }
1766     break;
1767   case 27:
1768     {
1769 #if QT_VERSION >= 0x050000
1770       int num_messages = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
1771 #else
1772       int num_messages = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
1773 #endif
1774                                                    tr( "Please select the maximum number of messages to be showed" ) + QString( "\n" )
1775                                                    + tr( "(current: %1, default: %2, all: -1, none: 0)" )
1776                                                        .arg( Settings::instance().chatMessagesToShow() )
1777                                                        .arg( Settings::instance().defaultChatMessagesToShow() ),
1778                                                    Settings::instance().chatMessagesToShow(),
1779                                                    -1, 2000, 10, &ok );
1780       if( ok )
1781       {
1782         Settings::instance().setChatMessagesToShow( num_messages );
1783         refresh_chat = true;
1784       }
1785       setChatMessagesToShowInAction( act );
1786     }
1787     break;
1788   case 28:
1789     {
1790       Settings::instance().setEnableMaximizeButton( act->isChecked() );
1791       if( Settings::instance().enableMaximizeButton() )
1792         setWindowFlags( windowFlags() | Qt::WindowMaximizeButtonHint );
1793       else
1794         setWindowFlags( windowFlags() & ~Qt::WindowMaximizeButtonHint );
1795       if( !isVisible() )
1796         show();
1797     }
1798     break;
1799   case 29:
1800     Settings::instance().setKeyEscapeMinimizeInTray( act->isChecked() );
1801     break;
1802   case 30:
1803     Settings::instance().setConfirmOnDownloadFile( act->isChecked() );
1804     break;
1805   case 31:
1806     Settings::instance().setUseFontEmoticons( act->isChecked() );
1807     mp_actSelectEmoticonSourcePath->setEnabled( !act->isChecked() );
1808     updateEmoticons();
1809     refresh_chat = true;
1810     break;
1811   case 32:
1812     Settings::instance().setSaveUserList( act->isChecked() );
1813     mp_actRemoveInactiveUsers->setEnabled( act->isChecked() );
1814     break;
1815   case 33:
1816     {
1817       Settings::instance().setRemoveInactiveUsers( act->isChecked() );
1818       if( act->isChecked() )
1819       {
1820 #if QT_VERSION >= 0x050000
1821         int num_days = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
1822 #else
1823         int num_days = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
1824 #endif
1825                                                      tr( "Please select the number of inactive days before user is removed" ),
1826                                                      Settings::instance().maxDaysOfUserInactivity(),
1827                                                      2, 365, 5, &ok );
1828         if( ok )
1829         {
1830           Settings::instance().setMaxDaysOfUserInactivity( num_days );
1831           setMaxInactivityDaysInAction( act );
1832         }
1833       }
1834     }
1835     break;
1836   case 34:
1837     Settings::instance().setBeepOnNewMessageArrived( act->isChecked() );
1838     break;
1839   case 35:
1840     Settings::instance().setShowMinimizedAtStartup( act->isChecked() );
1841     break;
1842   case 36:
1843     Settings::instance().setPromptOnCloseEvent( act->isChecked() );
1844     break;
1845   case 37:
1846     Settings::instance().setShowUserStatusDescription( act->isChecked() );
1847     refresh_users = true;
1848     break;
1849   case 38:
1850     Settings::instance().setShowUserStatusBackgroundColor( act->isChecked() );
1851     refresh_users = true;
1852     break;
1853   case 39:
1854     Settings::instance().setUseShortcuts( act->isChecked() );
1855     break;
1856   case 40:
1857     Settings::instance().setShowOnlyMessageNotificationOnTray( act->isChecked() );
1858     break;
1859   case 41:
1860     Settings::instance().setChatUseYourNameInsteadOfYou( act->isChecked() );
1861     refresh_chat = true;
1862     break;
1863   case 42:
1864     {
1865       Settings::instance().setShowChatToolbar( act->isChecked() );
1866       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
1867         fl_chat->setChatToolbarVisible( Settings::instance().showChatToolbar() );
1868     }
1869     break;
1870   case 43:
1871     Settings::instance().setCheckNewVersionAtStartup( act->isChecked() );
1872     break;
1873   case 44:
1874     Settings::instance().setPostUsageStatistics( act->isChecked() );
1875     break;
1876   case 45:
1877     Settings::instance().setAskChangeUserAtStartup( act->isChecked() );
1878     break;
1879   case 46:
1880     Settings::instance().setShowChatMessageOnTray( act->isChecked() );
1881     break;
1882   case 47:
1883     Settings::instance().setChatClearAllReadMessages( act->isChecked() );
1884     break;
1885   case 48:
1886     Settings::instance().setShowFileTransferCompletedOnTray( act->isChecked() );
1887     break;
1888   case 49:
1889     Settings::instance().setSortUsersAscending( act->isChecked() );
1890     refresh_users = true;
1891     break;
1892   case 50:
1893     Settings::instance().setUserSortingMode( 0 );
1894     refresh_users = true;
1895     break;
1896   case 51:
1897     Settings::instance().setUserSortingMode( 1 );
1898     refresh_users = true;
1899     break;
1900   case 52:
1901     Settings::instance().setUserSortingMode( 2 );
1902     refresh_users = true;
1903     break;
1904   case 53:
1905     Settings::instance().setUserSortingMode( 3 );
1906     refresh_users = true;
1907     break;
1908   case 54:
1909     Settings::instance().setShowPresetMessages( act->isChecked() );
1910     break;
1911   case 55:
1912     Settings::instance().setShowTextInModeRTL( act->isChecked() );
1913     refresh_chat = true;
1914     break;
1915   case 56:
1916     Settings::instance().setPlayBuzzSound( act->isChecked() );
1917     break;
1918   case 57:
1919     Settings::instance().setUserRecognitionMethod( Settings::RecognizeByAccountAndDomain );
1920     showRestartConnectionAlertMessage();
1921     break;
1922   case 58:
1923     Settings::instance().setUserRecognitionMethod( Settings::RecognizeByAccount );
1924     showRestartConnectionAlertMessage();
1925 
1926     break;
1927   case 59:
1928     Settings::instance().setUserRecognitionMethod( Settings::RecognizeByNickname );
1929     showRestartConnectionAlertMessage();
1930     break;
1931 #ifdef BEEBEEP_USE_SHAREDESKTOP
1932   case 60:
1933     {
1934       Settings::instance().setEnableShareDesktop( act->isChecked() );
1935       if( !act->isChecked() )
1936       {
1937         if( beeCore->shareDesktopIsActive( ID_INVALID ) )
1938           beeCore->stopShareDesktop();
1939       }
1940     }
1941     break;
1942   case 61:
1943     {
1944       int capture_delay = QInputDialog::getInt( this, Settings::instance().programName(), act->text() + QString( " (ms)" ),
1945                                                 Settings::instance().shareDesktopCaptureDelay(), 1100, 8000, 300, &ok );
1946       if( ok )
1947         Settings::instance().setShareDesktopCaptureDelay( capture_delay );
1948     }
1949     break;
1950   case 62:
1951     {
1952       QString image_type = QInputDialog::getItem( this, Settings::instance().programName(),
1953                                                   act->text() + QString( "\n(%1)" ).arg( tr( "jpg for photo, png for presentation" ) ),
1954                                                   ImageOptimizer::instance().imageTypes(),
1955                                                   qMax( 0, ImageOptimizer::instance().imageTypes().indexOf( Settings::instance().shareDesktopImageType() ) ),
1956                                                   false, &ok );
1957       if( ok )
1958         Settings::instance().setShareDesktopImageType( image_type );
1959     }
1960     break;
1961   case 63:
1962     {
1963       int image_quality = QInputDialog::getInt( this, Settings::instance().programName(),
1964                                                 act->text() + QString( "\n(%1)" ).arg( tr( "-1 default, 10 low, 60 medium, 100 high" ) ),
1965                                                 Settings::instance().shareDesktopImageQuality(), -1, 100, 10, &ok );
1966       if( ok )
1967         Settings::instance().setShareDesktopImageQuality( image_quality );
1968     }
1969     break;
1970   case 64:
1971     Settings::instance().setShareDesktopFitToScreen( act->isChecked() );
1972     break;
1973 #endif
1974   case 65:
1975     {
1976       int delay_connection = QInputDialog::getInt( this, Settings::instance().programName(),
1977                                               act->text() + QString( "\n(%1)" ).arg( tr( "milliseconds, 5000 default" ) ),
1978                                               Settings::instance().delayConnectionAtStartup(), 3000, 60000, 1000, &ok );
1979       if( ok )
1980         Settings::instance().setDelayConnectionAtStartup( delay_connection );
1981     }
1982     break;
1983   case 66:
1984     Settings::instance().setSendOfflineMessagesToDefaultChat( act->isChecked() );
1985     break;
1986   case 67:
1987     Settings::instance().setChatUseColoredUserNames( act->isChecked() );
1988     refresh_chat = true;
1989     break;
1990   case 68:
1991     Settings::instance().setSaveGeometryOnExit( act->isChecked() );
1992     break;
1993   case 69:
1994     Settings::instance().setShowUsersOnConnection( act->isChecked() );
1995     break;
1996   case 70:
1997     Settings::instance().setAlwaysOpenChatOnNewMessageArrived( act->isChecked() );
1998     break;
1999   case 71:
2000     {
2001  #if QT_VERSION >= 0x050000
2002       int opacity_level = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2003 #else
2004       int opacity_level = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2005 #endif
2006                                                  tr( "Please select the opacity percentage of inactive chat window (default: %1%)" ).arg( Settings::instance().chatInactiveWindowDefaultOpacityLevel() ),
2007                                                  Settings::instance().chatInactiveWindowOpacityLevel(),
2008                                                  10, 100, 5, &ok );
2009       if( ok )
2010         Settings::instance().setChatInactiveWindowOpacityLevel( opacity_level );
2011       setChatInactiveWindowOpacityLevelInAction( act );
2012     }
2013     break;
2014   case 72:
2015     {
2016       QColor c = QColorDialog::getColor( QColor( Settings::instance().chatBackgroundColor() ), this );
2017       if( c.isValid() )
2018       {
2019         Settings::instance().setChatBackgroundColor( c.name() );
2020         updateChatColors();
2021       }
2022     }
2023     break;
2024   case 73:
2025     {
2026       QColor c = QColorDialog::getColor( QColor( Settings::instance().chatDefaultTextColor() ), this );
2027       if( c.isValid() )
2028       {
2029         Settings::instance().setChatDefaultTextColor( c.name() );
2030         updateChatColors();
2031       }
2032     }
2033     break;
2034   case 74:
2035     {
2036       QColor c = QColorDialog::getColor( QColor( Settings::instance().chatSystemTextColor() ), this );
2037       if( c.isValid() )
2038       {
2039         Settings::instance().setChatSystemTextColor( c.name() );
2040         updateChatColors();
2041         QMessageBox::information( this, Settings::instance().programName(), tr( "You must close and reopen the chat windows to see the changes applied." ), tr( "Ok" ) );
2042       }
2043     }
2044     break;
2045   case 75:
2046     Settings::instance().setEnableDefaultChatNotifications( act->isChecked() );
2047     break;
2048   case 76:
2049     Settings::instance().setUseMessageTimestampWithAP( act->isChecked() );
2050     refresh_chat = true;
2051     break;
2052   case 77:
2053     {
2054       if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you really want to apply the new theme?" ), tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 0 )
2055       {
2056         Settings::instance().setUseDarkStyle( act->isChecked() );
2057         Settings::instance().resetAllColors();
2058         QTimer::singleShot( 0, this, SLOT( loadStyle() ) );
2059       }
2060     }
2061     break;
2062   case 78:
2063     Settings::instance().setalwaysShowFileTransferProgress( act->isChecked() );
2064     break;
2065   case 79:
2066     Settings::instance().setShowChatsOnConnection( act->isChecked() );
2067     break;
2068   case 80:
2069     Settings::instance().setRaiseMainWindowOnNewMessageArrived( act->isChecked() );
2070     break;
2071   case 81:
2072     {
2073       Settings::instance().setChatSaveUnsentMessages( act->isChecked() );
2074       if( Settings::instance().chatSaveUnsentMessages() && (!Settings::instance().saveUserList() || !Settings::instance().saveGroupList()) )
2075       {
2076         if( QMessageBox::question( this, Settings::instance().programName(),
2077                                tr( "Saving unsent messages may fail if 'Save users' and 'Save groups' options are not enabled. Do you want to enable them?" ),
2078                                tr( "Yes" ), tr( "No" ), QString(), 0, 1 ) == 0 )
2079         {
2080           Settings::instance().setSaveUserList( true );
2081           Settings::instance().setSaveGroupList( true );
2082           mp_actSaveUserList->setChecked( true );
2083           mp_actSaveGroupList->setChecked( true );
2084         }
2085       }
2086     }
2087     break;
2088   case 82:
2089     Settings::instance().setChatSaveFileTransfers( act->isChecked() );
2090     showCheckSaveChatMessages();
2091     break;
2092   case 83:
2093     Settings::instance().setChatSaveSystemMessages( act->isChecked() );
2094     showCheckSaveChatMessages();
2095     break;
2096   case 84:
2097     {
2098 #if QT_VERSION >= 0x050000
2099       int save_max_lines = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2100 #else
2101       int save_max_lines = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2102 #endif
2103                                                  tr( "Please select the maximum number of lines to be saved in the chat (current: %1)." ).arg( Settings::instance().chatMaxLineSaved() ),
2104                                                  Settings::instance().chatMaxLineSaved(),
2105                                                  100, 50000, 100, &ok );
2106       if( ok )
2107         Settings::instance().setChatMaxLineSaved( save_max_lines );
2108       setChatMaxLinesToSaveInAction( act );
2109     }
2110     break;
2111   case 85:
2112     {
2113 #if QT_VERSION >= 0x050000
2114       int cc_days = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2115 #else
2116       int cc_days = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2117 #endif
2118                                           tr( "Please select the number of days that items (such as images) can remain cached." ) +
2119                                           QString( "\n(%1)" ).arg( tr( "current: %1, never clear: -1, always clear: 0" ).arg( Settings::instance().clearCacheAfterDays() ) ),
2120                                           Settings::instance().clearCacheAfterDays(), -1, 999, 10, &ok );
2121       if( ok )
2122       {
2123         Settings::instance().setClearCacheAfterDays( cc_days );
2124         setClearCacheAfterDaysInAction( act );
2125       }
2126     }
2127     break;
2128   case 86:
2129     Settings::instance().setDownloadInUserFolder( act->isChecked() );
2130     break;
2131   case 87:
2132     Settings::instance().setShowUsersInWorkgroups( act->isChecked() );
2133     refresh_users = true;
2134     break;
2135   case 88:
2136     {
2137 #if QT_VERSION >= 0x050000
2138       int max_files_in_queue = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2139 #else
2140       int max_files_in_queue = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2141 #endif
2142                                   tr( "Please select the maximum number of files you can queue up for the transfer (current: %1)." ).arg( Settings::instance().maxQueuedDownloads() ),
2143                                   Settings::instance().maxQueuedDownloads(),
2144                                   1, 9999, 10, &ok );
2145       if( ok )
2146       {
2147         Settings::instance().setMaxQueuedDownloads( max_files_in_queue);
2148         setMaxQueuedDownloadsInAction( act );
2149       }
2150     }
2151     break;
2152   case 89:
2153     {
2154       QColor c = QColorDialog::getColor( QColor( Settings::instance().chatQuoteTextColor() ), this );
2155       if( c.isValid() )
2156       {
2157         Settings::instance().setChatQuoteTextColor( c.name() );
2158         refresh_chat = true;
2159       }
2160     }
2161     break;
2162   case 90:
2163     {
2164       QColor c = QColorDialog::getColor( QColor( Settings::instance().chatQuoteBackgroundColor() ), this );
2165       if( c.isValid() )
2166       {
2167         Settings::instance().setChatQuoteBackgroundColor( c.name() );
2168         refresh_chat = true;
2169       }
2170     }
2171     break;
2172   case 91:
2173     {
2174       Settings::instance().setChatOnSendingMessage( Settings::SkipOnSendingMessage );
2175       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
2176         fl_chat->guiChat()->updateOnSendingMessage();
2177     }
2178     break;
2179   case 92:
2180     {
2181       Settings::instance().setChatOnSendingMessage( Settings::MinimizeChatOnSendingMessage  );
2182       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
2183         fl_chat->guiChat()->updateOnSendingMessage();
2184     }
2185     break;
2186   case 93:
2187     {
2188       Settings::instance().setChatOnSendingMessage( Settings::CloseChatOnSendingMessage );
2189       foreach( GuiFloatingChat* fl_chat, m_floatingChats )
2190         fl_chat->guiChat()->updateOnSendingMessage();
2191     }
2192     break;
2193   case 94:
2194     {
2195 #if QT_VERSION >= 0x050000
2196       int max_duration = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2197 #else
2198       int max_duration = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2199 #endif
2200                                   tr( "Please select the maximum duration (in seconds) that a voice message can have (current: %1)." ).arg( Settings::instance().voiceMessageMaxDuration() ),
2201                                   Settings::instance().voiceMessageMaxDuration(),
2202                                   10, 900, 10, &ok );
2203       if( ok )
2204         Settings::instance().setVoiceMessageMaxDuration( max_duration );
2205     }
2206     break;
2207   case 95:
2208     Settings::instance().setUseVoicePlayer( act->isChecked() );
2209     break;
2210   case 96:
2211     Settings::instance().setDisableBeepInUserStatusBusy( act->isChecked() );
2212     break;
2213   case 97:
2214     Settings::instance().setResumeFileTransfer( act->isChecked() );
2215     break;
2216   case 98:
2217     Settings::instance().setBeepInActiveWindowAlso( act->isChecked() );
2218     break;
2219   case 99:
2220     break;
2221   case 100:
2222     {
2223 #if QT_VERSION >= 0x050000
2224       int cc_days = QInputDialog::getInt( qApp->activeWindow(), Settings::instance().programName(),
2225 #else
2226       int cc_days = QInputDialog::getInteger( qApp->activeWindow(), Settings::instance().programName(),
2227 #endif
2228                                               tr( "Please select the number of days that partially downloaded files can remain cached." ) +
2229                                               QString( "\n(%1)" ).arg( tr( "current: %1, never clear: -1, always clear: 0" ).arg( Settings::instance().removePartiallyDownloadedFilesAfterDays() ) ),
2230                                               Settings::instance().removePartiallyDownloadedFilesAfterDays(), -1, 999, 10, &ok );
2231       if( ok )
2232       {
2233         Settings::instance().setRemovePartiallyDownloadedFilesAfterDays( cc_days );
2234         setClearPartiallyDownloadedFilesAfterDaysInAction( act );
2235       }
2236     }
2237     break;
2238   case 101:
2239     Settings::instance().setKeepModificationDateOnFileTransferred( act->isChecked() );
2240     break;
2241   case 102:
2242     Settings::instance().setUseUserFirstNameFirstInFullName( !act->isChecked() );
2243     break;
2244   case 103:
2245     Settings::instance().setResetMinimumWidthForStyle( act->isChecked() );
2246     setMinimumWidthForStyle();
2247     break;
2248   case 104:
2249     EmoticonManager::instance().clearRecentEmoticons();
2250     updateEmoticons();
2251     break;
2252   case 105:
2253     Settings::instance().setUseHiResEmoticons( act->isChecked() );
2254     updateEmoticons();
2255     break;
2256   case 106:
2257     EmoticonManager::instance().clearFavoriteEmoticons();
2258     updateEmoticons();
2259     break;
2260   default:
2261     qWarning() << "GuiMain::settingsChanged(): error in setting id" << act->data().toInt();
2262   }
2263 
2264   if( refresh_users )
2265     mp_userList->updateUsers();
2266 
2267   if( refresh_chat )
2268   {
2269     QApplication::setOverrideCursor( Qt::WaitCursor );
2270     QApplication::processEvents();
2271     mp_chatList->updateChats();
2272     foreach( GuiFloatingChat* fl_chat, m_floatingChats )
2273     {
2274       Chat c = ChatManager::instance().chat( fl_chat->guiChat()->chatId() );
2275       if( c.isValid() )
2276         fl_chat->setChat( c );
2277     }
2278     QApplication::restoreOverrideCursor();
2279   }
2280 
2281   if( settings_data_id > 0 && settings_data_id != 99 )
2282   {
2283     if( act->isCheckable() )
2284     {
2285       QApplication::processEvents(); // Menu is closing and status bar will be reset -> force events to display next messages
2286       if( act->isChecked() )
2287         showMessage( tr( "Option enabled." ), 3000 );
2288       else
2289         showMessage( tr( "Option disabled." ), 3000 );
2290     }
2291     Settings::instance().save();
2292   }
2293 }
2294 
showCheckSaveChatMessages()2295 void GuiMain::showCheckSaveChatMessages()
2296 {
2297   if( !Settings::instance().chatAutoSave() && (Settings::instance().chatSaveFileTransfers() || !Settings::instance().chatSaveSystemMessages()) )
2298   {
2299     if( QMessageBox::warning( this, Settings::instance().programName(),
2300                               tr( "There will be no saving of 'system' and 'file transfer' messages if this option is disabled." ),
2301                               tr( "Ok" ), tr( "Cancel" ), QString(), 0, 1 ) )
2302     {
2303       Settings::instance().setChatSaveFileTransfers( false );
2304       Settings::instance().setChatSaveSystemMessages( false );
2305       mp_actSaveFileTransferMessages->setChecked( false );
2306       mp_actSaveSystemMessages->setChecked( false );
2307     }
2308   }
2309 }
2310 
setChatMessagesToShowInAction(QAction * act)2311 void GuiMain::setChatMessagesToShowInAction( QAction* act )
2312 {
2313   act->setText( tr( "Show only last %1 messages" ).arg( Settings::instance().chatMessagesToShow() >= 0 ? Settings::instance().chatMessagesToShow() : 800 ) );
2314   act->setChecked( Settings::instance().chatMessagesToShow() >= 0 );
2315 }
2316 
setMaxInactivityDaysInAction(QAction * act)2317 void GuiMain::setMaxInactivityDaysInAction( QAction* act )
2318 {
2319   act->setText( tr( "Remove users after %1 days of inactivity" ).arg( Settings::instance().maxDaysOfUserInactivity() ) );
2320   act->setEnabled( Settings::instance().saveUserList() );
2321 }
2322 
setChatInactiveWindowOpacityLevelInAction(QAction * act)2323 void GuiMain::setChatInactiveWindowOpacityLevelInAction( QAction* act )
2324 {
2325   act->setChecked( Settings::instance().chatInactiveWindowOpacityLevel() < 100 );
2326   act->setText( tr( "Show inactive chat window with %1% opacity" ).arg( Settings::instance().chatInactiveWindowOpacityLevel() ) );
2327 }
2328 
setChatMaxLinesToSaveInAction(QAction * act)2329 void GuiMain::setChatMaxLinesToSaveInAction( QAction* act )
2330 {
2331   act->setText( tr( "Save maximum %1 lines of chat" ).arg( Settings::instance().chatMaxLineSaved() ) );
2332   act->setEnabled( Settings::instance().chatAutoSave() );
2333   act->setChecked( Settings::instance().chatMaxLineSaved() > 0 );
2334 }
2335 
setClearCacheAfterDaysInAction(QAction * act)2336 void GuiMain::setClearCacheAfterDaysInAction( QAction* act )
2337 {
2338   act->setText( tr( "Clean the cache from items older than %1 days" ).arg( Settings::instance().clearCacheAfterDays() >= 0 ? Settings::instance().clearCacheAfterDays() : 96 ) );
2339   act->setEnabled( Settings::instance().chatAutoSave() );
2340   act->setChecked( Settings::instance().clearCacheAfterDays() >= 0 );
2341 }
2342 
setClearPartiallyDownloadedFilesAfterDaysInAction(QAction * act)2343 void GuiMain::setClearPartiallyDownloadedFilesAfterDaysInAction( QAction* act )
2344 {
2345   act->setText( tr( "Delete partially downloaded files after %1 days" ).arg( Settings::instance().removePartiallyDownloadedFilesAfterDays() >= 0 ? Settings::instance().removePartiallyDownloadedFilesAfterDays() : 5 ) );
2346   act->setChecked( Settings::instance().removePartiallyDownloadedFilesAfterDays() >= 0 );
2347 }
2348 
setMaxQueuedDownloadsInAction(QAction * act)2349 void GuiMain::setMaxQueuedDownloadsInAction( QAction* act )
2350 {
2351   act->setText( tr( "Add up to %1 files to the transfer queue" ).arg( Settings::instance().maxQueuedDownloads() ) );
2352   act->setChecked( Settings::instance().maxQueuedDownloads() > 0 );
2353 }
2354 
sendMessage(VNumber chat_id,const QString & msg)2355 void GuiMain::sendMessage( VNumber chat_id, const QString& msg )
2356 {
2357 #ifdef BEEBEEP_DEBUG
2358   int num_messages = beeCore->sendChatMessage( chat_id, msg, false );
2359   qDebug() << num_messages << "messages sent";
2360 #else
2361   beeCore->sendChatMessage( chat_id, msg, false );
2362 #endif
2363   mp_chatList->updateChat( ChatManager::instance().chat( chat_id ) ); // to sort the chats
2364 }
2365 
showAlertForMessage(const Chat & c,const ChatMessage & cm)2366 void GuiMain::showAlertForMessage( const Chat& c, const ChatMessage& cm )
2367 {
2368   if( cm.isImportant() )
2369   {
2370     playBuzz();
2371   }
2372   else
2373   {
2374     if( Settings::instance().beepOnNewMessageArrived() &&
2375         !(Settings::instance().localUser().status() == User::Busy && Settings::instance().disableBeepInUserStatusBusy()) )
2376     {
2377       playBeep();
2378     }
2379   }
2380 
2381   bool show_message_in_tray = true;
2382 
2383   GuiFloatingChat* fl_chat = floatingChat( c.id() );
2384   if( fl_chat )
2385   {
2386     fl_chat->setMainIcon( true );
2387     QApplication::alert( fl_chat, 0 );
2388     if( Settings::instance().raiseOnNewMessageArrived() || cm.isImportant() )
2389     {
2390       fl_chat->raiseOnTop();
2391       show_message_in_tray = false;
2392     }
2393   }
2394 
2395   if( Settings::instance().raiseMainWindowOnNewMessageArrived() )
2396     raiseOnTop();
2397 
2398   if( show_message_in_tray )
2399   {
2400     User u = UserManager::instance().findUser( cm.userId() );
2401     QString msg;
2402     bool long_time_show = false;
2403 
2404     if( u.isValid() )
2405     {
2406       if( Settings::instance().showChatMessageOnTray() )
2407       {
2408         QString txt = Bee::removeHtmlTags( cm.message() );
2409         if( txt.size() > Settings::instance().textSizeInChatMessagePreviewOnTray() )
2410         {
2411           txt.truncate( Settings::instance().textSizeInChatMessagePreviewOnTray() );
2412           txt.append( "..." );
2413         }
2414 
2415         if( c.isDefault() )
2416           msg = QString( "%1 %2: %3" ).arg( u.name(), tr( "to all" ), txt );
2417         else if( c.isGroup() )
2418           msg = QString( "%1 %2 %3: %4" ).arg( u.name(), tr( "to" ), c.name(), txt );
2419         else
2420           msg = QString( "%1 %2: %4" ).arg( u.name(), tr( "to you" ), txt );
2421 
2422         long_time_show = true;
2423       }
2424       else
2425       {
2426         QString pre_msg = tr( "New message from" );
2427         if( c.isDefault() )
2428           msg = QString( "%1 %2 %3" ).arg( pre_msg, u.name(), tr( "to all" ) );
2429         else if( c.isGroup() )
2430           msg = QString( "%1 %2 %3 %4" ).arg( pre_msg, u.name(), tr( "to" ), c.name() );
2431         else
2432           msg = QString( "%1 %2 %3" ).arg( pre_msg, u.name(), tr( "to you" ) );
2433       }
2434     }
2435     else
2436       msg = tr( "New message arrived" );
2437 
2438     mp_trayIcon->showNewMessageArrived( c.id(), msg, long_time_show );
2439   }
2440 }
2441 
onNewChatMessage(const Chat & c,const ChatMessage & cm)2442 void GuiMain::onNewChatMessage( const Chat& c, const ChatMessage& cm )
2443 {
2444   if( !c.isValid() )
2445   {
2446     qWarning() << "Invalid chat" << c.name() << "found in GuiMain::onNewChatMessage(...)";
2447     return;
2448   }
2449 
2450   if( c.isDefault() )
2451   {
2452     if( mp_home->addSystemMessage( cm ) && mp_tabMain->currentWidget() != mp_home )
2453     {
2454       m_unreadActivities++;
2455       updateTabTitles();
2456     }
2457   }
2458 
2459   bool floating_chat_created = false;
2460   bool alert_can_be_notified = false;
2461 
2462   if( c.isDefault() )
2463     alert_can_be_notified = cm.alertCanBeSent() && Settings::instance().enableDefaultChatNotifications();
2464   else if( c.isGroup() )
2465     alert_can_be_notified = cm.alertCanBeSent() && !Settings::instance().isNotificationDisabledForGroup( c.privateId() );
2466   else
2467     alert_can_be_notified = cm.alertCanBeSent();
2468 
2469   GuiFloatingChat* fl_chat = floatingChat( c.id() );
2470 
2471   if( !fl_chat && Settings::instance().alwaysOpenChatOnNewMessageArrived() && alert_can_be_notified )
2472   {
2473     fl_chat = createFloatingChat( c );
2474     floating_chat_created = true;
2475     fl_chat->show();
2476     fl_chat->guiChat()->ensureLastMessageVisible();
2477     if( !Settings::instance().raiseOnNewMessageArrived() && !cm.isImportant() )
2478       fl_chat->showMinimized();
2479   }
2480 
2481   if( fl_chat && !floating_chat_created )
2482     fl_chat->showChatMessage( c, cm );
2483 
2484   if( fl_chat && fl_chat->isActiveWindow() )
2485   {
2486     if( alert_can_be_notified && (cm.isImportant() || Settings::instance().beepInActiveWindowAlso()) )
2487       playBeep();
2488     readAllMessagesInChat( c.id() );
2489   }
2490   else
2491   {
2492     if( alert_can_be_notified )
2493       showAlertForMessage( c, cm );
2494   }
2495 }
2496 
updateUser(const User & u)2497 void GuiMain::updateUser( const User& u )
2498 {
2499   mp_userList->setUser( u, false );
2500   mp_chatList->updateUser( u );
2501   mp_groupList->updateUser( u );
2502   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
2503     fl_chat->updateUser( u );
2504   mp_fileTransfer->updateUser( u );
2505 }
2506 
searchUsers()2507 void GuiMain::searchUsers()
2508 {
2509   GuiNetwork gn( this );
2510   gn.setModal( true );
2511   gn.loadSettings();
2512   gn.setSizeGripEnabled( true );
2513   gn.show();
2514 
2515   if( gn.exec() != QDialog::Accepted )
2516     return;
2517 
2518   if( gn.restartConnection() )
2519   {
2520     showRestartConnectionAlertMessage();
2521     return;
2522   }
2523 
2524   if( !beeCore->isConnected() )
2525     return;
2526 
2527 #ifdef BEEBEEP_USE_MULTICAST_DNS
2528   if( Settings::instance().useMulticastDns() )
2529     beeCore->startDnsMulticasting();
2530   else
2531     beeCore->stopDnsMulticasting();
2532 #endif
2533 
2534   QMetaObject::invokeMethod( this, "sendBroadcastMessage", Qt::QueuedConnection );
2535 }
2536 
showWritingUser(const User & u,VNumber chat_id)2537 void GuiMain::showWritingUser( const User& u, VNumber chat_id )
2538 {
2539   QString msg = tr( "%1 is writing..." ).arg( u.name() );
2540   GuiFloatingChat* fl_chat = floatingChat( chat_id );
2541   if( fl_chat )
2542     fl_chat->showStatusMessage( msg, Settings::instance().writingTimeout() );
2543 }
2544 
setUserStatusSelected(int user_status)2545 void GuiMain::setUserStatusSelected( int user_status )
2546 {
2547   if( user_status == User::Offline )
2548   {
2549     if( beeCore->isConnected() )
2550     {
2551       if( !Settings::instance().promptOnCloseEvent() || QMessageBox::question( this, Settings::instance().programName(),
2552                                    tr( "Do you want to disconnect from %1 network?" ).arg( Settings::instance().programName() ),
2553                                    tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 0 )
2554       {
2555         disconnectFromNetwork();
2556         return;
2557       }
2558     }
2559     updateStatusIcon();
2560   }
2561   else
2562   {
2563     if( beeCore->isConnected() )
2564     {
2565       beeCore->setLocalUserStatus( user_status );
2566     }
2567     else
2568     {
2569       Settings::instance().setLocalUserStatus( static_cast<User::Status>(user_status) );
2570       startCore();
2571     }
2572   }
2573 }
2574 
statusSelected()2575 void GuiMain::statusSelected()
2576 {
2577   QAction* act = qobject_cast<QAction*>( sender() );
2578   if( !act )
2579     return;
2580 
2581   int user_status = act->data().toInt();
2582   setUserStatusSelected( user_status );
2583 }
2584 
updateStatusIcon()2585 void GuiMain::updateStatusIcon()
2586 {
2587   int status_type;
2588   if( !beeCore->isConnected() )
2589     status_type = User::Offline;
2590   else
2591     status_type = Settings::instance().localUser().status();
2592 
2593   mp_menuStatus->setIcon( Bee::avatarForUser( Settings::instance().localUser(), Settings::instance().avatarIconSize(), true ) );
2594   QString tip = tr( "You are %1%2" ).arg( Bee::userStatusToString( status_type ) )
2595       .arg( (Settings::instance().localUser().statusDescription().isEmpty() ? QString( "" ) : QString( ": %1" ).arg( Settings::instance().localUser().statusDescription() ) ) );
2596   QAction* act = mp_menuStatus->menuAction();
2597   act->setToolTip( tip );
2598   act->setText( Bee::capitalizeFirstLetter( Bee::userStatusToString( status_type ), true ) );
2599   updateWindowTitle();
2600 }
2601 
changeStatusDescription()2602 void GuiMain::changeStatusDescription()
2603 {
2604   bool ok = false;
2605   QString status_description = QInputDialog::getText( this, Settings::instance().programName(),
2606                            tr( "Please insert the new status description" ), QLineEdit::Normal, Settings::instance().localUser().statusDescription(), &ok );
2607   if( !ok || status_description.isNull() )
2608     return;
2609   beeCore->setLocalUserStatusDescription( Settings::instance().localUser().status(), status_description, true );
2610   loadUserStatusRecentlyUsed();
2611   updateStatusIcon();
2612   updateLocalStatusMessage();
2613 }
2614 
sendFileFromChat(VNumber chat_id,const QString & file_path)2615 void GuiMain::sendFileFromChat( VNumber chat_id, const QString& file_path )
2616 {
2617   Chat c = ChatManager::instance().chat( chat_id );
2618   if( !c.isValid() )
2619     return;
2620 
2621   if( c.isDefault() && !Settings::instance().chatWithAllUsersIsEnabled() )
2622     return;
2623 
2624   QStringList files_path_selected = checkFilePath( file_path );
2625   if( files_path_selected.isEmpty() )
2626     return;
2627 
2628   beeCore->sendFilesFromChat( c.id(), files_path_selected );
2629 }
2630 
sendFilesFromChat(VNumber chat_id,const QStringList & file_path_list)2631 void GuiMain::sendFilesFromChat( VNumber chat_id, const QStringList& file_path_list )
2632 {
2633   Chat c = ChatManager::instance().chat( chat_id );
2634   if( !c.isValid() )
2635     return;
2636 
2637   if( c.isDefault() && !Settings::instance().chatWithAllUsersIsEnabled() )
2638     return;
2639 
2640   if( file_path_list.isEmpty() )
2641     return;
2642 
2643   beeCore->sendFilesFromChat( c.id(), file_path_list );
2644 }
2645 
sendFile(VNumber user_id)2646 void GuiMain::sendFile( VNumber user_id )
2647 {
2648   User u = UserManager::instance().findUser( user_id );
2649   QStringList files_path_selected = checkFilePath( "" );
2650   if( files_path_selected.isEmpty() )
2651     return;
2652   Chat c = ChatManager::instance().privateChatForUser( user_id );
2653   if( !c.isValid() )
2654     qWarning() << "Unable to send files to user" << user_id << "without a private chat in GuiMain::sendFile(...)";
2655   beeCore->sendFilesFromChat( c.id(), files_path_selected );
2656 }
2657 
checkFilePath(const QString & file_path)2658 QStringList GuiMain::checkFilePath( const QString& file_path )
2659 {
2660   QStringList files_path_selected;
2661   if( file_path.isEmpty() || !QFile::exists( file_path ) )
2662   {
2663     files_path_selected = FileDialog::getOpenFileNames( true, activeWindow(), tr( "%1 - Select a file" ).arg( Settings::instance().programName() ) + QString( " %1" ).arg( tr( "or more" ) ),
2664                                                        Settings::instance().lastDirectorySelected() );
2665     if( files_path_selected.isEmpty() )
2666       return files_path_selected;
2667 
2668     Settings::instance().setLastDirectorySelectedFromFile( files_path_selected.last() );
2669   }
2670   else
2671   {
2672     files_path_selected.append( file_path );
2673   }
2674 
2675   return files_path_selected;
2676 }
2677 
sendFile(const User & u,const QString & file_path,VNumber chat_id)2678 bool GuiMain::sendFile( const User& u, const QString& file_path, VNumber chat_id )
2679 {
2680   if( !Settings::instance().enableFileTransfer() )
2681   {
2682     QMessageBox::information( activeWindow(), Settings::instance().programName(), tr( "File transfer is not enabled." ) );
2683     return false;
2684   }
2685 
2686   if( !beeCore->isConnected() )
2687   {
2688     QMessageBox::information( activeWindow(), Settings::instance().programName(), tr( "You are not connected." ) );
2689     return false;
2690   }
2691 
2692   User user_selected;
2693 
2694   if( !u.isValid() )
2695   {
2696     QStringList user_string_list;
2697     foreach( User u, UserManager::instance().userList().toList() )
2698     {
2699       if( u.isStatusConnected() )
2700         user_string_list.append( u.path() );
2701     }
2702 
2703     if( user_string_list.isEmpty() )
2704     {
2705       QMessageBox::information( activeWindow(), Settings::instance().programName(), tr( "There is no user connected." ) );
2706       return false;
2707     }
2708 
2709     bool ok = false;
2710     QString user_path = QInputDialog::getItem( activeWindow(), Settings::instance().programName(),
2711                                         tr( "Please select the user to whom you would like to send a file."),
2712                                         user_string_list, 0, false, &ok );
2713     if( !ok )
2714       return false;
2715 
2716     user_selected = UserManager::instance().findUserByPath( user_path );
2717 
2718     if( !user_selected.isValid() )
2719     {
2720       QMessageBox::warning( activeWindow(), Settings::instance().programName(), tr( "User not found." ) );
2721       return false;
2722     }
2723 
2724     Chat c = ChatManager::instance().privateChatForUser( user_selected.id() );
2725     chat_id = c.id();
2726   }
2727   else
2728     user_selected = u;
2729 
2730   return beeCore->sendFile( user_selected.id(), file_path, "", false, chat_id );
2731 }
2732 
sendFile(const QString & file_path)2733 void GuiMain::sendFile( const QString& file_path )
2734 {
2735   sendFile( User(), file_path, ID_INVALID );
2736 }
2737 
askToDownloadFile(const User & u,const FileInfo & fi,const QString & download_path,bool make_questions)2738 bool GuiMain::askToDownloadFile( const User& u, const FileInfo& fi, const QString& download_path, bool make_questions )
2739 {
2740   if( !Settings::instance().enableFileTransfer() )
2741   {
2742     QMessageBox::warning( activeWindow(), Settings::instance().programName(), tr( "File transfer is disabled. You cannot download %1." ).arg( fi.name() ) );
2743     return false;
2744   }
2745 
2746   int msg_result = make_questions ? 0 : 1;
2747 
2748   if( msg_result == 0 )
2749   {
2750     if( Settings::instance().confirmOnDownloadFile() )
2751     {
2752       if( isMinimized() || !isActiveWindow() )
2753       {
2754         if( Settings::instance().raiseMainWindowOnNewMessageArrived() )
2755           raiseOnTop();
2756         mp_actViewNewMessage->setEnabled( true );
2757       }
2758       QString msg = tr( "Do you want to download %1 (%2) from %3?" ).arg( fi.name(), Bee::bytesToString( fi.size() ), Bee::userNameToShow( u, false ) );
2759       msg_result = QMessageBox::question( this, Settings::instance().programName(), msg, tr( "No" ), tr( "Yes" ), tr( "Yes, and don't ask anymore" ), 0, 0 );
2760     }
2761     else
2762       msg_result = 1;
2763   }
2764 
2765   if( msg_result == 2 )
2766   {
2767     qDebug() << "Prompt on download file disabled by user request";
2768     Settings::instance().setConfirmOnDownloadFile( false );
2769     mp_actConfirmDownload->setChecked( false );
2770   }
2771 
2772   if( msg_result > 0 )
2773   {
2774     QFileInfo qfile_info( download_path, fi.name() );
2775     qDebug() << "You accept to download" << fi.name() << "from" << qPrintable( u.path() );
2776     if( qfile_info.exists() && Settings::instance().onExistingFileAction() == Settings::GenerateNewFileName )
2777     {
2778       QString file_name = Bee::uniqueFilePath( qfile_info.absoluteFilePath(), true );
2779       qDebug() << "File" << qfile_info.absoluteFilePath() << "exists. Save it with new path (auto):" << qPrintable( file_name );
2780       qfile_info = QFileInfo( file_name );
2781     }
2782     FileInfo file_info = fi;
2783     file_info.setPath( qfile_info.absoluteFilePath() );
2784     return beeCore->downloadFile( u.id(), file_info, make_questions );
2785   }
2786   else
2787   {
2788     qDebug() << "You refuse to download" << fi.name() << "from" << u.path();
2789     return false;
2790   }
2791 }
2792 
downloadFile(const User & u,const FileInfo & fi)2793 void GuiMain::downloadFile( const User& u, const FileInfo& fi )
2794 {
2795   if( !askToDownloadFile( u, fi, Settings::instance().downloadDirectoryForUser( u ), true ) )
2796     beeCore->refuseToDownloadFile( u.id(), fi );
2797 }
2798 
downloadSharedFiles(const QList<SharedFileInfo> & share_file_info_list)2799 void GuiMain::downloadSharedFiles( const QList<SharedFileInfo>& share_file_info_list )
2800 {
2801   if( share_file_info_list.isEmpty() )
2802     return;
2803 
2804   QString download_folder;
2805   User u;
2806   int files_to_download = 0;
2807 
2808   if( share_file_info_list.size() > Settings::instance().maxQueuedDownloads() )
2809   {
2810     if( QMessageBox::question( activeWindow(), Settings::instance().programName(),
2811                                tr( "You cannot download all these files at once. Do you want to download the first %1 files of the list?" )
2812                                .arg( Settings::instance().maxQueuedDownloads() ),
2813                                tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
2814       return;
2815   }
2816   else if( share_file_info_list.size() > 100 )
2817   {
2818     if( QMessageBox::question( activeWindow(), Settings::instance().programName(),
2819                            tr( "Downloading %1 files is a hard duty. Maybe you have to wait a lot of minutes. Do yo want to continue?" ).arg( share_file_info_list.size() ),
2820                            tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
2821       return;
2822   }
2823 
2824   foreach( SharedFileInfo sfi, share_file_info_list )
2825   {
2826     u = UserManager::instance().findUser( sfi.first );
2827     download_folder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( Settings::instance().downloadDirectoryForUser( u ), sfi.second.shareFolder() ) );
2828     if( !askToDownloadFile( u, sfi.second, download_folder, false ) )
2829       return;
2830     files_to_download++;
2831     if( files_to_download > Settings::instance().maxQueuedDownloads() )
2832       break;
2833   }
2834 
2835   showMessage( tr( "Downloading %1 files" ).arg( files_to_download ), 5000 );
2836 }
2837 
downloadSharedFile(VNumber user_id,VNumber file_id)2838 void GuiMain::downloadSharedFile( VNumber user_id, VNumber file_id )
2839 {
2840   User u = UserManager::instance().findUser( user_id );
2841   FileInfo file_info = FileShare::instance().networkFileInfo( user_id, file_id );
2842 
2843   if( u.isStatusConnected() && file_info.isValid() )
2844   {
2845     askToDownloadFile( u, file_info, Settings::instance().downloadDirectoryForUser( u ), true );
2846     return;
2847   }
2848 
2849   qWarning() << "Unable to download shared file" << file_id << "from user" << user_id;
2850   QString info_msg = tr( "File is not available for download." );
2851   if( u.isValid() && !u.isStatusConnected() )
2852     info_msg += QLatin1String( "\n" ) + tr( "%1 is not connected." ).arg( u.name() );
2853   info_msg += QLatin1String( "\n" ) + tr( "Please reload the list of shared files." );
2854 
2855   if( QMessageBox::information( activeWindow(), Settings::instance().programName(), info_msg,
2856                               tr( "Reload file list" ), tr( "Cancel" ), QString(), 1, 1 ) == 0 )
2857   {
2858     if( mp_fileSharing )
2859       mp_fileSharing->updateNetworkFileList();
2860   }
2861 }
2862 
downloadFolder(const User & u,const QString & folder_name,const QList<FileInfo> & file_info_list)2863 void GuiMain::downloadFolder( const User& u, const QString& folder_name, const QList<FileInfo>& file_info_list )
2864 {
2865   if( !Settings::instance().enableFileTransfer() )
2866   {
2867     QMessageBox::warning( activeWindow(), Settings::instance().programName(), tr( "File transfer is disabled. You cannot download %1." ).arg( folder_name ) );
2868     return;
2869   }
2870 
2871   if( file_info_list.isEmpty() )
2872   {
2873     qWarning() << "Unable to download folder" << folder_name << "from user" << qPrintable( u.path() ) << "with empty file list";
2874     return;
2875   }
2876 
2877   int msg_result = Settings::instance().confirmOnDownloadFile() ? 0 : 1;
2878 
2879   if( msg_result == 0 )
2880   {
2881     QString msg = tr( "Do you want to download folder %1 (%2 files) from %3?" ).arg( folder_name ).arg( file_info_list.size() ).arg( u.name() );
2882     msg_result = QMessageBox::question( activeWindow(), Settings::instance().programName(), msg, tr( "No" ), tr( "Yes" ), tr( "Yes, and don't ask anymore" ), 0, 0 );
2883   }
2884 
2885   if( msg_result == 2 )
2886   {
2887     Settings::instance().setConfirmOnDownloadFile( false );
2888     mp_actConfirmDownload->setChecked( false );
2889   }
2890 
2891   if( msg_result > 0 )
2892   {
2893     // Accepted
2894     qDebug() << "You accept to download folder" << folder_name << "from" << u.path();
2895     QString download_folder;
2896     int files_to_download = 0;
2897     foreach( FileInfo fi, file_info_list )
2898     {
2899       download_folder = Bee::convertToNativeFolderSeparator( QString( "%1/%2" ).arg( Settings::instance().downloadDirectoryForUser( u ), fi.shareFolder() ) );
2900       if( !askToDownloadFile( u, fi, download_folder, false ) )
2901         return;
2902 
2903       files_to_download++;
2904 
2905       if( files_to_download > Settings::instance().maxQueuedDownloads() )
2906       {
2907         qWarning() << "Unable to download all the" << file_info_list.size() << "files because max queued reached" << Settings::instance().maxQueuedDownloads();
2908         break;
2909       }
2910     }
2911   }
2912   else
2913   {
2914     qDebug() << "You refuse to download folder" << folder_name << "from" << u.path();
2915     beeCore->refuseToDownloadFolder( u.id(), folder_name, file_info_list.first().chatPrivateId() );
2916   }
2917 }
2918 
selectDownloadDirectory()2919 void GuiMain::selectDownloadDirectory()
2920 {
2921   QString download_directory_path = FileDialog::getExistingDirectory( activeWindow(),
2922                                                                        tr( "%1 - Select the download folder" )
2923                                                                        .arg( Settings::instance().programName() ),
2924                                                                        Settings::instance().downloadDirectory() );
2925   if( download_directory_path.isEmpty() )
2926     return;
2927 
2928   Settings::instance().setDownloadDirectory( download_directory_path );
2929   QMessageBox::information( this, Settings::instance().programName(),
2930                             QString( "%1<br>%2%3%4" ).arg( tr( "The files will be downloaded to the folder:" ) )
2931                                                      .arg( download_directory_path )
2932                                                      .arg( Bee::nativeFolderSeparator() )
2933                                                      .arg( Settings::instance().downloadInUserFolder() ? Bee::convertToNativeFolderSeparator( QString( "<user's name>" ) ) : "" ),
2934                             tr( "Ok" ) );
2935 }
2936 
showTipOfTheDay()2937 void GuiMain::showTipOfTheDay()
2938 {
2939   openWebUrl( Settings::instance().tipsWebSite() );
2940 }
2941 
showFactOfTheDay()2942 void GuiMain::showFactOfTheDay()
2943 {
2944   openWebUrl( Settings::instance().factWebSite() );
2945 }
2946 
showFaq()2947 void GuiMain::showFaq()
2948 {
2949   openWebUrl( Settings::instance().faqWebSite() );
2950 }
2951 
showChat(VNumber chat_id)2952 void GuiMain::showChat( VNumber chat_id )
2953 {
2954   Chat c = ChatManager::instance().chat( chat_id );
2955   if( !c.isValid() )
2956   {
2957     qWarning() << "Invalid chat" << chat_id << "found in GuiMain::showChat(...)";
2958     return;
2959   }
2960 
2961   GuiFloatingChat* fl_chat = createFloatingChat( c );
2962   if( !fl_chat )
2963     return;
2964 
2965   fl_chat->show();
2966   fl_chat->showUp();
2967   fl_chat->setFocusInChat();
2968 }
2969 
changeVCard()2970 void GuiMain::changeVCard()
2971 {
2972   GuiEditVCard gvc;
2973   gvc.setModal( true );
2974   gvc.setUser( Settings::instance().localUser() );
2975   gvc.setSizeGripEnabled( true );
2976   gvc.show();
2977   if( gvc.exec() == QDialog::Accepted )
2978   {
2979     beeCore->setLocalUserVCard( gvc.userColor(), gvc.vCard() );
2980     if( gvc.regenerateUserHash() )
2981     {
2982       beeCore->regenerateLocalUserHash();
2983       QMessageBox::information( this, Settings::instance().programName(), tr( "You must restart %1 to apply these changes." ).arg( Settings::instance().programName() ) );
2984     }
2985   }
2986 }
2987 
showLocalUserVCard()2988 void GuiMain::showLocalUserVCard()
2989 {
2990   showVCard( ID_LOCAL_USER );
2991 }
2992 
showVCard(VNumber user_id)2993 void GuiMain::showVCard( VNumber user_id )
2994 {
2995   User u = UserManager::instance().findUser( user_id );
2996   if( !u.isValid() )
2997     return;
2998 
2999   GuiVCard* gvc = new GuiVCard( this );
3000   connect( gvc, SIGNAL( showChat( VNumber ) ), this, SLOT( showChat( VNumber ) ) );
3001   connect( gvc, SIGNAL( sendFile( VNumber ) ), this, SLOT( sendFile( VNumber ) ) );
3002   connect( gvc, SIGNAL( changeUserColor( VNumber, const QString& ) ), this, SLOT( changeUserColor( VNumber, const QString& ) ) );
3003   connect( gvc, SIGNAL( toggleFavorite( VNumber ) ), this, SLOT( toggleUserFavorite( VNumber ) ) );
3004   connect( gvc, SIGNAL( removeUser( VNumber ) ), this, SLOT( removeUserFromList( VNumber ) ) );
3005   connect( gvc, SIGNAL( buzzUser( VNumber ) ), this, SLOT( sendBuzzToUser( VNumber ) ) );
3006   gvc->setVCard( u, ChatManager::instance().privateChatForUser( u.id() ).id(), beeCore->isConnected() );
3007 
3008   QPoint cursor_pos = QCursor::pos();
3009   QRect screen_rect = qApp->desktop()->availableGeometry( cursor_pos );
3010   int diff_margin = cursor_pos.x() + gvc->size().width() - screen_rect.width();
3011   if( diff_margin > 0 )
3012     cursor_pos.setX( cursor_pos.x() - gvc->size().width() - 16 );
3013   diff_margin = cursor_pos.y() + gvc->size().height() - screen_rect.height();
3014   if( diff_margin > 0 )
3015     cursor_pos.setY( cursor_pos.y() - gvc->size().height() + 24 );
3016   gvc->move( cursor_pos );
3017   gvc->show();
3018   gvc->adjustSize();
3019   gvc->setFixedSize( gvc->size() );
3020 }
3021 
updadePluginMenu()3022 void GuiMain::updadePluginMenu()
3023 {
3024   mp_menuPlugins->clear();
3025   QAction* act;
3026   mp_menuPlugins->addAction( IconManager::instance().icon( "plugin.png" ), tr( "Plugin Manager..." ), this, SLOT( showPluginManager() ) );
3027 
3028   QString help_data_ts = tr( "is a plugin developed by" );
3029   QString help_data_format = QString( "<p>%1 <b>%2</b> %3 <b>%4</b>.<br><i>%5</i></p><br>" );
3030 
3031   mp_menuPlugins->addAction( mp_actViewScreenShot );
3032 
3033   bool copymastro_available = false;
3034   QString copy_mastro_path = "";
3035 #ifdef Q_OS_WIN
3036   copy_mastro_path = QString( "%1\\%2" ).arg( Settings::instance().pluginPath(), QString( "CopyMastro.exe" ) );
3037   copymastro_available = QFile::exists( copy_mastro_path );
3038   if( !copymastro_available )
3039   {
3040     copy_mastro_path = QString( "C:\\Program Files (x86)\\CopyMastro\\CopyMastro.exe" );
3041     copymastro_available = QFile::exists( copy_mastro_path );
3042   }
3043 #endif
3044 
3045   if( copymastro_available )
3046   {
3047     qDebug() << "CopyMastro is found:" << qPrintable( copy_mastro_path );
3048     act = mp_menuPlugins->addAction( IconManager::instance().icon( "CopyMastro.png" ), "CopyMastro", this, SLOT( startExternalApplicationFromActionData() ) );
3049     act->setToolTip( tr( "Start the new application to copy file and folders by Marco Mastroddi" ) );
3050     act->setData( copy_mastro_path );
3051   }
3052 
3053   if( PluginManager::instance().textMarkers().size() > 0 )
3054   {
3055     mp_menuPlugins->addSeparator();
3056 
3057     foreach( TextMarkerInterface* text_marker, PluginManager::instance().textMarkers() )
3058     {
3059       act = mp_menuPlugins->addAction( text_marker->name(), this, SLOT( showPluginHelp() ) );
3060 
3061       act->setData( help_data_format
3062                   .arg( IconManager::instance().toHtml( (text_marker->icon().isNull() ? "images/plugin.png" : text_marker->iconFileName()), "*P*" ),
3063                         text_marker->name(), help_data_ts, text_marker->author(), text_marker->help() ) );
3064       act->setIcon( text_marker->icon() );
3065       act->setEnabled( text_marker->isEnabled() );
3066     }
3067   }
3068 }
3069 
showPluginHelp()3070 void GuiMain::showPluginHelp()
3071 {
3072   QAction* act = qobject_cast<QAction*>(sender());
3073   if( !act )
3074     return;
3075 
3076   QMessageBox::information( this, act->text(), act->data().toString() );
3077 }
3078 
showPluginManager()3079 void GuiMain::showPluginManager()
3080 {
3081   GuiPluginManager gpm;
3082   gpm.setModal( true );
3083   gpm.setSizeGripEnabled( true );
3084   gpm.updatePlugins();
3085   gpm.show();
3086   gpm.exec();
3087   if( gpm.isChanged() )
3088     updadePluginMenu();
3089 }
3090 
showWizard()3091 bool GuiMain::showWizard()
3092 {
3093   GuiWizard gw( this );
3094   gw.setModal( true );
3095   gw.loadSettings();
3096   gw.show();
3097   gw.setFixedSize( gw.size() );
3098   if( gw.exec() == QDialog::Accepted )
3099   {
3100     if( !beeCore->changeLocalUser( gw.userName() ) )
3101     {
3102       if( QMessageBox::question( this, Settings::instance().programName(), tr( "Your name is not changed. Do you want to continue?" ),
3103                                  tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
3104       {
3105         return false;
3106       }
3107     }
3108     return true;
3109   }
3110   else
3111     return false;
3112 }
3113 
hideToTrayIcon()3114 void GuiMain::hideToTrayIcon()
3115 {
3116   Chat c = ChatManager::instance().firstChatWithUnreadMessages();
3117   if( c.isValid() )
3118     mp_trayIcon->setUnreadMessages( c.id(), c.unreadMessages() );
3119   else
3120     mp_trayIcon->setUnreadMessages( ID_INVALID, 0 );
3121   hide();
3122 }
3123 
trayIconClicked(QSystemTrayIcon::ActivationReason ar)3124 void GuiMain::trayIconClicked( QSystemTrayIcon::ActivationReason ar )
3125 {
3126 #ifdef Q_OS_MAC
3127 
3128   // In Mac that is the expected behavior, there is no distinction
3129   // between left and right buttons for the systray icons.
3130   // They will always show the context menu, that's the Mac behavior.
3131   Q_UNUSED( ar );
3132 
3133 #else
3134 
3135   // Other OS
3136 
3137   if( ar == QSystemTrayIcon::Context )
3138   {
3139 #ifdef BEEBEEP_DEBUG
3140     qDebug() << "TrayIcon is activated with context click and menu is showed";
3141 #endif
3142     return;
3143   }
3144 
3145   if( ar == QSystemTrayIcon::Trigger )
3146   {
3147     if( !isActiveWindow() || isMinimized() )
3148     {
3149 #ifdef BEEBEEP_DEBUG
3150       qDebug() << "TrayIcon is activated with trigger click and main window will be showed";
3151 #endif
3152       QTimer::singleShot( 0, this, SLOT( raiseOnTop() ) );
3153     }
3154     else
3155     {
3156 #ifdef BEEBEEP_DEBUG
3157       qDebug() << "TrayIcon is activated with trigger click and menu will be showed";
3158 #endif
3159       mp_menuTrayIcon->popup( QCursor::pos() );
3160     }
3161   }
3162   else
3163   {
3164 #ifdef BEEBEEP_DEBUG
3165     qDebug() << "TrayIcon is activated with unknown click";
3166 #endif
3167     if( !mp_menuTrayIcon->isVisible() )
3168       mp_menuTrayIcon->popup( QCursor::pos() );
3169   }
3170 #endif
3171 }
3172 
trayMessageClicked()3173 void GuiMain::trayMessageClicked()
3174 {
3175   // QT 2019-06-27: Currently this signal is not sent on macOS.
3176   if( mp_trayIcon->chatId() != ID_INVALID && ChatManager::instance().chat( mp_trayIcon->chatId() ).isValid() )
3177   {
3178     VNumber chat_id = mp_trayIcon->chatId();
3179     showChat( chat_id );
3180     GuiFloatingChat* fl_chat = floatingChat( chat_id );
3181     if( fl_chat && !fl_chat->chatIsVisible() )
3182       QTimer::singleShot( 0, fl_chat, SLOT( raiseOnTop() ) );
3183   }
3184   else
3185     QTimer::singleShot( 0, this, SLOT( raiseOnTop() ) );
3186 }
3187 
addToShare(const QString & share_path)3188 void GuiMain::addToShare( const QString& share_path )
3189 {
3190   beeCore->addPathToShare( share_path );
3191 }
3192 
removeFromShare(const QString & share_path)3193 void GuiMain::removeFromShare( const QString& share_path )
3194 {
3195   beeCore->removePathFromShare( share_path );
3196 }
3197 
openUrl(const QUrl & file_url)3198 void GuiMain::openUrl( const QUrl& file_url )
3199 {
3200   openUrlFromChat( file_url, ID_INVALID );
3201 }
3202 
openUrlFromChat(const QUrl & file_url,VNumber chat_id)3203 void GuiMain::openUrlFromChat( const QUrl& file_url, VNumber chat_id )
3204 {
3205 #ifdef BEEBEEP_DEBUG
3206   qDebug() << "Opening url (not encoded):" << qPrintable( file_url.toString() );
3207 #endif
3208 
3209   if( file_url.scheme() == QLatin1String( "beeshowsavedchat" ) )
3210   {
3211     QStringList sl_chat_id = file_url.toString().split( "#" );
3212     if( !sl_chat_id.isEmpty() )
3213     {
3214       bool chat_id_is_integer = false;
3215       VNumber chat_id = sl_chat_id.last().toULongLong( &chat_id_is_integer );
3216       if( chat_id_is_integer && chat_id > 0 )
3217       {
3218         QString chat_name = ChatManager::instance().chatName( chat_id );
3219         if( ChatManager::instance().chatHasSavedText( chat_name ) )
3220           showSavedChatSelected( chat_name );
3221         else
3222           QMessageBox::information( QApplication::activeWindow(), Settings::instance().programName(),
3223                                     tr( "There are no messages saved in the chat with %1." ).arg( chat_name ), tr( "Ok" ) );
3224       }
3225       else
3226         qWarning() << "Invalid chat id" << chat_id << "found parsing open history request in GuiMain::openUrl(...)";
3227     }
3228   }
3229   else if( file_url.scheme() == FileInfo::urlSchemeShowFileInFolder() )
3230   {
3231     QUrl adj_file_url = file_url;
3232     adj_file_url.setScheme( QLatin1String( "file" ) );
3233     if( !Bee::showFileInGraphicalShell( Bee::convertToNativeFolderSeparator( adj_file_url.toLocalFile() ) ) )
3234     {
3235       QFileInfo file_info_url( adj_file_url.toLocalFile() );
3236       adj_file_url = QUrl::fromLocalFile( Bee::convertToNativeFolderSeparator( file_info_url.absoluteDir().absolutePath() ) );
3237       openUrlFromChat( adj_file_url, chat_id );
3238       return;
3239     }
3240   }
3241   else if( file_url.scheme() == FileInfo::urlSchemeVoiceMessage() )
3242   {
3243     QUrl adj_file_url = file_url;
3244     adj_file_url.setScheme( QLatin1String( "file" ) );
3245 #ifdef BEEBEEP_USE_VOICE_CHAT
3246     if( Settings::instance().useVoicePlayer() )
3247     {
3248       GuiFloatingChat* fl_chat = floatingChat( chat_id );
3249       if( fl_chat )
3250         fl_chat->guiChat()->guiVoicePlayer()->setFilePath( Bee::convertToNativeFolderSeparator( adj_file_url.toLocalFile() ), chat_id );
3251     }
3252     else
3253 #endif
3254       openUrlFromChat( adj_file_url, chat_id );
3255   }
3256 #if QT_VERSION >= 0x040800
3257   else if( file_url.isLocalFile() )
3258 #else
3259   else if( file_url.scheme() == QLatin1String( "file" ) )
3260 #endif
3261   {
3262     QString file_path = Bee::convertToNativeFolderSeparator( file_url.toLocalFile() );
3263     if( file_path.isEmpty() )
3264     {
3265       qWarning() << "Unable to open an empty file path";
3266       return;
3267     }
3268 
3269     QFileInfo fi( file_path );
3270     if( !fi.exists() )
3271     {
3272       QMessageBox::information( qApp->activeWindow(), Settings::instance().programName(),
3273                                 tr( "%1: no such file or directory." ).arg( file_path.isEmpty() ? file_url.toString() : file_path ), tr( "Ok" ) );
3274       return;
3275     }
3276 
3277 #ifdef Q_OS_MAC
3278     bool is_exe_file = fi.isBundle();
3279 #else
3280     bool is_exe_file = fi.isExecutable() && !fi.isDir();
3281 #endif
3282     if( is_exe_file && QMessageBox::question( qApp->activeWindow(), Settings::instance().programName(),
3283                              tr( "Do you want to open the file %1?" ).arg( file_path ),
3284                              tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
3285       return;
3286 
3287     qDebug() << "Open file:" << file_path;
3288     if( !QDesktopServices::openUrl( QUrl::fromLocalFile( file_path ) ) )
3289       QMessageBox::information( qApp->activeWindow(), Settings::instance().programName(),
3290                               tr( "Unable to open %1" ).arg( file_path.isEmpty() ? file_url.toString() : file_path ), tr( "Ok" ) );
3291   }
3292   else
3293   {
3294     QString url_txt = file_url.toString();
3295     qDebug() << "Open url:" << url_txt;
3296     if( !QDesktopServices::openUrl( file_url ) )
3297       qWarning() << "Unable to open link url:" << url_txt;
3298   }
3299 }
3300 
selectBeepFile()3301 void GuiMain::selectBeepFile()
3302 {
3303   QString file_path = FileDialog::getOpenFileName( false, this, Settings::instance().programName(), Settings::instance().beepFilePath(), tr( "Sound files (*.wav)" ) );
3304   if( file_path.isNull() || file_path.isEmpty() )
3305     return;
3306 
3307   Settings::instance().setBeepFilePath( file_path );
3308   qDebug() << "New sound file selected:" << qPrintable( file_path );
3309 
3310   AudioManager::instance().clearBeep();
3311   AudioManager::instance().playBeep();
3312 
3313   if( !Settings::instance().beepOnNewMessageArrived() )
3314   {
3315     if( QMessageBox::question( this, Settings::instance().programName(), tr( "Sound is not enabled on a new message. Do you want to enable it?" ), tr( "Yes" ), tr( "No" ) ) == 0 )
3316     {
3317       Settings::instance().setBeepOnNewMessageArrived( true );
3318       mp_actBeepOnNewMessage->setChecked( true );
3319     }
3320   }
3321 }
3322 
testBeepFile()3323 void GuiMain::testBeepFile()
3324 {
3325   QString s_default_beep = tr( "The default BEEP will be used" );
3326   if( !AudioManager::instance().isAudioDeviceAvailable() )
3327   {
3328     qWarning() << "Sound device is not available";
3329     QMessageBox::warning( this, Settings::instance().programName(), QString( "%1. %2." ).arg( tr( "Sound module is not working" ), s_default_beep  ) );
3330   }
3331   else if( !QFile::exists( Settings::instance().beepFilePath() ) )
3332   {
3333     QString warn_text = QString( "%1\n%2. %3." ).arg( Settings::instance().beepFilePath() )
3334                                                   .arg( tr( "Sound file not found" ) )
3335                                                   .arg( s_default_beep );
3336     QMessageBox::warning( this, Settings::instance().programName(), warn_text );
3337   }
3338 
3339   playBeep();
3340 }
3341 
playBeep()3342 void GuiMain::playBeep()
3343 {
3344   AudioManager::instance().playBeep();
3345 }
3346 
playBuzz()3347 void GuiMain::playBuzz()
3348 {
3349   AudioManager::instance().playBuzz();
3350 }
3351 
createGroupChat()3352 void GuiMain::createGroupChat()
3353 {
3354   if( !Settings::instance().canAddMembersToGroup() )
3355   {
3356     QMessageBox::information( this, Settings::instance().programName(),
3357                               tr( "You are not allowed create groups." ) + QString( " " ) + tr( "The option has been disabled by your system administrator." ),
3358                               tr( "Ok" ) );
3359     return;
3360   }
3361 
3362   GuiCreateGroup gcg;
3363   gcg.loadData();
3364   gcg.setModal( true );
3365   gcg.show();
3366   gcg.setFixedSize( gcg.size() );
3367   if( gcg.exec() != QDialog::Accepted )
3368     return;
3369 
3370   if( gcg.leaveGroup() )
3371     return;
3372 
3373   Group g = gcg.group();
3374 
3375   Chat c = ChatManager::instance().findGroupChatByUsers( g.usersId() );
3376   if( c.isValid() )
3377   {
3378     if( QMessageBox::question( this, Settings::instance().programName(),
3379                                      QString( "%1\n%2" ).arg( tr( "There is a chat with the same members: %1." ).arg( c.name() ) )
3380                                                         .arg( "How do you want to continue?" ),
3381                                      tr( "Create new group chat" ), tr( "Cancel" ), QString(), 1, 1 ) == 1 )
3382     {
3383       return;
3384     }
3385   }
3386 
3387   c = beeCore->createGroupChat( Settings::instance().localUser(), g, true );
3388   if( c.isValid() )
3389     showChat( c.id() );
3390 }
3391 
editGroupChat(VNumber chat_id)3392 void GuiMain::editGroupChat( VNumber chat_id )
3393 {
3394   Chat c = ChatManager::instance().chat( chat_id );
3395   if( !c.isValid() )
3396     return;
3397 
3398   if( !Settings::instance().canAddMembersToGroup() && !Settings::instance().canRemoveMembersFromGroup() )
3399   {
3400     QMessageBox::information( this, Settings::instance().programName(),
3401                               tr( "You are not allowed modify groups." ) + QString( " " ) + tr( "The option has been disabled by your system administrator." ),
3402                               tr( "Ok" ) );
3403     return;
3404   }
3405 
3406   GuiCreateGroup gcg( activeWindow() );
3407   gcg.init( c.group() );
3408   gcg.loadData();
3409   gcg.setModal( true );
3410   gcg.show();
3411   gcg.setFixedSize( gcg.size() );
3412   if( gcg.exec() == QDialog::Accepted )
3413   {
3414     if( gcg.leaveGroup() )
3415       removeChat( chat_id );
3416     else
3417       beeCore->changeGroupChat( Settings::instance().localUser(), gcg.group() );
3418   }
3419 }
3420 
checkAutoStartOnBoot(bool add_service)3421 void GuiMain::checkAutoStartOnBoot( bool add_service )
3422 {
3423   if( add_service )
3424   {
3425     if( Settings::instance().addStartOnSystemBoot() )
3426     {
3427       QString alert_message = tr( "Now %1 will start on windows boot." ).arg( Settings::instance().programName() );
3428 #ifdef Q_OS_WIN
3429       if( QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8_1 )
3430         alert_message += QString( "\n%1" ).arg( "Note: you have to disable the alert window for unsigned software." );
3431 #endif
3432       QMessageBox::information( this, Settings::instance().programName(), alert_message );
3433     }
3434     else
3435       QMessageBox::warning( this, Settings::instance().programName(), tr( "Unable to add this key in the registry: permission denied." ) );
3436   }
3437   else
3438   {
3439     if( Settings::instance().removeStartOnSystemBoot() )
3440       QMessageBox::information( this, Settings::instance().programName(), tr( "%1 will not start on windows boot." ).arg( Settings::instance().programName() ) );
3441     else
3442       QMessageBox::warning( this, Settings::instance().programName(), tr( "Unable to add this key in the registry: permission denied." ) );
3443   }
3444 }
3445 
loadSession()3446 void GuiMain::loadSession()
3447 {
3448   showMessage( tr( "Starting" ), 3000 );
3449   mp_tabMain->setCurrentWidget( mp_home );
3450   mp_home->loadSystemMessages();
3451   QTimer::singleShot( 100, beeCore, SLOT( buildSavedChatList() ) );
3452 
3453   QTimer::singleShot( Settings::instance().delayConnectionAtStartup(), this, SLOT( startCore() ) );
3454   if( Settings::instance().delayConnectionAtStartup() > 5000 )
3455     qDebug() << "Delay first connection for" << Settings::instance().delayConnectionAtStartup() << "ms";
3456 }
3457 
showSavedChatSelected(const QString & chat_name)3458 void GuiMain::showSavedChatSelected( const QString& chat_name )
3459 {
3460   if( chat_name.isEmpty() )
3461     return;
3462 
3463   foreach( QWidget* w, qApp->allWidgets() )
3464   {
3465     GuiSavedChat* gsv = qobject_cast<GuiSavedChat*>( w );
3466     if( gsv && gsv->savedChatName() == chat_name )
3467     {
3468       gsv->raise();
3469       return;
3470     }
3471   }
3472 
3473   GuiSavedChat* saved_chat = new GuiSavedChat( this );
3474   saved_chat->setAttribute( Qt::WA_DeleteOnClose, true );
3475   saved_chat->resize( qMin( (QApplication::desktop()->availableGeometry().width()-80), 680 ), 420 );
3476   connect( saved_chat, SIGNAL( deleteSavedChatRequest( const QString& ) ), this, SLOT( removeSavedChat( const QString& ) ) );
3477   connect( saved_chat, SIGNAL( openUrl( const QUrl& ) ), this, SLOT( openUrl( const QUrl& ) ) );
3478   saved_chat->showSavedChat( chat_name );
3479   saved_chat->show();
3480 }
3481 
removeSavedChat(const QString & chat_name)3482 void GuiMain::removeSavedChat( const QString& chat_name )
3483 {
3484   if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you want to delete saved chat with %1?" ).arg( chat_name ), tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 1 )
3485     return;
3486 
3487   foreach( QWidget* w, qApp->allWidgets() )
3488   {
3489     GuiSavedChat* gsv = qobject_cast<GuiSavedChat*>( w );
3490     if( gsv && gsv->savedChatName() == chat_name )
3491     {
3492       gsv->close();
3493       break;
3494     }
3495   }
3496   beeCore->removeSavedChat( chat_name );
3497   mp_savedChatList->updateSavedChats();
3498   updateTabTitles();
3499 }
3500 
linkSavedChat(const QString & chat_name)3501 void GuiMain::linkSavedChat( const QString& chat_name )
3502 {
3503   bool ok = false;
3504   QStringList chat_names_string_list = ChatManager::instance().chatNamesToStringList( true );
3505   chat_names_string_list.removeOne( chat_name );
3506 
3507   QString chat_name_selected = QInputDialog::getItem( this, Settings::instance().programName(),
3508                                         tr( "Please select a chat you would like to link the saved text."),
3509                                         chat_names_string_list, 0, false, &ok );
3510   if( !ok )
3511     return;
3512 
3513   bool add_to_existing_saved_text = false;
3514   if( ChatManager::instance().chatHasSavedText( chat_name_selected ) )
3515   {
3516      switch( QMessageBox::question( this, Settings::instance().programName(),
3517                tr( "The chat '%1' selected has already a saved text.<br>"
3518                    "What do you want to do with the selected saved text?" ).arg( chat_name_selected ),
3519                    tr( "Overwrite" ), tr( "Add in the head" ), tr( "Cancel" ), 2, 2 ) )
3520      {
3521      case 0:
3522        break;
3523      case 1:
3524        add_to_existing_saved_text = true;
3525        break;
3526      default:
3527        return;
3528      }
3529 
3530   }
3531 
3532   beeCore->linkSavedChat( chat_name, chat_name_selected, add_to_existing_saved_text );
3533 }
3534 
openWebUrl(const QString & web_url)3535 bool GuiMain::openWebUrl( const QString& web_url )
3536 {
3537   QUrl url( web_url );
3538 
3539   if( !QDesktopServices::openUrl( url ) )
3540   {
3541     QMessageBox::information( this, Settings::instance().programName(), tr( "Unable to open %1" ).arg( web_url ), tr( "Ok" ) );
3542     return false;
3543   }
3544   else
3545     return true;
3546 }
3547 
checkNewVersion()3548 void GuiMain::checkNewVersion()
3549 {
3550   QString url_and_arguments = Settings::instance().checkVersionWebSite();
3551   openWebUrl( url_and_arguments );
3552 }
3553 
openWebSite()3554 void GuiMain::openWebSite()
3555 {
3556   openWebUrl( Settings::instance().officialWebSite() );
3557 }
3558 
openDownloadPluginPage()3559 void GuiMain::openDownloadPluginPage()
3560 {
3561   openWebUrl( Settings::instance().pluginWebSite() );
3562 }
3563 
openDonationPage()3564 void GuiMain::openDonationPage()
3565 {
3566   openWebUrl( Settings::instance().donationWebSite() );
3567 }
3568 
openHelpPage()3569 void GuiMain::openHelpPage()
3570 {
3571   openWebUrl( Settings::instance().helpWebSite() );
3572 }
3573 
openDeveloperWebSite()3574 void GuiMain::openDeveloperWebSite()
3575 {
3576   openWebUrl( Settings::instance().developerWebSite() );
3577 }
3578 
setInIdle()3579 void GuiMain::setInIdle()
3580 {
3581   if( !beeCore->isConnected() )
3582     return;
3583 
3584   if( !Settings::instance().autoUserAway() )
3585     return;
3586 
3587   if( Settings::instance().localUser().status() == User::Away )
3588     return;
3589 
3590   m_lastUserStatus = Settings::instance().localUser().status();
3591   beeCore->setLocalUserStatus( User::Away );
3592   updateStatusIcon();
3593 }
3594 
exitFromIdle()3595 void GuiMain::exitFromIdle()
3596 {
3597   if( !beeCore->isConnected() )
3598     return;
3599 
3600   if( !Settings::instance().autoUserAway() )
3601     return;
3602 
3603   if( Settings::instance().localUser().status() != User::Away )
3604     return;
3605 
3606   beeCore->setLocalUserStatus( m_lastUserStatus );
3607   updateStatusIcon();
3608 }
3609 
updateLocalStatusMessage()3610 void GuiMain::updateLocalStatusMessage()
3611 {
3612   showMessage( Settings::instance().localUser().statusDescription(), 0 );
3613 }
3614 
onStatusBarMessageChanged(const QString & msg)3615 void GuiMain::onStatusBarMessageChanged( const QString& msg )
3616 {
3617   if( msg.isNull() && !Settings::instance().localUser().statusDescription().isEmpty() )
3618     QTimer::singleShot( 0, this, SLOT( updateLocalStatusMessage() ) );
3619 }
3620 
showMessage(const QString & status_msg,int time_out)3621 void GuiMain::showMessage( const QString& status_msg, int time_out )
3622 {
3623   statusBar()->showMessage( status_msg, time_out );
3624   if( status_msg == Settings::instance().localUser().statusDescription() )
3625     statusBar()->setToolTip( tr( "Your status description" ) );
3626   else
3627     statusBar()->setToolTip( "" );
3628 }
3629 
changeUserColor(VNumber user_id,const QString & user_color)3630 void GuiMain::changeUserColor( VNumber user_id, const QString& user_color )
3631 {
3632   QColor c = QColorDialog::getColor( QColor( user_color ), qApp->activeWindow() );
3633   if( c.isValid() )
3634     beeCore->changeUserColor( user_id, c.name() );
3635 }
3636 
onUserChanged(const User & u)3637 void GuiMain::onUserChanged( const User& u )
3638 {
3639   mp_userList->setUser( u, true );
3640   mp_groupList->updateUser( u );
3641   mp_chatList->updateUser( u );
3642   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
3643     fl_chat->updateUser( u );
3644   checkViewActions();
3645   if( u.isLocal() )
3646   {
3647     updateStatusIcon();
3648     updateWindowTitle();
3649   }
3650   else
3651   {
3652     if( m_changeTabToUserListOnFirstConnected && u.isStatusConnected() && mp_tabMain->currentWidget() == mp_home )
3653     {
3654       m_changeTabToUserListOnFirstConnected = false;
3655       mp_tabMain->setCurrentWidget( mp_userList );
3656     }
3657   }
3658 #ifdef BEEBEEP_USE_SHAREDESKTOP
3659   foreach( GuiShareDesktop* gsd, m_desktops )
3660     gsd->onUserChanged( u );
3661 #endif
3662 }
3663 
onUserRemoved(const User & u)3664 void GuiMain::onUserRemoved( const User& u )
3665 {
3666   showMessage( tr( "%1 removed" ).arg( u.name() ), 2000 );
3667   mp_userList->updateUsers();
3668   updateTabTitles();
3669 }
3670 
onChatChanged(const Chat & c)3671 void GuiMain::onChatChanged( const Chat& c )
3672 {
3673 #ifdef BEEBEEP_DEBUG
3674   showMessage( tr( "%1 updated" ).arg( c.name() ), 2000 );
3675 #endif
3676   mp_userList->updateChat( c );
3677   mp_chatList->updateChat( c );
3678   mp_groupList->updateChat( c );
3679   GuiFloatingChat* fl_chat = floatingChat( c.id() );
3680   if( fl_chat )
3681     fl_chat->updateChat( c );
3682   mp_savedChatList->updateSavedChats();
3683   updateTabTitles();
3684   updateNewMessageAction();
3685 }
3686 
onChatRemoved(const Chat & c)3687 void GuiMain::onChatRemoved( const Chat& c )
3688 {
3689   showMessage( tr( "%1 removed" ).arg( c.name() ), 2000 );
3690   GuiFloatingChat* fl_chat = floatingChat( c.id() );
3691   if( fl_chat )
3692     fl_chat->close();
3693   mp_chatList->updateChats();
3694   mp_groupList->updateGroups();
3695   mp_savedChatList->updateSavedChats();
3696   if( mp_trayIcon->chatId() == c.id() )
3697     mp_trayIcon->setUnreadMessages( c.id(), 0 );
3698   updateTabTitles();
3699   updateNewMessageAction();
3700 }
3701 
checkAllChatMembersAreConnected(const QList<VNumber> & users_id)3702 bool GuiMain::checkAllChatMembersAreConnected( const QList<VNumber>& users_id )
3703 {
3704   if( !beeCore->areUsersConnected( users_id ) )
3705   {
3706     if( QMessageBox::question( activeWindow(), Settings::instance().programName(),
3707                                tr( "All the members of this chat are not online. The changes may not be permanent. Do you wish to continue?" ),
3708                                tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
3709        return false;
3710   }
3711   return true;
3712 }
3713 
clearChat(VNumber chat_id)3714 void GuiMain::clearChat( VNumber chat_id )
3715 {
3716   Chat c = ChatManager::instance().chat( chat_id );
3717   if( !c.isValid() )
3718     return;
3719   QString chat_name = c.isDefault() ? QObject::tr( "All users" ).toLower() : c.name();
3720   if( c.isEmpty() && !ChatManager::instance().chatHasSavedText( c.name() ) )
3721   {
3722     QMessageBox::information( activeWindow(), Settings::instance().programName(), tr( "Chat with %1 is empty." ).arg( chat_name ) );
3723     return;
3724   }
3725 
3726   QString question_txt = tr( "Do you want to clear messages with %1?" ).arg( chat_name );
3727   QString button_2_text;
3728   if( ChatManager::instance().chatHasSavedText( c.name() ) )
3729     button_2_text = QString( "  " ) + tr( "Yes and delete history" ) + QString( "  " );
3730 
3731   bool chat_cleared = false;
3732   switch( QMessageBox::information( activeWindow(), Settings::instance().programName(), question_txt, tr( "Yes" ), tr( "No" ), button_2_text, 1, 1 ) )
3733   {
3734   case 0:
3735     chat_cleared = beeCore->clearMessagesInChat( chat_id, false );
3736     break;
3737   case 2:
3738     chat_cleared = beeCore->clearMessagesInChat( chat_id, true );
3739     break;
3740   default:
3741     return;
3742   }
3743 
3744   if( chat_cleared )
3745   {
3746     GuiFloatingChat* fl_chat = floatingChat( chat_id );
3747     if( fl_chat )
3748     {
3749       Chat c = ChatManager::instance().chat( chat_id );
3750       if( c.isValid() )
3751         fl_chat->setChat( c );
3752     }
3753 
3754     if( chat_id == ID_DEFAULT_CHAT )
3755       mp_home->loadSystemMessages();
3756   }
3757 }
3758 
clearSystemMessagesInChat(VNumber chat_id)3759 void GuiMain::clearSystemMessagesInChat( VNumber chat_id )
3760 {
3761   if( beeCore->clearSystemMessagesInChat( chat_id ) )
3762   {
3763     GuiFloatingChat* fl_chat = floatingChat( chat_id );
3764     if( fl_chat )
3765     {
3766       Chat c = ChatManager::instance().chat( chat_id );
3767       if( c.isValid() )
3768         fl_chat->setChat( c );
3769     }
3770 
3771     if( chat_id == ID_DEFAULT_CHAT )
3772       mp_home->loadSystemMessages();
3773   }
3774 }
3775 
removeChat(VNumber chat_id)3776 void GuiMain::removeChat( VNumber chat_id )
3777 {
3778   Chat c = ChatManager::instance().chat( chat_id );
3779   if( !c.isValid() )
3780   {
3781     qWarning() << "Invalid chat" << chat_id << "found in GuiMain::removeChat(...)";
3782     return;
3783   }
3784 
3785   QString button_2_text;
3786   if( ChatManager::instance().chatHasSavedText( c.name() ) )
3787     button_2_text = QString( "  " ) + tr( "Yes and delete history" ) + QString( "  " );
3788   QString question_txt = tr( "Do you want to leave the chat with %1?" ).arg( c.name() );
3789   int answer_id = QMessageBox::question( activeWindow(), Settings::instance().programName(), question_txt, tr( "Yes" ), tr( "No" ), button_2_text, 1, 1 );
3790   if( answer_id == 1 )
3791     return;
3792 
3793   if( !beeCore->removeChat( chat_id, answer_id == 0 ) )
3794     QMessageBox::warning( activeWindow(), Settings::instance().programName(), tr( "Unable to leave the chat with %1." ).arg( c.name() ) );
3795 }
3796 
showSharesForUser(const User & u)3797 void GuiMain::showSharesForUser( const User& u )
3798 {
3799   if( mp_fileSharing )
3800     mp_fileSharing->showUserFileList( u );
3801 }
3802 
selectLanguage()3803 void GuiMain::selectLanguage()
3804 {
3805   GuiLanguage gl;
3806   gl.setModal( true );
3807   gl.loadLanguages();
3808   gl.setSizeGripEnabled( true );
3809   gl.show();
3810 
3811   if( gl.exec() == QDialog::Rejected )
3812     return;
3813 
3814   QString old_language_path = Settings::instance().languageFilePath( Settings::instance().languagePath(), Settings::instance().language() );
3815   QString new_language_path = Settings::instance().languageFilePath( gl.folderSelected(), gl.languageSelected() );
3816 
3817   if( old_language_path != new_language_path )
3818   {
3819     QString language_message;
3820     if( gl.languageSelected().isEmpty() )
3821       language_message = tr( "Default language is restored." );
3822     else
3823       language_message = tr( "New language '%1' is selected." ).arg( gl.languageSelected() );
3824 
3825     QMessageBox::information( this, Settings::instance().programName(),
3826                               QString( "%1<br>%2" ).arg( language_message ).arg( tr( "You must restart %1 to apply these changes." )
3827                                                                                     .arg( Settings::instance().programName() ) ) );
3828 
3829     Settings::instance().setLanguage( gl.languageSelected() );
3830     Settings::instance().setLanguagePath( gl.folderSelected() );
3831   }
3832 }
3833 
showAddUser()3834 void GuiMain::showAddUser()
3835 {
3836   GuiAddUser gad;
3837   gad.loadUsers();
3838   gad.setModal( true );
3839   gad.setSizeGripEnabled( true );
3840   gad.show();
3841 
3842   if( gad.exec() == QDialog::Accepted )
3843   {
3844     if( !Settings::instance().networkAddressList().isEmpty() )
3845     {
3846       beeCore->updateUsersAddedManually();
3847       QMetaObject::invokeMethod( this, "sendBroadcastMessage", Qt::QueuedConnection );
3848     }
3849   }
3850 }
3851 
showChatSettingsMenu()3852 void GuiMain::showChatSettingsMenu()
3853 {
3854   mp_menuChat->clear();
3855   QAction* act = mp_menuChat->addAction( tr( "Use RTL mode to show text" ), this, SLOT( settingsChanged() ) );
3856   act->setCheckable( true );
3857   act->setChecked( Settings::instance().showTextInModeRTL() );
3858   act->setData( 55 );
3859   mp_menuChat->addSeparator();
3860   act = mp_menuChat->addAction( tr( "Show the chat in compact view mode" ), this, SLOT( settingsChanged() ) );
3861   act->setCheckable( true );
3862   act->setChecked( Settings::instance().chatCompact() );
3863   act->setData( 1 );
3864   act = mp_menuChat->addAction( tr( "Show the timestamp" ), this, SLOT( settingsChanged() ) );
3865   act->setCheckable( true );
3866   act->setChecked( Settings::instance().chatShowMessageTimestamp() );
3867   act->setData( 3 );
3868   act = mp_menuChat->addAction( tr( "Show the time with the AM/PM notation" ), this, SLOT( settingsChanged() ) );
3869   act->setCheckable( true );
3870   act->setChecked( Settings::instance().useMessageTimestampWithAP() );
3871   act->setData( 76 );
3872   act = mp_menuChat->addAction( tr( "Show messages grouped by user" ), this, SLOT( settingsChanged() ) );
3873   act->setCheckable( true );
3874   act->setChecked( Settings::instance().showMessagesGroupByUser() );
3875   act->setData( 13 );
3876   act = mp_menuChat->addAction( tr( "Show your name instead of 'You'" ), this, SLOT( settingsChanged() ) );
3877   act->setCheckable( true );
3878   act->setChecked( Settings::instance().chatUseYourNameInsteadOfYou() );
3879   act->setData( 41 );
3880   if( mp_actShowUserFullName->isChecked() )
3881   {
3882     mp_menuChat->addAction( mp_actShowUserFullName );
3883     mp_menuChat->addAction( mp_actShowUserFirstNameFirstInFullName );
3884   }
3885   act = mp_menuChat->addAction( tr( "Show username's color" ), this, SLOT( settingsChanged() ) );
3886   act->setCheckable( true );
3887   act->setChecked( Settings::instance().chatUseColoredUserNames() );
3888   act->setData( 67 );
3889   mp_menuChat->addSeparator();
3890   act = mp_menuChat->addAction( tr( "Show emoticons" ), this, SLOT( settingsChanged() ) );
3891   act->setCheckable( true );
3892   act->setChecked( Settings::instance().showEmoticons() );
3893   act->setData( 10 );
3894   act = mp_menuChat->addAction( tr( "Use HTML tags" ), this, SLOT( settingsChanged() ) );
3895   act->setCheckable( true );
3896   act->setChecked( Settings::instance().chatUseHtmlTags() );
3897   act->setData( 8 );
3898   act = mp_menuChat->addAction( tr( "Use clickable links" ), this, SLOT( settingsChanged() ) );
3899   act->setCheckable( true );
3900   act->setChecked( Settings::instance().chatUseClickableLinks() );
3901   act->setData( 9 );
3902   mp_menuChat->addSeparator();
3903   act = mp_menuChat->addAction( tr( "Clear recent emoticons" ), this, SLOT( settingsChanged() ) );
3904   act->setIcon( IconManager::instance().icon( "clear.png" ) );
3905   act->setData( 104 );
3906   act = mp_menuChat->addAction( tr( "Clear favorite emoticons" ), this, SLOT( settingsChanged() ) );
3907   act->setIcon( IconManager::instance().icon( "clear.png" ) );
3908   act->setData( 106 );
3909   act = mp_menuChat->addAction( tr( "Restore default font" ), this, SLOT( settingsChanged() ) );
3910   act->setIcon( IconManager::instance().icon( "font.png" ) );
3911   act->setData( 23 );
3912   mp_menuChat->exec( QCursor::pos() );
3913 }
3914 
showDefaultServerPortInMenu()3915 void GuiMain::showDefaultServerPortInMenu()
3916 {
3917   QString host_address = tr( "offline" );
3918   QString broadcast_port = tr( "offline" );
3919   QString listener_port = tr( "offline" );
3920   QString file_transfer_port = tr( "offline" );
3921 #ifdef BEEBEEP_USE_MULTICAST_DNS
3922   QString multicast_dns = tr( "inactive" );
3923 #endif
3924   QString multicast_group = tr( "none" );
3925 
3926   if( beeCore->isConnected() )
3927   {
3928     mp_menuNetworkStatus->setIcon( IconManager::instance().icon( "network-connected.png" ) );
3929     mp_actHostAddress->setIcon( IconManager::instance().icon( "network-connected.png" ) );
3930     mp_actHostAddress->setEnabled( true );
3931     mp_actPortBroadcast->setEnabled( true );
3932     mp_actPortListener->setEnabled( true );
3933     mp_actEncryptedConnectionByDefault->setEnabled( true );
3934     mp_actCompressedDataByDefault->setEnabled( true );
3935 
3936     host_address = Settings::instance().localUser().networkAddress().hostAddress().toString();
3937     broadcast_port = QString::number( Settings::instance().defaultBroadcastPort() );
3938     listener_port = QString::number( Settings::instance().localUser().networkAddress().hostPort() );
3939 
3940     QHostAddress multicast_host_address = beeCore->multicastGroupAddress();
3941     mp_actMulticastGroupAddress->setEnabled( !multicast_host_address.isNull() );
3942     if( !multicast_host_address.isNull() )
3943       multicast_group = multicast_host_address.toString();
3944 
3945     if( Settings::instance().enableFileTransfer() )
3946     {
3947       file_transfer_port = QString::number( beeCore->fileTransferPort() );
3948       mp_actPortFileTransfer->setEnabled( true );
3949       if( mp_networkTest )
3950         mp_networkTest->updateSettings( QString::number( beeCore->fileTransferPort() ) );
3951     }
3952     else
3953     {
3954       file_transfer_port = tr( "disabled" );
3955       mp_actPortFileTransfer->setEnabled( false );
3956       if( mp_networkTest )
3957         mp_networkTest->updateSettings( file_transfer_port );
3958     }
3959 
3960 #ifdef BEEBEEP_USE_MULTICAST_DNS
3961     if( beeCore->dnsMulticastingIsActive() )
3962     {
3963 
3964       multicast_dns = tr( "active" );
3965       mp_actMulticastDns->setEnabled( true );
3966     }
3967     else
3968       mp_actMulticastDns->setEnabled( false );
3969 #endif
3970 
3971 
3972   }
3973   else
3974   {
3975     mp_menuNetworkStatus->setIcon( IconManager::instance().icon( "network-disconnected.png" ) );
3976     mp_actHostAddress->setIcon( IconManager::instance().icon( "network-disconnected.png" ) );
3977     mp_actHostAddress->setEnabled( false );
3978     mp_actPortBroadcast->setEnabled( false );
3979     mp_actMulticastGroupAddress->setEnabled( false );
3980     mp_actPortListener->setEnabled( false );
3981     mp_actPortFileTransfer->setEnabled( false );
3982 #ifdef BEEBEEP_USE_MULTICAST_DNS
3983     mp_actMulticastDns->setEnabled( false );
3984 #endif
3985     mp_actEncryptedConnectionByDefault->setEnabled( false );
3986     mp_actCompressedDataByDefault->setEnabled( false );
3987   }
3988 
3989   mp_actHostAddress->setText( QString( "ip: %1 (%2)" ).arg( host_address ).arg( tr( "your IP address" ) ) );
3990   mp_actPortBroadcast->setText( QString( "udp: %1 (%2)" ).arg( broadcast_port ).arg( tr( "to search for users" ) ) );
3991   mp_actMulticastGroupAddress->setText( QString( "multicast: %1" ).arg( multicast_group ) );
3992   mp_actPortListener->setText( QString( "tcp1: %1 (%2)" ).arg( listener_port ).arg( tr( "chat messages" ) ) );
3993   mp_actPortFileTransfer->setText( QString( "tcp2: %1 (%2)" ).arg( file_transfer_port ).arg( tr( "file transfer" ) ) );
3994 #ifdef BEEBEEP_USE_MULTICAST_DNS
3995   mp_actMulticastDns->setText( QString( "mdns: %1" ).arg( multicast_dns ) );
3996 #endif
3997   if( Settings::instance().disableConnectionSocketEncryption() )
3998   {
3999     mp_actEncryptedConnectionByDefault->setIcon( IconManager::instance().icon( "warning.png" ) );
4000     mp_actEncryptedConnectionByDefault->setText( tr( "End-to-end encryption is disabled" ) );
4001   }
4002   else
4003   {
4004     mp_actEncryptedConnectionByDefault->setIcon( IconManager::instance().icon( "encryption-enabled.png" ) );
4005     mp_actEncryptedConnectionByDefault->setText( tr( "End-to-end encryption is enabled" ) );
4006   }
4007 
4008   if( Settings::instance().disableConnectionSocketEncryption() )
4009   {
4010     mp_actCompressedDataByDefault->setIcon( IconManager::instance().icon( "folder.png" ) );
4011     mp_actCompressedDataByDefault->setText( tr( "Data compression is disabled" ) );
4012   }
4013   else
4014   {
4015     mp_actCompressedDataByDefault->setIcon( IconManager::instance().icon( "file-compressed.png" ) );
4016     mp_actCompressedDataByDefault->setText( tr( "Data compression is enabled" ) );
4017   }
4018 }
4019 
sendBroadcastMessage()4020 void GuiMain::sendBroadcastMessage()
4021 {
4022   mp_actBroadcast->setDisabled( true );
4023   beeCore->sendBroadcastMessage();
4024 #ifdef BEEBEEP_USE_MULTICAST_DNS
4025   beeCore->sendDnsMulticastingMessage();
4026 #endif
4027   QTimer::singleShot( 61000, this, SLOT( enableBroadcastAction() ) );
4028 }
4029 
enableBroadcastAction()4030 void GuiMain::enableBroadcastAction()
4031 {
4032   mp_actBroadcast->setEnabled( beeCore->isConnected() );
4033 }
4034 
checkUserSelected(VNumber user_id)4035 void GuiMain::checkUserSelected( VNumber user_id )
4036 {
4037   User u = UserManager::instance().findUser( user_id );
4038   if( !u.isValid() )
4039   {
4040     qWarning() << "Invalid user id" << user_id << "found in check user selected";
4041     return;
4042   }
4043 
4044   Chat c = ChatManager::instance().privateChatForUser( user_id );
4045   if( !c.isValid() )
4046   {
4047     beeCore->createPrivateChat( u );
4048     c = ChatManager::instance().privateChatForUser( user_id );
4049     if( !c.isValid() )
4050     {
4051       qWarning() << "Unable to create private chat for user" << user_id;
4052       return;
4053     }
4054   }
4055   showChat( c.id() );
4056 }
4057 
showConnectionStatusChanged(const User & u)4058 void GuiMain::showConnectionStatusChanged( const User& u )
4059 {
4060   if( !beeCore->isConnected() )
4061     return;
4062 
4063   if( Settings::instance().showOnlyMessageNotificationOnTray() )
4064     return;
4065 
4066   QString msg;
4067   if( u.isStatusConnected() )
4068     msg = tr( "%1 is online" ).arg( u.name() );
4069   else
4070     msg = tr( "%1 is offline" ).arg( u.name() );
4071 
4072   Chat c = ChatManager::instance().privateChatForUser( u.id() );
4073   if( c.isValid() && u.isStatusConnected() )
4074     mp_trayIcon->showUserStatusChanged( c.id(), msg );
4075   else
4076     mp_trayIcon->showUserStatusChanged( ID_DEFAULT_CHAT, msg );
4077 }
4078 
changeAvatarSizeInList()4079 void GuiMain::changeAvatarSizeInList()
4080 {
4081   bool ok = false;
4082   int avatar_size = QInputDialog::getInt( this, Settings::instance().programName(), tr( "Please select the new size of the user picture" ),
4083                                           Settings::instance().avatarIconSize().height(), 16, 96, 4, &ok );
4084   if( !ok )
4085     return;
4086 
4087   Settings::instance().setAvatarIconSize( QSize( avatar_size, avatar_size ) );
4088   mp_userList->updateUsers();
4089   mp_chatList->updateChats();
4090   mp_groupList->updateGroups();
4091   mp_savedChatList->updateSavedChats();
4092   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4093   {
4094     Chat c = ChatManager::instance().chat( fl_chat->guiChat()->chatId() );
4095     if( c.isValid() )
4096       fl_chat->updateChatMembers( c );
4097   }
4098 }
4099 
toggleUserFavorite(VNumber user_id)4100 void GuiMain::toggleUserFavorite( VNumber user_id )
4101 {
4102   beeCore->toggleUserFavorite( user_id );
4103 }
4104 
removeUserFromList(VNumber user_id)4105 void GuiMain::removeUserFromList( VNumber user_id )
4106 {
4107   QString question_txt = tr( "Do you want to delete user %1?" ).arg( UserManager::instance().findUser( user_id ).name() );
4108   if( QMessageBox::question( activeWindow(), Settings::instance().programName(), question_txt, tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
4109     return;
4110   beeCore->removeOfflineUser( user_id );
4111 }
4112 
openResourceFolder()4113 void GuiMain::openResourceFolder()
4114 {
4115   QUrl folder_url = QUrl::fromLocalFile( Settings::instance().resourceFolder() );
4116   openUrl( folder_url );
4117 }
4118 
openDataFolder()4119 void GuiMain::openDataFolder()
4120 {
4121   QUrl folder_url = QUrl::fromLocalFile( Settings::instance().dataFolder() );
4122   openUrl( folder_url );
4123 }
4124 
openDownloadFolder()4125 void GuiMain::openDownloadFolder()
4126 {
4127   QUrl folder_url = QUrl::fromLocalFile( Settings::instance().downloadDirectory() );
4128   openUrl( folder_url );
4129 }
4130 
floatingChat(VNumber chat_id) const4131 GuiFloatingChat* GuiMain::floatingChat( VNumber chat_id ) const
4132 {
4133   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4134   {
4135     if( fl_chat->guiChat()->chatId() == chat_id )
4136       return fl_chat;
4137   }
4138   return Q_NULLPTR;
4139 }
4140 
removeFloatingChatFromList(VNumber chat_id)4141 void GuiMain::removeFloatingChatFromList( VNumber chat_id )
4142 {
4143   GuiFloatingChat* fl_chat = floatingChat( chat_id );
4144   if( !fl_chat )
4145     return;
4146 
4147   if( mp_menuChat->isVisible() )
4148     mp_menuChat->close();
4149 
4150   m_floatingChats.removeOne( fl_chat );
4151   fl_chat->deleteLater();
4152 #ifdef BEEBEEP_DEBUG
4153   qDebug() << "Floating chat" << chat_id << "closed and deleted";
4154 #endif
4155 
4156 #ifdef BEEBEEP_USE_SHAREDESKTOP
4157   onShareDesktopRequestFromChat( chat_id, false );
4158 #endif
4159 }
4160 
createFloatingChat(const Chat & c)4161 GuiFloatingChat* GuiMain::createFloatingChat( const Chat& c )
4162 {
4163   GuiFloatingChat* fl_chat = floatingChat( c.id() );
4164   if( fl_chat )
4165     return fl_chat;
4166 
4167   if( Settings::instance().showChatsInOneWindow() && !m_floatingChats.isEmpty() )
4168     fl_chat = m_floatingChats.first();
4169 
4170   if( !fl_chat )
4171   {
4172     fl_chat = new GuiFloatingChat;
4173     setupChatConnections( fl_chat->guiChat() );
4174     connect( fl_chat, SIGNAL( chatIsAboutToClose( VNumber ) ), this, SLOT( removeFloatingChatFromList( VNumber ) ) );
4175     connect( fl_chat, SIGNAL( readAllMessages( VNumber ) ), this, SLOT( readAllMessagesInChat( VNumber ) ) );
4176     connect( fl_chat, SIGNAL( showVCardRequest( VNumber ) ), this, SLOT( showVCard( VNumber ) ) );
4177     connect( fl_chat, SIGNAL( updateChatFontRequest() ), this, SLOT( updateChatFont() ) );
4178     connect( fl_chat, SIGNAL( updateChatColorsRequest() ), this, SLOT( updateChatColors() ) );
4179 #ifdef BEEBEEP_USE_VOICE_CHAT
4180     connect( fl_chat, SIGNAL( sendVoiceMessageRequest( VNumber, const QString&, qint64 ) ), this, SLOT( sendVoiceMessageToChat( VNumber, const QString&, qint64 ) ) );
4181 #endif
4182 
4183     m_floatingChats.append( fl_chat );
4184     fl_chat->setWindowFlagsAndGeometry();
4185     fl_chat->setSaveGeometryDisabled( Settings::instance().resetGeometryAtStartup() );
4186   }
4187 
4188   if( !fl_chat->setChat( c ) )
4189   {
4190     qWarning() << "Unable to create floating window for not existing chat" << c.id() << c.name();
4191     fl_chat->deleteLater();
4192     return Q_NULLPTR;
4193   }
4194 
4195   return fl_chat;
4196 }
4197 
activeWindow()4198 QWidget* GuiMain::activeWindow()
4199 {
4200   QWidget* active_window = QApplication::activeWindow();
4201   if( active_window )
4202     return active_window;
4203   else
4204     return qobject_cast<QWidget*>( this );
4205 }
4206 
loadUserStatusRecentlyUsed()4207 void GuiMain::loadUserStatusRecentlyUsed()
4208 {
4209   if( !mp_menuUserStatusList->isEmpty() )
4210     mp_menuUserStatusList->clear();
4211 
4212   QList<UserStatusRecord> user_status_list;
4213   foreach( QString s, Settings::instance().userStatusList() )
4214   {
4215     UserStatusRecord usr = Protocol::instance().loadUserStatusRecord( s );
4216     if( usr.isValid() )
4217       user_status_list.append( usr );
4218   }
4219 
4220   if( user_status_list.size() < Settings::instance().maxUserStatusDescriptionInList() )
4221   {
4222     UserStatusRecord usr1;
4223     usr1.setStatus( User::Away );
4224     usr1.setStatusDescription( tr( "at lunch" ) );
4225     if( !user_status_list.contains( usr1 ) )
4226       user_status_list.append( usr1 );
4227   }
4228 
4229   if( user_status_list.size() < Settings::instance().maxUserStatusDescriptionInList() )
4230   {
4231     UserStatusRecord usr2;
4232     usr2.setStatus( User::Busy );
4233     usr2.setStatusDescription( tr( "in a meeting" ) );
4234     if( !user_status_list.contains( usr2 ) )
4235       user_status_list.append( usr2 );
4236   }
4237 
4238   qSort( user_status_list );
4239 
4240   QAction* act;
4241   foreach( UserStatusRecord usr, user_status_list )
4242   {
4243     if( usr.isValid() )
4244     {
4245       act = mp_menuUserStatusList->addAction( Bee::userStatusIcon( usr.status() ), usr.statusDescription(), this, SLOT( recentlyUsedUserStatusSelected() ) );
4246       act->setData( Protocol::instance().saveUserStatusRecord( usr ) );
4247     }
4248   }
4249 }
4250 
recentlyUsedUserStatusSelected()4251 void GuiMain::recentlyUsedUserStatusSelected()
4252 {
4253   QAction* act = qobject_cast<QAction*>( sender() );
4254   if( !act )
4255     return;
4256 
4257   UserStatusRecord usr = Protocol::instance().loadUserStatusRecord( act->data().toString() );
4258   if( usr.isValid() )
4259   {
4260     beeCore->setLocalUserStatusDescription( usr.status(), usr.statusDescription(), false );
4261     setUserStatusSelected( usr.status() );
4262     loadUserStatusRecentlyUsed();
4263     updateLocalStatusMessage();
4264   }
4265 }
4266 
clearRecentlyUsedUserStatus()4267 void GuiMain::clearRecentlyUsedUserStatus()
4268 {
4269   if( QMessageBox::question( this, Settings::instance().programName(),
4270                              tr( "Do you want to clear all saved status descriptions?" ),
4271                              tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
4272     return;
4273 
4274   qDebug() << "User status description list is cleared";
4275   QStringList sl = Settings::instance().userStatusList();
4276   sl.clear();
4277   Settings::instance().setUserStatusList( sl );
4278   loadUserStatusRecentlyUsed();
4279 }
4280 
loadSavedChatsCompleted()4281 void GuiMain::loadSavedChatsCompleted()
4282 {
4283   mp_chatList->updateChats();
4284   mp_savedChatList->updateSavedChats();
4285   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4286     fl_chat->setChat( ChatManager::instance().chat( fl_chat->guiChat()->chatId() ) );
4287   updateTabTitles();
4288 }
4289 
editShortcuts()4290 void GuiMain::editShortcuts()
4291 {
4292   GuiShortcut gs;
4293   gs.setModal( true );
4294   gs.loadShortcuts();
4295   gs.setSizeGripEnabled( true );
4296   gs.show();
4297 
4298   if( gs.exec() == QDialog::Rejected )
4299     return;
4300 
4301   Settings::instance().setShortcuts( ShortcutManager::instance().saveToStringList() );
4302   Settings::instance().save();
4303   updateShortcuts();
4304 }
4305 
updateShortcuts()4306 void GuiMain::updateShortcuts()
4307 {
4308   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4309     fl_chat->guiChat()->updateShortcuts();
4310 
4311   QKeySequence ks = ShortcutManager::instance().shortcut( ShortcutManager::ShowFileTransfers );
4312   if( !ks.isEmpty() && Settings::instance().useShortcuts() )
4313     mp_actViewFileTransfer->setShortcut( ks );
4314   else
4315     mp_actViewFileTransfer->setShortcut( QKeySequence() );
4316 
4317   ks = ShortcutManager::instance().shortcut( ShortcutManager::MinimizeAllChats );
4318   if( !ks.isEmpty() )
4319   {
4320     mp_scMinimizeAllChats->setKey( ks );
4321     mp_scMinimizeAllChats->setEnabled( Settings::instance().useShortcuts() );
4322   }
4323   else
4324     mp_scMinimizeAllChats->setEnabled( false );
4325 
4326 #ifdef BEEBEEP_USE_QXT
4327   ks = ShortcutManager::instance().shortcut( ShortcutManager::ShowAllChats );
4328   if( !ks.isEmpty() && Settings::instance().useShortcuts() )
4329   {
4330     mp_scShowAllChats->setShortcut( ks );
4331     mp_scShowAllChats->setEnabled( true );
4332   }
4333   else
4334   {
4335     mp_scShowAllChats->unsetShortcut();
4336     mp_scShowAllChats->setEnabled( false );
4337   }
4338 #endif
4339   ks = ShortcutManager::instance().shortcut( ShortcutManager::ShowNextUnreadMessage );
4340   if( !ks.isEmpty() )
4341   {
4342     mp_scShowNextUnreadMessage->setKey( ks );
4343     mp_scShowNextUnreadMessage->setEnabled( Settings::instance().useShortcuts() );
4344   }
4345   else
4346     mp_scShowNextUnreadMessage->setEnabled( false );
4347 
4348   ks = ShortcutManager::instance().shortcut( ShortcutManager::Broadcast );
4349   if( !ks.isEmpty() && Settings::instance().useShortcuts() )
4350     mp_actBroadcast->setShortcut( ks );
4351   else
4352     mp_actBroadcast->setShortcut( QKeySequence() );
4353 
4354 }
4355 
minimizeAllChats()4356 void GuiMain::minimizeAllChats()
4357 {
4358   QWidget* w = qApp->activeWindow();
4359 
4360   bool last_active_window_exists = w == this ? true : false;
4361 
4362   if( !m_floatingChats.isEmpty() )
4363   {
4364     foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4365     {
4366       if( !fl_chat->isMinimized() )
4367         fl_chat->showMinimized();
4368       if( fl_chat == mp_lastActiveWindow )
4369         last_active_window_exists = true;
4370     }
4371   }
4372 
4373   if( !isMinimized() )
4374     showMinimized();
4375 
4376   if( last_active_window_exists )
4377     mp_lastActiveWindow = w;
4378 }
4379 
showAllChats()4380 void GuiMain::showAllChats()
4381 {
4382   bool last_active_window_exists = false;
4383 
4384   if( !m_floatingChats.isEmpty() )
4385   {
4386     foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4387     {
4388       if( fl_chat->isMinimized() )
4389         fl_chat->showNormal();
4390       else
4391         fl_chat->show();
4392       fl_chat->raiseOnTop();
4393 
4394       if( fl_chat == mp_lastActiveWindow )
4395         last_active_window_exists = true;
4396     }
4397   }
4398 
4399   if( isMinimized() )
4400     showNormal();
4401   else
4402     show();
4403   raiseOnTop();
4404 
4405   if( this == mp_lastActiveWindow )
4406     last_active_window_exists = true;
4407 
4408   if( last_active_window_exists )
4409   {
4410     mp_lastActiveWindow->raise();
4411     qApp->setActiveWindow( mp_lastActiveWindow );
4412   }
4413 }
4414 
selectDictionatyPath()4415 void GuiMain::selectDictionatyPath()
4416 {
4417   QString dictionary_path = FileDialog::getOpenFileName( false, this, tr( "Select your dictionary path" ), Settings::instance().dictionaryPath(), QString( "*.dic" ) );
4418 
4419   if( dictionary_path.isEmpty() )
4420     return;
4421 
4422   Settings::instance().setDictionaryPath( dictionary_path );
4423 #ifdef BEEBEEP_USE_HUNSPELL
4424   if( SpellChecker::instance().setDictionary( dictionary_path ) )
4425     QMessageBox::information( this, Settings::instance().programName(), tr( "Dictionary selected: %1" ).arg( dictionary_path ) );
4426   else
4427     QMessageBox::warning( this, Settings::instance().programName(), tr( "Unable to set dictionary: %1" ).arg( dictionary_path ) );
4428 #endif
4429   Settings::instance().setUseSpellChecker( true );
4430   Settings::instance().setUseWordCompleter( true );
4431 
4432   // update spellchecker and wordcompleter actions
4433   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4434     fl_chat->guiChat()->updateActionsOnFocusChanged();
4435 }
4436 
onNetworkInterfaceDown()4437 void GuiMain::onNetworkInterfaceDown()
4438 {
4439   if( beeCore->isConnected() )
4440   {
4441     m_autoConnectOnInterfaceUp = true;
4442     QMetaObject::invokeMethod( this, "stopCore", Qt::QueuedConnection );
4443   }
4444   else
4445     m_autoConnectOnInterfaceUp = false;
4446 }
4447 
onNetworkInterfaceUp()4448 void GuiMain::onNetworkInterfaceUp()
4449 {
4450   if( m_autoConnectOnInterfaceUp )
4451     QMetaObject::invokeMethod( this, "startCore", Qt::QueuedConnection );
4452 }
4453 
onTickEvent(int ticks)4454 void GuiMain::onTickEvent( int ticks )
4455 {
4456   int chat_tab_index = mp_tabMain->indexOf( mp_chatList );
4457   if( mp_actViewNewMessage->isEnabled() )
4458   {
4459     QIcon new_message_blinking_icon = IconManager::instance().icon( "beebeep-message.png" );
4460     mp_actViewNewMessage->setIcon( ticks % 2 == 0 ? new_message_blinking_icon : Bee::convertToGrayScale( new_message_blinking_icon, Settings::instance().mainBarIconSize() ) );
4461     mp_tabMain->setTabIcon( chat_tab_index, ticks % 2 == 0 ? new_message_blinking_icon : IconManager::instance().icon( "chat-list.png" ) );
4462     setWindowIcon( ticks % 2 == 0 ? new_message_blinking_icon : IconManager::instance().icon( "beebeep.png" )  );
4463   }
4464 
4465   mp_trayIcon->onTickEvent( ticks );
4466   mp_chatList->onTickEvent( ticks );
4467   mp_userList->onTickEvent( ticks );
4468   mp_groupList->onTickEvent( ticks );
4469   mp_fileTransfer->onTickEvent( ticks );
4470   if( mp_fileSharing )
4471     mp_fileSharing->onTickEvent( ticks );
4472   if( mp_networkTest )
4473     mp_networkTest->onTickEvent( ticks );
4474 
4475   if( beeCore->hasFileTransferInProgress() )
4476     mp_actViewFileTransfer->setIcon( ticks % 2 == 0 ? IconManager::instance().icon( "file-transfer-progress.png" ) : IconManager::instance().icon( "file-transfer.png" ) );
4477 
4478   if( ticks % 2 == 0 && mp_actViewNewMessage->isEnabled() )
4479   {
4480     Chat c = ChatManager::instance().firstChatWithUnreadMessages();
4481     GuiFloatingChat* fl_chat = floatingChat( c.id() );
4482     if( !fl_chat )
4483       QApplication::alert( this, 1000 );
4484     showMessage( tr( "You have new message" ), 1000 );
4485   }
4486 
4487   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4488     fl_chat->onTickEvent( ticks );
4489 
4490 #ifdef BEEBEEP_USE_SHAREDESKTOP
4491   foreach( GuiShareDesktop* gsd, m_desktops )
4492     gsd->onTickEvent( ticks );
4493 #endif
4494 
4495   if( beeApp->isInSleepMode() )
4496     return;
4497 
4498   if( !m_coreIsConnecting )
4499   {
4500     if( Bee::isTimeToCheck( ticks, Settings::instance().tickIntervalCheckIdle() ) )
4501     {
4502       if( beeApp->idleTimeout() > 0 )
4503         QMetaObject::invokeMethod( beeApp, "checkIdle", Qt::QueuedConnection );
4504     }
4505 
4506     beeCore->onTickEvent( ticks );
4507   }
4508 }
4509 
onChatReadByUser(const Chat & c,const User & u)4510 void GuiMain::onChatReadByUser( const Chat& c, const User& u )
4511 {
4512   GuiFloatingChat* fl_chat = floatingChat( c.id() );
4513   if( fl_chat )
4514     fl_chat->setChatReadByUser( c, u );
4515 }
4516 
readAllMessagesInChat(VNumber chat_id)4517 void GuiMain::readAllMessagesInChat( VNumber chat_id )
4518 {
4519   beeCore->readAllMessagesInChat( chat_id );
4520 }
4521 
saveSession(QSessionManager &)4522 void GuiMain::saveSession( QSessionManager& )
4523 {
4524   qDebug() << "Session manager ask to save and close session";
4525   forceShutdown();
4526 }
4527 
updateEmoticons()4528 void GuiMain::updateEmoticons()
4529 {
4530   if( m_floatingChats.isEmpty() )
4531     return;
4532 
4533   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
4534     fl_chat->updateEmoticons();
4535 }
4536 
updateNewMessageAction()4537 void GuiMain::updateNewMessageAction()
4538 {
4539   Chat c = ChatManager::instance().firstChatWithUnreadMessages();
4540   mp_trayIcon->setNextChatToRead( c );
4541   mp_actViewNewMessage->setEnabled( c.isValid() );
4542   int chat_tab_index = mp_tabMain->indexOf( mp_chatList );
4543   if( mp_actViewNewMessage->isEnabled() )
4544   {
4545     mp_actViewNewMessage->setStatusTip( tr( "You have new message" ) );
4546     mp_tabMain->setTabIcon( chat_tab_index, IconManager::instance().icon( "beebeep-message.png" ) );
4547     setWindowIcon( IconManager::instance().icon( "beebeep-message.png" ) );
4548   }
4549   else
4550   {
4551     mp_actViewNewMessage->setStatusTip( "" );
4552     mp_tabMain->setTabIcon( chat_tab_index, IconManager::instance().icon( "chat-list.png" ) );
4553     setWindowIcon( IconManager::instance().icon( "beebeep.png" )  );
4554   }
4555 }
4556 
saveGeometryAndState()4557 void GuiMain::saveGeometryAndState()
4558 {
4559   if( isVisible() )
4560   {
4561     Settings::instance().setGuiGeometry( saveGeometry() );
4562     Settings::instance().setGuiState( saveState() );
4563     Settings::instance().save();
4564   }
4565 }
4566 
askSaveGeometryAndState()4567 void GuiMain::askSaveGeometryAndState()
4568 {
4569   if( isVisible() )
4570   {
4571     QByteArray ba_state = saveState();
4572 #if QT_VERSION == 0x050906
4573     int default_button = mp_dockFileTransfers->isVisible() ? 0 : 1;
4574     int ret_code = QMessageBox::warning( this, Settings::instance().programName(),
4575                                          tr( "Qt libraries have a bug on saving the window's state." ) + QString( " " ) +
4576                                          tr( "If you have layout problem please save only geometry." ),
4577                                          tr( "Save all" ), tr( "Save only geometry" ), tr( "Cancel" ), default_button, 2 );
4578     switch( ret_code )
4579     {
4580     case 0:
4581       break;
4582     case 1:
4583       ba_state = QByteArray();
4584       break;
4585     default:
4586       return;
4587     }
4588  #endif
4589     Settings::instance().setGuiGeometry( saveGeometry() );
4590     Settings::instance().setGuiState( ba_state );
4591     Settings::instance().save();
4592     if( ba_state.isEmpty() )
4593       showMessage( tr( "Window geometry saved" ), 3000 );
4594     else
4595       showMessage( tr( "Window geometry and state saved" ), 3000 );
4596   }
4597 }
4598 
restoreGeometryAndState()4599 void GuiMain::restoreGeometryAndState()
4600 {
4601   restoreGeometry( Settings::instance().guiGeometry() );
4602   if( !Settings::instance().guiState().isEmpty() )
4603     restoreState( Settings::instance().guiState() );
4604 }
4605 
resetGeometryAndState()4606 void GuiMain::resetGeometryAndState()
4607 {
4608   if( mp_dockFileTransfers->isVisible() )
4609     mp_dockFileTransfers->hide();
4610   resize( qMax( width(), 280 ), qMin( 520, qMax( QApplication::desktop()->availableGeometry().height() - 120, 460 ) ) );
4611 
4612 #ifdef Q_OS_WIN
4613   move( QApplication::desktop()->availableGeometry().width() - frameGeometry().width(),
4614         QApplication::desktop()->availableGeometry().height() - frameGeometry().height() );
4615 #elif defined BEEBEEP_FOR_RASPBERRY_PI
4616   move( QApplication::desktop()->availableGeometry().width() - frameGeometry().width(), 70 );
4617 #elif defined Q_OS_MAC
4618   #if QT_VERSION >= 0x050900
4619     move( QApplication::desktop()->availableGeometry().width() - frameGeometry().width(), 0 );
4620   #else
4621     move( QApplication::desktop()->availableGeometry().width() - frameGeometry().width() - 20, 0 );
4622   #endif
4623 #else
4624   move( QApplication::desktop()->availableGeometry().width() - frameGeometry().width(), 0 );
4625 #endif
4626 
4627   if( !Settings::instance().guiGeometry().isEmpty() )
4628     Settings::instance().setGuiGeometry( QByteArray() );
4629   if( !Settings::instance().guiState().isEmpty() )
4630     Settings::instance().setGuiState( QByteArray() );
4631 }
4632 
askResetGeometryAndState()4633 void GuiMain::askResetGeometryAndState()
4634 {
4635   if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you really want to reset window's geometry?" ), tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 0 )
4636   {
4637     resetGeometryAndState();
4638     setMinimumWidthForStyle();
4639     if( !Settings::instance().floatingChatGeometry().isEmpty() )
4640       Settings::instance().setFloatingChatGeometry( QByteArray() );
4641     if( !Settings::instance().floatingChatState().isEmpty() )
4642       Settings::instance().setFloatingChatState( QByteArray() );
4643     if( !Settings::instance().floatingChatSplitterState().isEmpty() )
4644       Settings::instance().setFloatingChatSplitterState( QByteArray() );
4645     if( !Settings::instance().createMessageGeometry().isEmpty() )
4646       Settings::instance().setCreateMessageGeometry( QByteArray() );
4647     if( !Settings::instance().fileSharingGeometry().isEmpty() )
4648       Settings::instance().setFileSharingGeometry( QByteArray() );
4649     Settings::instance().setShowEmoticonMenu( false );
4650     Settings::instance().save();
4651     showMessage( tr( "Geometry of all windows has been reset" ), 3000 );
4652   }
4653 }
4654 
onChangeSettingOnExistingFile(QAction * act)4655 void GuiMain::onChangeSettingOnExistingFile( QAction* act )
4656 {
4657   if( !act )
4658     return;
4659 
4660   Settings::instance().setOnExistingFileAction( act->data().toInt() );
4661   Settings::instance().save();
4662 }
4663 
onFileTransferProgress(VNumber peer_id,const User & u,const FileInfo & fi,FileSizeType bytes,qint64 elapsed_time)4664 void GuiMain::onFileTransferProgress( VNumber peer_id, const User& u, const FileInfo& fi, FileSizeType bytes, qint64 elapsed_time )
4665 {
4666   mp_fileTransfer->setProgress( peer_id, u, fi, bytes, elapsed_time );
4667   if( Settings::instance().alwaysShowFileTransferProgress() )
4668   {
4669     if( !mp_dockFileTransfers->isVisible() )
4670     {
4671       mp_dockFileTransfers->show();
4672       raiseOnTop();
4673     }
4674   }
4675 }
4676 
onFileTransferMessage(VNumber peer_id,const User & u,const FileInfo & fi,const QString & msg,FileTransferPeer::TransferState ft_state)4677 void GuiMain::onFileTransferMessage( VNumber peer_id, const User& u, const FileInfo& fi, const QString& msg, FileTransferPeer::TransferState ft_state )
4678 {
4679   mp_fileTransfer->setMessage( peer_id, u, fi, msg, ft_state );
4680   if( Settings::instance().alwaysShowFileTransferProgress() )
4681   {
4682     if( !mp_dockFileTransfers->isVisible() )
4683     {
4684       mp_dockFileTransfers->show();
4685       raiseOnTop();
4686     }
4687   }
4688 
4689   if( ft_state == FileTransferPeer::Completed )
4690   {
4691     if( !fi.isInShareBox() && fi.isDownload() )
4692     {
4693       Chat c = ChatManager::instance().findChatByPrivateId( fi.chatPrivateId(), false, u.id() );
4694       if( !c.isValid() )
4695       {
4696         qWarning() << "Unable to find chat by private id" << qPrintable( fi.chatPrivateId() ) << "for user" << qPrintable( u.name() ) << "in onFileTransferCompleted(...)";
4697         return;
4698       }
4699 
4700       if( Settings::instance().showFileTransferCompletedOnTray() )
4701         mp_trayIcon->showNewFileArrived( c.id(), tr( "New file from %1" ).arg( u.name() ), false );
4702 
4703       GuiFloatingChat* fl_chat = floatingChat( c.id() );
4704       if( fl_chat && fl_chat->isActiveWindow() )
4705         return;
4706       onChatChanged( c );
4707     }
4708   }
4709 }
4710 
sendBuzzToUser(VNumber user_id)4711 void GuiMain::sendBuzzToUser( VNumber user_id )
4712 {
4713   if( beeCore->isConnected() )
4714     beeCore->sendBuzzToUser( user_id );
4715 }
4716 
showBuzzFromUser(const User & u)4717 void GuiMain::showBuzzFromUser( const User& u )
4718 {
4719   if( Settings::instance().playBuzzSound() )
4720     playBuzz();
4721 
4722   Chat c = ChatManager::instance().privateChatForUser( u.id() );
4723   if( c.isValid() )
4724     mp_trayIcon->showNewMessageArrived( c.id(), tr( "%1 is buzzing you!" ).arg( u.name() ), true );
4725 }
4726 
showFileSharingWindow()4727 void GuiMain::showFileSharingWindow()
4728 {
4729   if( Settings::instance().disableFileSharing() )
4730     return;
4731 
4732   if( !mp_fileSharing )
4733   {
4734     mp_fileSharing = new GuiFileSharing( Q_NULLPTR );
4735     mp_fileSharing->setAttribute( Qt::WA_DeleteOnClose, true );
4736     Bee::setWindowStaysOnTop( mp_fileSharing, Settings::instance().stayOnTop() );
4737     mp_fileSharing->resize( qMin( (QApplication::desktop()->availableGeometry().width()-20), 760 ), 460 );
4738     mp_fileSharing->updateLocalFileList();
4739     connect( mp_fileSharing, SIGNAL( destroyed() ), this, SLOT( onFileSharingWindowClosed() ) );
4740     connect( mp_fileSharing, SIGNAL( openUrlRequest( const QUrl& ) ), this, SLOT( openUrl( const QUrl& ) ) );
4741     connect( mp_fileSharing, SIGNAL( sendFileRequest( const QString& ) ), this, SLOT( sendFile( const QString& ) ) );
4742     connect( mp_fileSharing, SIGNAL( downloadSharedFileRequest( VNumber, VNumber ) ), this, SLOT( downloadSharedFile( VNumber, VNumber ) ) );
4743     connect( mp_fileSharing, SIGNAL( downloadSharedFilesRequest( const QList<SharedFileInfo>& ) ), this, SLOT( downloadSharedFiles( QList<SharedFileInfo> ) ) );
4744     connect( beeCore, SIGNAL( userChanged( const User& ) ), mp_fileSharing, SLOT( onUserChanged( const User& ) ) );
4745   }
4746   mp_fileSharing->showUp();
4747 }
4748 
onFileSharingWindowClosed()4749 void GuiMain::onFileSharingWindowClosed()
4750 {
4751   if( mp_fileSharing )
4752     mp_fileSharing = Q_NULLPTR;
4753 }
4754 
showScreenShotWindow()4755 void GuiMain::showScreenShotWindow()
4756 {
4757   if( !mp_screenShot )
4758   {
4759     mp_screenShot = new GuiScreenShot;
4760     mp_screenShot->setAttribute( Qt::WA_DeleteOnClose, true );
4761     Bee::setWindowStaysOnTop( mp_screenShot, Settings::instance().stayOnTop() );
4762     mp_screenShot->resize( 620,  460 );
4763     connect( mp_screenShot, SIGNAL( screenShotToSend( const QString& ) ), this, SLOT( sendFile( const QString& ) ) );
4764     connect( mp_screenShot, SIGNAL( destroyed() ), this, SLOT( onScreenShotWindowClosed() ) );
4765   }
4766   mp_screenShot->showUp();
4767 }
4768 
onScreenShotWindowClosed()4769 void GuiMain::onScreenShotWindowClosed()
4770 {
4771   if( mp_screenShot )
4772     mp_screenShot = Q_NULLPTR;
4773 }
4774 
showLogWindow()4775 void GuiMain::showLogWindow()
4776 {
4777   if( !mp_log )
4778   {
4779     mp_log = new GuiLog;
4780     Bee::setWindowStaysOnTop( mp_log, Settings::instance().stayOnTop() );
4781     mp_log->resize( qMin( (QApplication::desktop()->availableGeometry().width()-20), 760 ), 460 );
4782     connect( mp_log, SIGNAL( destroyed() ), this, SLOT( onLogWindowClosed() ) );
4783   }
4784   mp_log->showUp();
4785 }
4786 
onLogWindowClosed()4787 void GuiMain::onLogWindowClosed()
4788 {
4789   if( mp_log )
4790     mp_log = Q_NULLPTR;
4791 }
4792 
onMainTabChanged(int tab_index)4793 void GuiMain::onMainTabChanged( int tab_index )
4794 {
4795   if( mp_tabMain->widget( tab_index ) == mp_home )
4796   {
4797     m_unreadActivities = 0;
4798     updateTabTitles();
4799   }
4800 
4801   if( m_changeTabToUserListOnFirstConnected )
4802     m_changeTabToUserListOnFirstConnected = false;
4803 }
4804 
setFileTransferEnabled(bool enable)4805 void GuiMain::setFileTransferEnabled( bool enable )
4806 {
4807   if( Settings::instance().disableFileTransfer() )
4808     return;
4809 
4810   Settings::instance().setEnableFileTransfer( enable );
4811   if( !enable )
4812   {
4813     Settings::instance().setEnableFileSharing( false );
4814     Settings::instance().setUseShareBox( false );
4815     mp_actEnableFileSharing->setChecked( false );
4816     beeCore->stopFileTransferServer();
4817     QMetaObject::invokeMethod( beeCore, "buildLocalShareList", Qt::QueuedConnection );
4818   }
4819   else
4820   {
4821     if( !Bee::folderIsWriteable( Settings::instance().downloadDirectory(), false ) )
4822     {
4823       QMessageBox::warning( this, Settings::instance().programName(), tr( "The download folder does not exists or is not writable. Please select a new one." ), tr( "Ok" ) );
4824       selectDownloadDirectory();
4825     }
4826     beeCore->startFileTransferServer();
4827   }
4828   checkViewActions();
4829 }
4830 
setFileSharingEnabled(bool enable)4831 void GuiMain::setFileSharingEnabled( bool enable )
4832 {
4833   if( Settings::instance().disableFileTransfer() || Settings::instance().disableFileSharing() )
4834     return;
4835 
4836   Settings::instance().setEnableFileSharing( enable );
4837   QMetaObject::invokeMethod( beeCore, "buildLocalShareList", Qt::QueuedConnection );
4838   checkViewActions();
4839   if( !enable )
4840   {
4841     if( mp_fileSharing )
4842       mp_fileSharing->close();
4843   }
4844 }
4845 
showWorkgroups()4846 void GuiMain::showWorkgroups()
4847 {
4848   GuiWorkgroups gw;
4849   gw.loadWorkgroups();
4850   gw.setModal( true );
4851   gw.setSizeGripEnabled( true );
4852   gw.show();
4853   if( gw.exec() != QDialog::Accepted )
4854     return;
4855 
4856   if( Settings::instance().acceptConnectionsOnlyFromWorkgroups() && !Settings::instance().localUser().workgroups().isEmpty() )
4857     qDebug() << "You have selected to accept connections only from these workgroups:" << qPrintable( Settings::instance().localUser().workgroups().join( ", " ) );
4858 
4859   if( gw.restartConnection() )
4860     showRestartConnectionAlertMessage();
4861 }
4862 
showRefusedChats()4863 void GuiMain::showRefusedChats()
4864 {
4865   GuiRefusedChat grc;
4866   int previous_refused_chats = grc.loadRefusedChats();
4867   grc.setModal( true );
4868   grc.setSizeGripEnabled( true );
4869   grc.show();
4870   if( grc.exec() == QDialog::Accepted )
4871   {
4872     showMessage( tr( "%1 blocked chats" ).arg( Settings::instance().refusedChats().size() ), 5000 );
4873     if( previous_refused_chats != ChatManager::instance().refusedChats().size() )
4874       showRestartConnectionAlertMessage();
4875   }
4876 }
4877 
selectIconSourcePath()4878 void GuiMain::selectIconSourcePath()
4879 {
4880   int ret_code = 1;
4881   if( Settings::instance().iconSourcePath().isEmpty() )
4882   {
4883     ret_code = QMessageBox::information( this, Settings::instance().programName(),
4884                                          tr( "You are using the default icons." ),
4885                                          tr( "Select the icon folder" ), tr( "Cancel" ), QString(), 1, 1 );
4886   }
4887   else
4888   {
4889     ret_code = QMessageBox::information( this, Settings::instance().programName(),
4890                                          tr( "You are using custom icons in folder %1." ).arg( Settings::instance().iconSourcePath() ),
4891                                          tr( "Select the icon folder" ), tr( "Cancel" ), tr( "Restore default icons" ), 1, 1 );
4892   }
4893 
4894   if( ret_code == 1 )
4895     return;
4896 
4897   QString icon_source_path = "";
4898   if( ret_code == 0 )
4899   {
4900     icon_source_path = QFileDialog::getExistingDirectory( this, tr( "Select the icon folder" ),
4901                                                                 Settings::instance().iconSourcePath().isEmpty() ? Settings::instance().resourceFolder() : Settings::instance().iconSourcePath() );
4902     if( icon_source_path.isEmpty() )
4903       return;
4904 
4905     icon_source_path = Bee::convertToNativeFolderSeparator( icon_source_path );
4906   }
4907 
4908   if( icon_source_path != Settings::instance().iconSourcePath() )
4909   {
4910     showRestartApplicationAlertMessage();
4911     Settings::instance().setIconSourcePath( icon_source_path );
4912   }
4913 }
4914 
selectEmoticonSourcePath()4915 void GuiMain::selectEmoticonSourcePath()
4916 {
4917   int ret_code = 1;
4918   if( Settings::instance().emoticonSourcePath().isEmpty() )
4919   {
4920     ret_code = QMessageBox::information( this, Settings::instance().programName(),
4921                                          tr( "You are using the default emoticons." ),
4922                                          tr( "Select the emoticon folder" ), tr( "Cancel" ), QString(), 1, 1 );
4923   }
4924   else
4925   {
4926     ret_code = QMessageBox::information( this, Settings::instance().programName(),
4927                                          tr( "You are using custom emoticons in folder %1." ).arg( Settings::instance().emoticonSourcePath() ),
4928                                          tr( "Select the emoticon folder" ), tr( "Cancel" ), tr( "Restore default emoticons" ), 1, 1 );
4929   }
4930 
4931   if( ret_code == 1 )
4932     return;
4933 
4934   QString emoticon_source_path = "";
4935   if( ret_code == 0 )
4936   {
4937     emoticon_source_path = QFileDialog::getExistingDirectory( this, tr( "Select the emoticon folder" ),
4938                                                                   Settings::instance().emoticonSourcePath().isEmpty() ? Settings::instance().resourceFolder() : Settings::instance().emoticonSourcePath() );
4939     if( emoticon_source_path.isEmpty() )
4940       return;
4941 
4942     emoticon_source_path = Bee::convertToNativeFolderSeparator( emoticon_source_path );
4943   }
4944 
4945   if( emoticon_source_path != Settings::instance().emoticonSourcePath() )
4946   {
4947     Settings::instance().setEmoticonSourcePath( emoticon_source_path );
4948     updateEmoticons();
4949   }
4950 }
4951 
showRestartConnectionAlertMessage()4952 void GuiMain::showRestartConnectionAlertMessage()
4953 {
4954   if( QMessageBox::information( this, Settings::instance().programName(), tr( "You have to restart your connection to apply changes." ),
4955                             tr( "Restart connection now" ), tr( "Restart later manually" ), QString(), 0, 1 ) == 0 )
4956   {
4957     QTimer::singleShot( 0, this, SLOT( restartCore() ) );
4958   }
4959 }
4960 
showRestartApplicationAlertMessage()4961 void GuiMain::showRestartApplicationAlertMessage()
4962 {
4963   QMessageBox::information( this, Settings::instance().programName(), tr( "You must restart %1 to apply these changes." ).arg( Settings::instance().programName() ), tr( "Ok" ) );
4964 }
4965 
onNewsAvailable(const QString & news)4966 void GuiMain::onNewsAvailable( const QString& news )
4967 {
4968 #ifdef BEEBEEP_DEBUG
4969   qDebug() << "News from the website available:" << qPrintable( news );
4970 #endif
4971   mp_home->setNews( news );
4972 }
4973 
createMessage()4974 void GuiMain::createMessage()
4975 {
4976   if( Settings::instance().disableCreateMessage() )
4977   {
4978     QMessageBox::information( this, Settings::instance().programName(),
4979                               tr( "You are not allowed create new message." ) + QString( " " ) + tr( "The option has been disabled by your system administrator." ),
4980                               tr( "Ok" ) );
4981     return;
4982   }
4983   GuiCreateMessage gcm;
4984   gcm.setModal( true );
4985   gcm.setSizeGripEnabled( true );
4986   gcm.show();
4987   if( gcm.exec() == QDialog::Accepted )
4988   {
4989     if( !gcm.toChatIdList().isEmpty() )
4990     {
4991       int max_chat_to_open = 6;
4992       int num_chat_opened = 0;
4993       foreach( VNumber chat_id, gcm.toChatIdList() )
4994       {
4995         beeCore->sendChatMessage( chat_id, gcm.message(), gcm.messageIsImportant() );
4996         mp_chatList->updateChat( ChatManager::instance().chat( chat_id ) ); // to sort the chats
4997         if( gcm.openChat() && num_chat_opened < max_chat_to_open )
4998         {
4999           showChat( chat_id );
5000           num_chat_opened++;
5001         }
5002       }
5003       updateTabTitles();
5004     }
5005   }
5006 }
5007 
updateChatFont()5008 void GuiMain::updateChatFont()
5009 {
5010   if( m_floatingChats.isEmpty() )
5011     return;
5012 
5013   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
5014     fl_chat->guiChat()->setChatFont( Settings::instance().chatFont() );
5015 }
5016 
updateChatColors()5017 void GuiMain::updateChatColors()
5018 {
5019   if( m_floatingChats.isEmpty() )
5020     return;
5021 
5022   foreach( GuiFloatingChat* fl_chat, m_floatingChats )
5023   {
5024     if( fl_chat->guiChat()->chatId() != ID_DEFAULT_CHAT )
5025       fl_chat->guiChat()->updateChatColors();
5026   }
5027 }
5028 
resetAllColors()5029 void GuiMain::resetAllColors()
5030 {
5031   if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you really want to restore the colors to the default ones?" ), tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) == 0 )
5032   {
5033     Settings::instance().resetAllColors();
5034     Settings::instance().save();
5035     loadStyle();
5036   }
5037 }
5038 
onHideEmptyChatsRequest()5039 void GuiMain::onHideEmptyChatsRequest()
5040 {
5041   Settings::instance().setHideEmptyChatsInList( !Settings::instance().hideEmptyChatsInList() );
5042   mp_chatList->updateChats();
5043 }
5044 
onApplicationFocusChanged(QWidget * old,QWidget * now)5045 void GuiMain::onApplicationFocusChanged( QWidget* old, QWidget* now )
5046 {
5047   if( old == Q_NULLPTR && isAncestorOf( now )  )
5048   {
5049 #ifdef BEEBEEP_DEBUG
5050     qDebug() << "Main window has grabbed focus";
5051 #endif
5052     m_prevActivatedState = true;
5053     return;
5054   }
5055 
5056   if( isAncestorOf( old ) && now == Q_NULLPTR )
5057   {
5058 #ifdef BEEBEEP_DEBUG
5059     qDebug() << "Main window has lost focus";
5060 #endif
5061     m_prevActivatedState = false;
5062     return;
5063   }
5064 
5065   bool current_state = isActiveWindow();
5066   if( current_state != m_prevActivatedState )
5067   {
5068     m_prevActivatedState = current_state;
5069 #ifdef BEEBEEP_DEBUG
5070     if( current_state )
5071       qDebug() << "Main window has grabbed focus (active)";
5072     else
5073       qDebug() << "Main window has lost focus (active)";
5074 #endif
5075   }
5076 }
5077 
5078 #ifdef BEEBEEP_USE_WEBENGINE
showWebView()5079 void GuiMain::showWebView()
5080 {
5081   mp_webView->show();
5082 }
5083 
onNewsLoad(bool ok)5084 void GuiMain::onNewsLoad( bool ok )
5085 {
5086   mp_actWebView->setEnabled( ok );
5087 }
5088 #endif
5089 
5090 #ifdef BEEBEEP_USE_SHAREDESKTOP
onShareDesktopImageAvailable(const User & u,const QImage & img,const QString & image_type,QRgb diff_color)5091 void GuiMain::onShareDesktopImageAvailable( const User& u, const QImage& img, const QString& image_type, QRgb diff_color )
5092 {
5093   foreach( GuiShareDesktop* gsd, m_desktops )
5094   {
5095     if( gsd->userId() == u.id() )
5096     {
5097       if( img.isNull() )
5098         gsd->close();
5099       else
5100         gsd->updateImage( img, image_type, diff_color );
5101       return;
5102     }
5103   }
5104 
5105   if( img.isNull() )
5106     return;
5107 
5108   int desktop_h = qApp->desktop()->availableGeometry().height() - 50;
5109   int desktop_w = qApp->desktop()->availableGeometry().width() - 80;
5110   int frame_w = frameGeometry().width() - geometry().width();
5111   int frame_h = frameGeometry().height() - geometry().height();
5112   int max_img_w = img.width()+ frame_w;
5113   int max_img_h = img.height()+ frame_h;
5114 
5115   GuiShareDesktop* new_gui = new GuiShareDesktop;
5116   connect( new_gui, SIGNAL( shareDesktopClosed( VNumber ) ), this, SLOT( onShareDesktopCloseEvent( VNumber ) ) );
5117   connect( new_gui, SIGNAL( shareDesktopDeleteRequest( VNumber ) ), this, SLOT( onShareDesktopDeleteRequest( VNumber ) ) );
5118   new_gui->setUser( u );
5119   new_gui->setGeometry( 10, 40, qMin( max_img_w, qMax( 640, desktop_w ) ), qMin( max_img_h, qMax( 480, desktop_h ) ) );
5120   new_gui->setMaximumSize( max_img_w, max_img_h );
5121   new_gui->show();
5122   new_gui->updateImage( img, image_type, diff_color );
5123 
5124   m_desktops.append( new_gui );
5125 }
5126 
onShareDesktopCloseEvent(VNumber user_id)5127 void GuiMain::onShareDesktopCloseEvent( VNumber user_id )
5128 {
5129 #ifdef BEEBEEP_DEBUG
5130   qDebug() << "You close the desktop shared viewer for user" << user_id;
5131 #endif
5132   beeCore->refuseToViewShareDesktop( ID_LOCAL_USER, user_id );
5133 }
5134 
onShareDesktopDeleteRequest(VNumber user_id)5135 void GuiMain::onShareDesktopDeleteRequest( VNumber user_id )
5136 {
5137   QList<GuiShareDesktop*>::iterator it = m_desktops.begin();
5138   while( it != m_desktops.end() )
5139   {
5140     if( (*it)->userId() == user_id )
5141     {
5142 #ifdef BEEBEEP_DEBUG
5143       qDebug() << "Delete GuiShareDesktop for user" << user_id;
5144 #endif
5145       (*it)->disconnect();
5146       (*it)->deleteLater();
5147       m_desktops.erase( it );
5148       return;
5149     }
5150   }
5151 }
5152 
onShareDesktopRequestFromChat(VNumber chat_id,bool enable_desktop_sharing)5153 void GuiMain::onShareDesktopRequestFromChat( VNumber chat_id, bool enable_desktop_sharing )
5154 {
5155   if( chat_id == ID_DEFAULT_CHAT )
5156     return;
5157 
5158   if( beeCore->shareDesktopIsActive( ID_INVALID ) == enable_desktop_sharing )
5159     return;
5160 
5161   Chat c = ChatManager::instance().chat( chat_id );
5162   if( !c.isValid() )
5163   {
5164     qWarning() << "Invalid chat" << chat_id << "found in GuiMain::onShareDesktopRequestFromChat(...)";
5165     return;
5166   }
5167 
5168   if( enable_desktop_sharing )
5169   {
5170     if( QMessageBox::question( activeWindow(), Settings::instance().programName(),
5171                                tr( "Do you really want to share your desktop with %1?" ).arg( c.name() ),
5172                                tr( "Yes" ), tr( "No" ), QString(), 0, 1 ) == 1 )
5173       return;
5174 
5175     foreach( VNumber user_id, c.usersId() )
5176     {
5177       if( user_id != ID_LOCAL_USER )
5178         beeCore->startShareDesktop( user_id );
5179     }
5180   }
5181   else
5182   {
5183     foreach( VNumber user_id, c.usersId() )
5184     {
5185       if( user_id != ID_LOCAL_USER )
5186         beeCore->stopShareDesktop( user_id );
5187     }
5188   }
5189 }
5190 
onShareDesktopUpdate(const User & u)5191 void GuiMain::onShareDesktopUpdate( const User& u )
5192 {
5193   bool core_is_connected = beeCore->isConnected();
5194   int connected_users = beeCore->connectedUsers();
5195   bool file_transfer_is_active = beeCore->isFileTransferActive();
5196   QList<Chat> chat_list = ChatManager::instance().chatsWithUser( u.id() );
5197   foreach( Chat c, chat_list )
5198   {
5199     GuiFloatingChat* fl_chat = floatingChat( c.id() );
5200     if( fl_chat )
5201       fl_chat->guiChat()->updateActions( c, core_is_connected, connected_users, file_transfer_is_active );
5202   }
5203 }
5204 
sendScreenshotToChat(VNumber chat_id)5205 void GuiMain::sendScreenshotToChat( VNumber chat_id )
5206 {
5207   QMetaObject::invokeMethod( beeCore, "sendScreenshotToChat", Qt::QueuedConnection, Q_ARG(VNumber, chat_id) );
5208   GuiFloatingChat* fl_chat = floatingChat( chat_id );
5209   if( fl_chat && fl_chat->isMinimized() )
5210     QTimer::singleShot( 200, fl_chat, SLOT( showNormal() ) );
5211 }
5212 #endif
5213 
showNetworkTest()5214 void GuiMain::showNetworkTest()
5215 {
5216   if( !mp_networkTest )
5217   {
5218     mp_networkTest = new GuiNetworkTest( this );
5219     mp_networkTest->updateSettings( Settings::instance().enableFileTransfer() ? QString::number( beeCore->fileTransferPort() ) : tr( "disabled" ) );
5220     connect( mp_networkTest, SIGNAL( destroyed() ), this, SLOT( onScreenShotWindowClosed() ) );
5221   }
5222   mp_networkTest->showUp();
5223 }
5224 
onNetworkTestWindowClosed()5225 void GuiMain::onNetworkTestWindowClosed()
5226 {
5227   if( mp_networkTest )
5228     mp_networkTest = Q_NULLPTR;
5229 }
5230 
setMinimumWidthForStyle()5231 void GuiMain::setMinimumWidthForStyle()
5232 {
5233   if( Settings::instance().resetMinimumWidthForStyle() )
5234   {
5235     int old_w = width();
5236     int wasted_w = 20;
5237 #if defined( Q_OS_MAC )
5238     int icon_wasted_w = m_useFusionStyle ? 4 : 8;
5239     int min_w = qMax( 300, mp_barMain->actions().size() * (mp_barMain->iconSize().width() + icon_wasted_w) + wasted_w );
5240 #elif defined( Q_OS_UNIX )
5241     int min_w = qMax( 320, mp_barMain->actions().size() * (mp_barMain->iconSize().width()+4) + wasted_w );
5242 #elif defined( Q_OS_WIN )
5243     int min_w = qMax( 320, mp_barMain->actions().size() * (mp_barMain->iconSize().width()+2) + wasted_w );
5244 #else
5245     int min_w = qMax( 320, mp_barMain->actions().size() * (mp_barMain->iconSize().width()+2) + wasted_w );
5246 #endif
5247     setMinimumWidth( min_w );
5248     if( min_w > old_w )
5249     {
5250       int new_pos_x = qMax( 1, pos().x() - (min_w - old_w) );
5251       move( new_pos_x, pos().y() );
5252     }
5253   }
5254   else
5255     setMinimumWidth( 90 );
5256 }
5257 
loadStyle()5258 void GuiMain::loadStyle()
5259 {
5260   QStyle* p_style = QStyleFactory::create( "Fusion" );
5261   if( p_style )
5262   {
5263     beeApp->setStyle( p_style );
5264     m_useFusionStyle = true;
5265   }
5266   else
5267   {
5268     beeApp->resetStyle();
5269     m_useFusionStyle = false;
5270   }
5271 
5272   if( Settings::instance().useDarkStyle() )
5273   {
5274     qDebug() << "Stylesheet:" << (m_useFusionStyle ? "Fusion" : "System Default") << "Dark";
5275     beeApp->setPalette( Bee::darkPalette() );
5276   }
5277   else
5278   {
5279     qDebug() << "Stylesheet:" << (m_useFusionStyle ? "Fusion" : "System Default" );
5280     beeApp->resetPalette();
5281   }
5282 
5283   setMinimumWidthForStyle();
5284 
5285   mp_home->updateBackground();
5286   mp_userList->updateBackground();
5287   mp_chatList->updateBackground();
5288   mp_groupList->updateBackground();
5289   mp_savedChatList->updateBackground();
5290   updateChatColors();
5291   updateEmoticons();
5292 }
5293 
5294 #ifdef BEEBEEP_USE_VOICE_CHAT
sendVoiceMessageToChat(VNumber chat_id,const QString & file_path,qint64 message_duration)5295 void GuiMain::sendVoiceMessageToChat( VNumber chat_id, const QString& file_path, qint64 message_duration )
5296 {
5297   beeCore->sendVoiceMessageToChat( chat_id, file_path, message_duration );
5298 }
5299 
showVoiceEncoderSettings()5300 void GuiMain::showVoiceEncoderSettings()
5301 {
5302   GuiRecordVoiceMessageSettings grvm( this );
5303   grvm.setModal( true );
5304   grvm.init();
5305   grvm.loadSettings();
5306   grvm.show();
5307   if( grvm.exec() == QDialog::Accepted )
5308   {
5309     Settings::instance().save();
5310     AudioManager::instance().checkDefaultAudioDevice();
5311   }
5312 }
5313 #endif
5314 
resumeFileTransfer(VNumber user_id,const FileInfo & file_info)5315 void GuiMain::resumeFileTransfer( VNumber user_id, const FileInfo& file_info )
5316 {
5317   beeCore->resumeFileTransfer( user_id, file_info );
5318 }
5319