File indexing completed on 2024-05-12 05:39:41
0001 /************************************************************************* 0002 * Copyright (C) 2007 by Romain Campioni * 0003 * Copyright (C) 2009 by Renaud Guezennec * 0004 * Copyright (C) 2010 by Berenger Morel * 0005 * Copyright (C) 2010 by Joseph Boudou * 0006 * * 0007 * https://rolisteam.org/ * 0008 * * 0009 * rolisteam is free software; you can redistribute it and/or modify * 0010 * it under the terms of the GNU General Public License as published * 0011 * by the Free Software Foundation; either version 2 of the License, * 0012 * or (at your option) any later version. * 0013 * * 0014 * This program is distributed in the hope that it will be useful, * 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0017 * GNU General Public License for more details. * 0018 * * 0019 * You should have received a copy of the GNU General Public License * 0020 * along with this program; if not, write to the * 0021 * Free Software Foundation, Inc., * 0022 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0023 *************************************************************************/ 0024 #include "dialogs/vmapwizzarddialog.h" 0025 #include <QApplication> 0026 #include <QBitmap> 0027 #include <QBuffer> 0028 #include <QCommandLineParser> 0029 #include <QDesktopServices> 0030 #include <QFileDialog> 0031 #include <QFileInfo> 0032 #include <QLoggingCategory> 0033 #include <QMenuBar> 0034 #include <QMessageBox> 0035 #include <QProcess> 0036 #include <QSettings> 0037 #include <QStatusBar> 0038 #include <QStringBuilder> 0039 #include <QSystemTrayIcon> 0040 #include <QTime> 0041 #include <QUrl> 0042 #include <QUuid> 0043 #include <QWebEngineProfile> 0044 #include <QWebEngineSettings> 0045 #include <algorithm> 0046 0047 #include "mainwindow.h" 0048 #include "ui_mainwindow.h" 0049 0050 #include "common/logcategory.h" 0051 #include "controller/contentcontroller.h" 0052 #include "controller/playercontroller.h" 0053 #include "data/person.h" 0054 #include "data/player.h" 0055 #include "model/historymodel.h" 0056 #include "preferences/preferencesmanager.h" 0057 #include "rwidgets/customs/shortcutvisitor.h" 0058 #include "rwidgets/customs/workspace.h" 0059 #include "rwidgets/dialogs/historyviewerdialog.h" 0060 #include "rwidgets/dialogs/imageselectordialog.h" 0061 #include "rwidgets/dialogs/keygeneratordialog.h" 0062 #include "rwidgets/dialogs/preferencesdialog.h" 0063 #include "rwidgets/dialogs/shortcuteditordialog.h" 0064 #include "rwidgets/dialogs/tipofdayviewer.h" 0065 #include "rwidgets/docks/notificationzone.h" 0066 #include "rwidgets/docks/playerspanel.h" 0067 #include "rwidgets/gmtoolbox/gamemastertool.h" 0068 #include "rwidgets/mediacontainers/mediacontainer.h" 0069 0070 // worker 0071 #include "utils/networkdownloader.h" 0072 #include "worker/iohelper.h" 0073 #include "worker/modelhelper.h" 0074 #include "worker/utilshelper.h" 0075 0076 #include "data/campaignmanager.h" 0077 #include "model/actiononlistmodel.h" 0078 #include "rwidgets/dialogs/campaignproperties.h" 0079 0080 // LOG 0081 #include "common/logcontroller.h" 0082 0083 // Controller 0084 #include "controller/instantmessagingcontroller.h" 0085 #include "controller/networkcontroller.h" 0086 #include "controller/preferencescontroller.h" 0087 #include "controller/view_controller/imageselectorcontroller.h" 0088 0089 // dialogs 0090 #include "rwidgets/dialogs/aboutrolisteam.h" 0091 #include "rwidgets/dialogs/campaignintegritydialog.h" 0092 #include "rwidgets/dialogs/importdatafromcampaigndialog.h" 0093 #include "rwidgets/dialogs/newfiledialog.h" 0094 0095 // GMToolBox 0096 #include "rwidgets/gmtoolbox/NameGenerator/namegeneratorwidget.h" 0097 #include "rwidgets/gmtoolbox/UnitConvertor/convertor.h" 0098 0099 // session 0100 #include "rwidgets/docks/antagonistboard.h" 0101 #include "rwidgets/docks/campaigndock.h" 0102 #include "utils/iohelper.h" 0103 0104 Q_LOGGING_CATEGORY(WidgetClient, "WidgetClient") 0105 0106 MainWindow::MainWindow(GameController* game, const QStringList& args) 0107 : QMainWindow() 0108 , m_gameController(game) 0109 #ifndef NULL_PLAYER 0110 , m_audioPlayer(new AudioPlayer(m_gameController->audioController(), this)) 0111 #endif 0112 , m_dockLogUtil(new NotificationZone(game->logController(), this)) 0113 , m_systemTray(new QSystemTrayIcon) 0114 , m_ui(new Ui::MainWindow) 0115 , m_roomPanelDockWidget(new QDockWidget(this)) 0116 { 0117 parseCommandLineArguments(args); 0118 setAcceptDrops(true); 0119 m_systemTray->setIcon(QIcon::fromTheme("500-symbole")); 0120 m_systemTray->show(); 0121 0122 // ALLOCATIONS 0123 m_campaignDock.reset(new campaign::CampaignDock(m_gameController->campaignManager()->editor())); 0124 connect(m_campaignDock.get(), &campaign::CampaignDock::openResource, this, 0125 [this](const QString& id, const QString& path, Core::ContentType type) 0126 { 0127 std::map<QString, QVariant> vec; 0128 vec.insert({Core::keys::KEY_PATH, path}); 0129 vec.insert({Core::keys::KEY_UUID, id}); 0130 vec.insert({Core::keys::KEY_TYPE, QVariant::fromValue(type)}); 0131 vec.insert({Core::keys::KEY_SERIALIZED, utils::IOHelper::loadFile(path)}); 0132 vec.insert({Core::keys::KEY_INTERNAL, true}); 0133 auto localId= m_gameController->localPlayerId(); 0134 vec.insert({Core::keys::KEY_OWNERID, localId}); 0135 vec.insert({Core::keys::KEY_LOCALID, localId}); 0136 m_gameController->openMedia(vec); 0137 }); 0138 connect(m_campaignDock.get(), &campaign::CampaignDock::removeFile, this, 0139 [this](const QString& path) 0140 { 0141 auto campaignManager= m_gameController->campaignManager(); 0142 campaignManager->removeFile(path); 0143 }); 0144 0145 connect(m_gameController->campaignManager(), &campaign::CampaignManager::createBlankFile, this, 0146 [this](const QString& path, Core::MediaType mediaType) 0147 { 0148 std::map<QString, QVariant> params; 0149 /// TODO change mediaType to ContentType. 0150 params.insert({Core::keys::KEY_TYPE, QVariant::fromValue(mediaType)}); 0151 params.insert({Core::keys::KEY_PATH, path}); 0152 m_gameController->newMedia(params); 0153 }); 0154 0155 connect(m_gameController->campaignManager(), &campaign::CampaignManager::createBlankFile, this, 0156 [this](const QString& path, Core::MediaType mediaType) 0157 { 0158 std::map<QString, QVariant> params; 0159 /// TODO change mediaType to ContentType. 0160 params.insert({Core::keys::KEY_TYPE, QVariant::fromValue(mediaType)}); 0161 params.insert({Core::keys::KEY_PATH, path}); 0162 m_gameController->newMedia(params); 0163 }); 0164 0165 connect(m_gameController, &GameController::dataLoaded, this, 0166 [this](const QStringList missignFiles, const QStringList unmanagedFile) 0167 { 0168 if(missignFiles.isEmpty() && unmanagedFile.isEmpty()) 0169 return; 0170 campaign::CampaignIntegrityDialog dialog(missignFiles, unmanagedFile, m_gameController->campaignRoot(), 0171 this); 0172 auto val= dialog.exec(); 0173 if(val == QDialog::Accepted) 0174 { 0175 auto const& missingActions= dialog.missingFileActions(); 0176 auto const& unmanagedActions= dialog.unmanagedFileActions(); 0177 auto ctrl= m_gameController->campaignManager(); 0178 0179 QList<QPair<QString, Core::CampaignAction>> list; 0180 std::transform(std::begin(missingActions), std::end(missingActions), std::back_inserter(list), 0181 [](const DataInfo& info) 0182 { 0183 return QPair<QString, Core::CampaignAction>( 0184 {info.data, info.indexAction == 0 ? Core::CampaignAction::ForgetAction : 0185 Core::CampaignAction::CreateAction}); 0186 }); 0187 ctrl->performAction(list); 0188 0189 QList<QPair<QString, Core::CampaignAction>> list2; 0190 std::transform(std::begin(unmanagedActions), std::end(unmanagedActions), std::back_inserter(list2), 0191 [](const DataInfo& info) 0192 { 0193 return QPair<QString, Core::CampaignAction>( 0194 {info.data, info.indexAction == 0 ? Core::CampaignAction::ManageAction : 0195 Core::CampaignAction::DeleteAction}); 0196 }); 0197 ctrl->performAction(list2); 0198 } 0199 }); 0200 0201 m_antagonistWidget.reset(new campaign::AntagonistBoard(m_gameController->campaignManager()->editor(), this)); 0202 0203 m_gmToolBoxList.append({new NameGeneratorWidget(this), new GMTOOL::Convertor(this)}); 0204 m_roomPanel= new ChannelListPanel(m_gameController->networkController(), this); 0205 0206 connect(m_gameController, &GameController::updateAvailableChanged, this, &MainWindow::showUpdateNotification); 0207 connect(m_gameController, &GameController::tipOfDayChanged, this, &MainWindow::showTipChecker); 0208 connect(m_gameController, &GameController::localPlayerIdChanged, this, 0209 [this]() { m_roomPanel->setLocalPlayerId(m_gameController->localPlayerId()); }); 0210 0211 m_ui->setupUi(this); 0212 0213 m_separatorAction= m_ui->m_fileMenu->insertSeparator(m_ui->m_closeAction); 0214 m_separatorAction->setVisible(false); 0215 // registerQmlTypes(); 0216 0217 #ifdef HAVE_WEBVIEW 0218 auto defaultProfile= QWebEngineProfile::defaultProfile(); 0219 QWebEngineSettings* defaultSettings= defaultProfile->settings(); 0220 defaultSettings->setAttribute(QWebEngineSettings::PluginsEnabled, true); 0221 defaultSettings->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled, false); 0222 #endif 0223 0224 m_preferences= m_gameController->preferencesManager(); 0225 0226 auto func= [](QVariant var) 0227 { 0228 auto v= var.toInt(); 0229 if(var.isNull()) 0230 v= 6; 0231 VisualItem::setHighlightWidth(v); 0232 }; 0233 m_preferences->registerLambda(QStringLiteral("VMAP::highlightPenWidth"), func); 0234 auto func2= [](QVariant var) 0235 { 0236 auto v= var.value<QColor>(); 0237 if(!v.isValid()) 0238 v= QColor(Qt::red); 0239 VisualItem::setHighlightColor(v); 0240 }; 0241 m_preferences->registerLambda(QStringLiteral("VMAP::highlightColor"), func2); 0242 0243 connect(m_ui->m_mediaTitleAct, &QAction::toggled, this, 0244 [this](bool b) 0245 { m_ui->m_toolBar->setToolButtonStyle(b ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly); }); 0246 0247 connect(m_gameController->contentController(), &ContentController::sessionChanged, this, 0248 &MainWindow::setWindowModified); 0249 connect(m_gameController->contentController(), &ContentController::canPasteChanged, m_ui->m_pasteAct, 0250 &QAction::setEnabled); 0251 0252 connect(m_gameController->networkController(), &NetworkController::connectedChanged, this, 0253 [this](bool connected) 0254 { 0255 if(connected) 0256 postConnection(); 0257 0258 updateWindowTitle(); 0259 m_ui->m_changeProfileAct->setEnabled(connected); 0260 m_ui->m_disconnectAction->setEnabled(connected); 0261 }); 0262 0263 connect(m_gameController->campaign(), &campaign::Campaign::nameChanged, this, &MainWindow::updateWindowTitle); 0264 0265 // connect(m_sessionManager, &SessionManager::openResource, this, 0266 // &MainWindow::openResource); 0267 0268 /// Create all GM toolbox widget 0269 for(auto& gmTool : m_gmToolBoxList) 0270 { 0271 QWidget* wid= dynamic_cast<QWidget*>(gmTool); 0272 0273 if(wid == nullptr) 0274 continue; 0275 0276 QDockWidget* widDock= new QDockWidget(this); 0277 widDock->setAllowedAreas(Qt::AllDockWidgetAreas); 0278 widDock->setWidget(wid); 0279 widDock->setWindowTitle(wid->windowTitle()); 0280 widDock->setObjectName(wid->objectName()); 0281 addDockWidget(Qt::RightDockWidgetArea, widDock); 0282 0283 m_ui->m_gmToolBoxMenu->addAction(widDock->toggleViewAction()); 0284 widDock->setVisible(false); 0285 } 0286 0287 connect(m_gameController->instantMessagingController(), &InstantMessagingController::unreadChanged, this, 0288 [this]() 0289 { 0290 auto ctrl= m_gameController->instantMessagingController(); 0291 m_ui->m_showChatAct->setIcon(ctrl->unread() ? QIcon::fromTheme("chaticon_with_message") : 0292 QIcon::fromTheme("chaticon")); 0293 }); 0294 0295 m_ui->m_pasteAct->setEnabled(m_gameController->contentController()->canPaste()); 0296 0297 // Room List 0298 m_roomPanelDockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); 0299 m_roomPanelDockWidget->setWidget(m_roomPanel); 0300 m_roomPanelDockWidget->setWindowTitle(m_roomPanel->windowTitle()); 0301 m_roomPanelDockWidget->setObjectName(m_roomPanel->objectName()); 0302 m_roomPanelDockWidget->setVisible(false); 0303 addDockWidget(Qt::RightDockWidgetArea, m_roomPanelDockWidget); 0304 0305 connect(m_ui->m_keyGeneratorAct, &QAction::triggered, this, 0306 []() 0307 { 0308 KeyGeneratorDialog dialog; 0309 dialog.exec(); 0310 }); 0311 0312 setupUi(); 0313 readSettings(); 0314 connect(m_ui->m_cleanHistoryAct, &QAction::triggered, m_gameController->contentController(), 0315 &ContentController::clearHistory); 0316 0317 connect(m_gameController->contentController(), &ContentController::historyChanged, this, 0318 &MainWindow::updateFileHistoryMenu); 0319 updateFileHistoryMenu(); 0320 } 0321 0322 MainWindow::~MainWindow()= default; 0323 0324 void MainWindow::setupUi() 0325 { 0326 connect(m_ui->m_showChatAct, &QAction::triggered, m_gameController->instantMessagingController(), 0327 &InstantMessagingController::setVisible); 0328 connect(m_gameController->instantMessagingController(), &InstantMessagingController::visibleChanged, 0329 m_ui->m_showChatAct, &QAction::setChecked); 0330 0331 auto contentCtrl= m_gameController->contentController(); 0332 0333 connect(m_ui->m_pasteAct, &QAction::triggered, contentCtrl, &ContentController::pasteData); 0334 0335 m_mdiArea.reset(new Workspace(m_ui->m_toolBar, contentCtrl, m_gameController->instantMessagingController())); 0336 setCentralWidget(m_mdiArea.get()); 0337 0338 addDockWidget(Qt::RightDockWidgetArea, m_campaignDock.get()); 0339 m_ui->m_menuSubWindows->insertAction(m_ui->m_audioPlayerAct, m_campaignDock->toggleViewAction()); 0340 0341 createNotificationZone(); 0342 /////////////////// 0343 // PlayerList 0344 /////////////////// 0345 auto playersListWidget= new PlayersPanel(m_gameController->playerController(), this); 0346 0347 addDockWidget(Qt::RightDockWidgetArea, playersListWidget); 0348 auto dock= new QDockWidget(); 0349 dock->setObjectName("AntagonistTable"); 0350 dock->setWindowTitle(tr("Antagonist Table")); 0351 dock->setWidget(m_antagonistWidget.get()); 0352 dock->setWindowIcon(QIcon::fromTheme("contact")); 0353 addDockWidget(Qt::RightDockWidgetArea, dock); 0354 setWindowIcon(QIcon::fromTheme("logo")); 0355 m_ui->m_menuSubWindows->insertAction(m_ui->m_characterListAct, playersListWidget->toggleViewAction()); 0356 m_ui->m_menuSubWindows->insertAction(m_ui->m_characterListAct, dock->toggleViewAction()); 0357 m_ui->m_menuSubWindows->removeAction(m_ui->m_characterListAct); 0358 0359 /////////////////// 0360 // Audio Player 0361 /////////////////// 0362 #ifndef NULL_PLAYER 0363 // ReceiveEvent::registerNetworkReceiver(NetMsg::MusicCategory, m_audioPlayer.get()); 0364 addDockWidget(Qt::RightDockWidgetArea, m_audioPlayer.get()); 0365 m_ui->m_menuSubWindows->insertAction(m_ui->m_audioPlayerAct, m_audioPlayer->toggleViewAction()); 0366 m_ui->m_menuSubWindows->removeAction(m_ui->m_audioPlayerAct); 0367 connect(m_audioPlayer.get(), &AudioPlayer::changePlayerDirectory, this, 0368 [this]() { m_preferencesDialog->show(PreferencesDialog::PreferenceTab::Player); }); 0369 #endif 0370 0371 m_preferencesDialog= new PreferencesDialog(m_gameController->preferencesController(), this); 0372 linkActionToMenu(); 0373 } 0374 0375 void MainWindow::closeAllMediaContainer() 0376 { 0377 auto content= m_gameController->contentController(); 0378 content->clear(); 0379 } 0380 0381 void MainWindow::showTipChecker() 0382 { 0383 auto tip= m_gameController->tipOfDay(); 0384 TipOfDayViewer view(tip.title, tip.content, tip.url, this); 0385 view.exec(); 0386 0387 m_preferences->registerValue(QStringLiteral("MainWindow::neverDisplayTips"), view.dontshowAgain()); 0388 } 0389 0390 void MainWindow::closeEvent(QCloseEvent* event) 0391 { 0392 if(mayBeSaved()) 0393 { 0394 m_gameController->aboutToClose(); 0395 writeSettings(); 0396 event->accept(); 0397 } 0398 else 0399 { 0400 event->ignore(); 0401 } 0402 } 0403 void MainWindow::userNatureChange() 0404 { 0405 updateUi(); 0406 updateWindowTitle(); 0407 } 0408 0409 void MainWindow::createNotificationZone() 0410 { 0411 m_dockLogUtil->setObjectName("dockLogUtil"); 0412 m_dockLogUtil->setAllowedAreas(Qt::AllDockWidgetAreas); 0413 m_dockLogUtil->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable 0414 | QDockWidget::DockWidgetFloatable); 0415 0416 m_ui->m_menuSubWindows->insertAction(m_ui->m_notificationAct, m_dockLogUtil->toggleViewAction()); 0417 m_ui->m_menuSubWindows->removeAction(m_ui->m_notificationAct); 0418 addDockWidget(Qt::RightDockWidgetArea, m_dockLogUtil.get()); 0419 } 0420 0421 void MainWindow::linkActionToMenu() 0422 { 0423 connect(m_ui->m_addVectorialMap, &QAction::triggered, this, &MainWindow::newVMap); 0424 m_ui->m_newNoteAction->setData(QVariant::fromValue(Core::ContentType::NOTES)); 0425 m_ui->m_newSharedNote->setData(QVariant::fromValue(Core::ContentType::SHAREDNOTE)); 0426 m_ui->m_openWebViewAct->setData(QVariant::fromValue(Core::ContentType::WEBVIEW)); 0427 m_ui->m_newMindmap->setData(QVariant::fromValue(Core::ContentType::MINDMAP)); 0428 0429 auto callNewMedia= [this]() 0430 { 0431 auto act= qobject_cast<QAction*>(sender()); 0432 std::map<QString, QVariant> params; 0433 if(!m_gameController->localIsGM()) 0434 { 0435 QUrl dir; 0436 QString filter; 0437 NewFileDialog dial(act->data().value<Core::ContentType>()); 0438 if(QDialog::Rejected == dial.exec()) 0439 return; 0440 params.insert({Core::keys::KEY_TYPE, static_cast<int>(dial.type())}); 0441 params.insert({Core::keys::KEY_URL, dial.url()}); 0442 params.insert({Core::keys::KEY_NAME, dial.name()}); 0443 } 0444 else 0445 { 0446 params.insert({Core::keys::KEY_TYPE, act->data()}); 0447 } 0448 0449 m_gameController->newMedia(params); 0450 }; 0451 0452 connect(m_ui->m_newNoteAction, &QAction::triggered, this, callNewMedia); 0453 connect(m_ui->m_newSharedNote, &QAction::triggered, this, callNewMedia); 0454 connect(m_ui->m_newMindmap, &QAction::triggered, this, callNewMedia); 0455 0456 // open 0457 connect(m_ui->m_openPictureAction, &QAction::triggered, this, &MainWindow::openImage); 0458 connect(m_ui->m_openCharacterSheet, &QAction::triggered, this, &MainWindow::openGenericContent); 0459 connect(m_ui->m_openWebViewAct, &QAction::triggered, this, 0460 [this]() 0461 { 0462 auto str= QInputDialog::getText(this, tr("Open Webpage"), tr("Webpage url:")); 0463 if(str.isEmpty()) 0464 return; 0465 std::map<QString, QVariant> params; 0466 params.insert({Core::keys::KEY_TYPE, QVariant::fromValue(Core::ContentType::WEBVIEW)}); 0467 QUrl url= QUrl::fromUserInput(str); 0468 params.insert({Core::keys::KEY_NAME, url.fileName()}); 0469 params.insert({Core::keys::KEY_PATH, str}); 0470 m_gameController->newMedia(params); 0471 }); 0472 connect(m_ui->m_openVectorialMap, &QAction::triggered, this, 0473 []() 0474 { 0475 // TODO open vmap 0476 }); 0477 connect(m_ui->m_openCampaignAction, &QAction::triggered, this, &MainWindow::openCampaign); 0478 connect(m_ui->m_openNoteAction, &QAction::triggered, this, &MainWindow::openGenericContent); 0479 connect(m_ui->m_openShareNote, &QAction::triggered, this, &MainWindow::openGenericContent); 0480 connect(m_ui->m_openPdfAct, &QAction::triggered, this, &MainWindow::openGenericContent); 0481 connect(m_ui->m_openMindmap, &QAction::triggered, this, &MainWindow::openGenericContent); 0482 0483 connect(m_ui->m_importFromCampaign, &QAction::triggered, this, 0484 [this]() 0485 { 0486 ImportDataFromCampaignDialog dialog(m_gameController->campaignRoot(), this); 0487 0488 if(dialog.exec() == QDialog::Accepted) 0489 { 0490 /// TODO call controller to import data. 0491 auto src= dialog.source(); 0492 auto cats= dialog.categoryList(); 0493 auto manager= m_gameController->campaignManager(); 0494 manager->importDataFrom(src, cats); 0495 } 0496 }); 0497 0498 connect(m_ui->m_shortCutEditorAct, &QAction::triggered, this, &MainWindow::showShortCutEditor); 0499 0500 m_ui->m_openPictureAction->setData(static_cast<int>(Core::ContentType::PICTURE)); 0501 // m_ui->m_openOnlinePictureAction->setData(static_cast<int>(Core::ContentType::ONLINEPICTURE)); 0502 m_ui->m_openCharacterSheet->setData(static_cast<int>(Core::ContentType::CHARACTERSHEET)); 0503 m_ui->m_openVectorialMap->setData(static_cast<int>(Core::ContentType::VECTORIALMAP)); 0504 m_ui->m_openNoteAction->setData(static_cast<int>(Core::ContentType::NOTES)); 0505 m_ui->m_openShareNote->setData(static_cast<int>(Core::ContentType::SHAREDNOTE)); 0506 m_ui->m_openMindmap->setData(static_cast<int>(Core::ContentType::MINDMAP)); 0507 m_ui->m_openPdfAct->setData(static_cast<int>(Core::ContentType::PDF)); 0508 0509 // m_ui->m_recentFileMenu->setVisible(false); 0510 connect(m_ui->m_closeAction, &QAction::triggered, m_mdiArea.get(), &Workspace::closeActiveSub); 0511 connect(m_ui->m_saveCampaignAction, &QAction::triggered, m_gameController, &GameController::save); 0512 connect(m_ui->m_saveCampaignAsAct, &QAction::triggered, this, 0513 [this]() 0514 { 0515 QString fileName= QFileDialog::getExistingDirectory(this, tr("Open Campaign"), 0516 m_gameController->campaign()->rootDirectory()); 0517 if(fileName.isEmpty()) 0518 return; 0519 m_gameController->saveAs(fileName); 0520 }); 0521 connect(m_ui->m_preferencesAction, &QAction::triggered, m_preferencesDialog, 0522 [this]() { m_preferencesDialog->show(); }); 0523 0524 // Campaign 0525 auto func= [this]() 0526 { 0527 auto s= qobject_cast<QAction*>(sender()); 0528 if(nullptr == s) 0529 return; 0530 auto tab= s->data().value<CampaignProperties::Tab>(); 0531 CampaignProperties dialog(m_gameController->campaign(), m_gameController->preferencesController()->themeModel(), 0532 this); 0533 dialog.setCurrentTab(tab); 0534 dialog.exec(); 0535 }; 0536 m_ui->m_diceAliasAct->setData(QVariant::fromValue(CampaignProperties::Tab::Dice)); 0537 m_ui->m_statesAct->setData(QVariant::fromValue(CampaignProperties::Tab::States)); 0538 m_ui->m_campaignPropertiesAct->setData(QVariant::fromValue(CampaignProperties::Tab::Properties)); 0539 0540 connect(m_ui->m_diceAliasAct, &QAction::triggered, this, func); 0541 connect(m_ui->m_statesAct, &QAction::triggered, this, func); 0542 connect(m_ui->m_campaignPropertiesAct, &QAction::triggered, this, func); 0543 0544 // Edition 0545 // Windows managing 0546 connect(m_ui->m_cascadeViewAction, &QAction::triggered, m_mdiArea.get(), &Workspace::cascadeSubWindows); 0547 connect(m_ui->m_tabViewAction, &QAction::triggered, m_mdiArea.get(), &Workspace::setTabbedMode); 0548 connect(m_ui->m_tileViewAction, &QAction::triggered, m_mdiArea.get(), &Workspace::tileSubWindows); 0549 0550 connect(m_ui->m_fullScreenAct, &QAction::triggered, this, 0551 [=](bool enable) 0552 { 0553 if(enable) 0554 { 0555 showFullScreen(); 0556 m_mdiArea->addAction(m_ui->m_fullScreenAct); 0557 menuBar()->setVisible(false); 0558 m_mdiArea->setMouseTracking(true); 0559 setMouseTracking(true); 0560 } 0561 else 0562 { 0563 showNormal(); 0564 menuBar()->setVisible(true); 0565 m_mdiArea->setMouseTracking(false); 0566 setMouseTracking(false); 0567 m_mdiArea->removeAction(m_ui->m_fullScreenAct); 0568 } 0569 }); 0570 0571 auto undoStack= m_gameController->undoStack(); 0572 0573 auto redo= undoStack->createRedoAction(this, tr("&Redo")); 0574 auto undo= undoStack->createUndoAction(this, tr("&Undo")); 0575 0576 redo->setIcon(QIcon::fromTheme("redo")); 0577 undo->setIcon(QIcon::fromTheme("undo")); 0578 0579 undo->setShortcut(QKeySequence::Undo); 0580 redo->setShortcut(QKeySequence::Redo); 0581 auto acts= m_ui->m_toolBar->actions(); 0582 auto firstAct= acts.first(); 0583 0584 m_ui->m_toolBar->insertAction(firstAct, undo); 0585 m_ui->m_toolBar->insertAction(firstAct, redo); 0586 0587 connect(undoStack, &QUndoStack::cleanChanged, this, [this](bool clean) { setWindowModified(!clean); }); 0588 0589 m_ui->m_editMenu->insertAction(m_ui->m_shortCutEditorAct, redo); 0590 m_ui->m_editMenu->insertAction(redo, undo); 0591 m_ui->m_editMenu->insertSeparator(m_ui->m_shortCutEditorAct); 0592 0593 // close 0594 connect(m_ui->m_quitAction, &QAction::triggered, this, &MainWindow::close); 0595 0596 // network 0597 connect(m_ui->m_disconnectAction, &QAction::triggered, m_gameController->networkController(), 0598 &NetworkController::stopConnection); 0599 connect(m_ui->m_connectionLinkAct, &QAction::triggered, this, 0600 [this]() 0601 { 0602 QString str("rolisteam://%1/%2/%3"); 0603 auto networkCtrl= m_gameController->networkController(); 0604 0605 auto* clipboard= QGuiApplication::clipboard(); 0606 clipboard->setText(str.arg(networkCtrl->host()) 0607 .arg(networkCtrl->port()) 0608 .arg(QString::fromUtf8(networkCtrl->serverPassword().toBase64()))); 0609 }); 0610 connect(m_ui->m_roomListAct, &QAction::triggered, m_roomPanelDockWidget, &QDockWidget::setVisible); 0611 // Help 0612 connect(m_ui->m_aboutAction, &QAction::triggered, this, 0613 [this]() 0614 { 0615 AboutRolisteam diag(m_gameController->version(), this); 0616 diag.exec(); 0617 }); 0618 connect(m_ui->m_onlineHelpAction, &QAction::triggered, this, &MainWindow::helpOnLine); 0619 0620 m_ui->m_supportRolisteam->setData(QStringLiteral("https://liberapay.com/Rolisteam/donate")); 0621 m_ui->m_patreon->setData(QStringLiteral("https://www.patreon.com/rolisteam")); 0622 connect(m_ui->m_supportRolisteam, &QAction::triggered, this, &MainWindow::showSupportPage); 0623 connect(m_ui->m_patreon, &QAction::triggered, this, &MainWindow::showSupportPage); 0624 0625 connect(m_ui->m_manageHistoryAct, &QAction::triggered, this, 0626 [this]() 0627 { 0628 auto ctrl= m_gameController->contentController(); 0629 HistoryViewerDialog dialog(ctrl->historyModel(), this); 0630 dialog.exec(); 0631 updateFileHistoryMenu(); 0632 }); 0633 } 0634 0635 void MainWindow::showSupportPage() 0636 { 0637 auto act= qobject_cast<QAction*>(sender()); 0638 if(nullptr == act) 0639 return; 0640 0641 QString url= act->data().toString(); 0642 if(!QDesktopServices::openUrl(QUrl(url))) //"https://liberapay.com/Rolisteam/donate" 0643 { 0644 QMessageBox msgBox(QMessageBox::Information, tr("Support"), 0645 tr("The %1 donation page can be found online at :<br> <a " 0646 "href=\"%2\">%2</a>") 0647 .arg(m_preferences->value("Application_Name", "rolisteam").toString(), url), 0648 QMessageBox::Ok); 0649 msgBox.exec(); 0650 } 0651 } 0652 0653 void MainWindow::mouseMoveEvent(QMouseEvent* event) 0654 { 0655 if(isFullScreen()) 0656 { 0657 if(qFuzzyCompare(event->windowPos().y(), 0.0)) 0658 { 0659 menuBar()->setVisible(true); 0660 } 0661 else if(event->windowPos().y() > 100) 0662 { 0663 menuBar()->setVisible(false); 0664 } 0665 } 0666 QMainWindow::mouseMoveEvent(event); 0667 } 0668 0669 void MainWindow::makeVisible(bool value) 0670 { 0671 if(value) 0672 m_preferences->value("FullScreenAtStarting", true).toBool() ? showMaximized() : show(); 0673 else 0674 QMainWindow::setVisible(value); 0675 } 0676 0677 void MainWindow::newVMap() 0678 { 0679 MapWizzardDialog mapWizzard(m_mdiArea.get()); 0680 if(mapWizzard.exec()) 0681 { 0682 std::map<QString, QVariant> params; 0683 params.insert({QStringLiteral("name"), mapWizzard.name()}); 0684 params.insert({QStringLiteral("permission"), mapWizzard.permission()}); 0685 params.insert({QStringLiteral("bgcolor"), mapWizzard.backgroundColor()}); 0686 params.insert({QStringLiteral("gridSize"), mapWizzard.gridSize()}); 0687 params.insert({QStringLiteral("gridPattern"), QVariant::fromValue(mapWizzard.pattern())}); 0688 params.insert({QStringLiteral("gridColor"), mapWizzard.gridColor()}); 0689 params.insert({QStringLiteral("visibility"), mapWizzard.visibility()}); 0690 params.insert({QStringLiteral("scale"), mapWizzard.scale()}); 0691 params.insert({QStringLiteral("unit"), mapWizzard.unit()}); 0692 params.insert({Core::keys::KEY_TYPE, QVariant::fromValue(Core::ContentType::VECTORIALMAP)}); 0693 m_gameController->newMedia(params); 0694 } 0695 } 0696 0697 bool MainWindow::mayBeSaved(bool connectionLoss) 0698 { 0699 QMessageBox msgBox(this); 0700 QAbstractButton* saveBtn= msgBox.addButton(QMessageBox::Save); 0701 QAbstractButton* quitBtn= msgBox.addButton(tr("Quit"), QMessageBox::RejectRole); 0702 Qt::WindowFlags flags= msgBox.windowFlags(); 0703 msgBox.setWindowFlags(flags ^ Qt::WindowSystemMenuHint); 0704 0705 QString message; 0706 QString msg= m_preferences->value("Application_Name", "rolisteam").toString(); 0707 if(connectionLoss) 0708 { 0709 message= tr("Connection has been lost. %1 will be close").arg(msg); 0710 msgBox.setIcon(QMessageBox::Critical); 0711 msgBox.setWindowTitle(tr("Connection lost")); 0712 } 0713 else 0714 { 0715 msgBox.setIcon(QMessageBox::Information); 0716 msgBox.addButton(QMessageBox::Cancel); 0717 msgBox.setWindowTitle(tr("Quit %1 ").arg(msg)); 0718 } 0719 return true; 0720 } 0721 0722 void MainWindow::openCampaign() 0723 { 0724 QString fileName 0725 = QFileDialog::getExistingDirectory(this, tr("Open Campaign"), m_gameController->campaign()->rootDirectory()); 0726 0727 m_gameController->setCampaignRoot(fileName); 0728 } 0729 0730 bool MainWindow::saveStory(bool saveAs) 0731 { 0732 /*auto contentCtrl= m_gameController->contentController(); 0733 if(contentCtrl->sessionPath().isEmpty() || saveAs) 0734 { 0735 QString fileName= QFileDialog::getSaveFileName( 0736 this, tr("Save Scenario as"), m_preferences->value("SessionDirectory", QDir::homePath()).toString(), 0737 tr("Scenarios (*.sce)")); 0738 if(fileName.isNull()) 0739 { 0740 return false; 0741 } 0742 if(!fileName.endsWith(".sce")) 0743 { 0744 fileName.append(QStringLiteral(".sce")); 0745 } 0746 contentCtrl->setSessionPath(fileName); 0747 } 0748 QFileInfo info(contentCtrl->sessionPath()); 0749 m_preferences->registerValue("SessionDirectory", info.absolutePath()); 0750 contentCtrl->saveSession(); 0751 updateWindowTitle();*/ 0752 return true; 0753 } 0754 //////////////////////////////////////////////////// 0755 // Save data 0756 //////////////////////////////////////////////////// 0757 /*void MainWindow::saveCurrentMedia() 0758 { 0759 0760 auto content= m_gameController->contentController(); 0761 auto mediaId= content->currentMediaId(); 0762 auto media= content->media(mediaId); 0763 0764 if(!media) 0765 return; 0766 0767 QString dest= media->path(); 0768 QUrl url(dest); 0769 if(qobject_cast<QAction*>(sender()) == m_ui->m_saveAsAction || dest.isEmpty() || !url.isLocalFile()) 0770 { 0771 auto type= media->contentType(); 0772 auto filter= CleverURI::getFilterForType(type); 0773 auto key= m_preferences->value(, QDir::homePath()).toString(); 0774 QFileDialog::getSaveFileName(this, tr("Save %1").arg(media->name()), key, filter); 0775 } 0776 }*/ 0777 0778 void MainWindow::stopReconnection() 0779 { 0780 m_ui->m_changeProfileAct->setEnabled(true); 0781 m_ui->m_disconnectAction->setEnabled(false); 0782 } 0783 0784 void MainWindow::setUpNetworkConnection() 0785 { 0786 connect(m_gameController, &GameController::localIsGMChanged, this, &MainWindow::userNatureChange); 0787 auto networkCtrl= m_gameController->networkController(); 0788 connect(networkCtrl, &NetworkController::downloadingData, m_dockLogUtil.get(), &NotificationZone::receiveData); 0789 } 0790 0791 void MainWindow::helpOnLine() 0792 { 0793 if(!QDesktopServices::openUrl(QUrl("http://doc.rolisteam.org/"))) 0794 { 0795 QMessageBox* msgBox= new QMessageBox(QMessageBox::Information, tr("Help"), 0796 tr("Documentation of %1 can be found online at :<br> <a " 0797 "href=\"http://doc.rolisteam.org\">http://doc.rolisteam.org/</a>") 0798 .arg(m_preferences->value("Application_Name", "rolisteam").toString()), 0799 QMessageBox::Ok); 0800 msgBox->exec(); 0801 } 0802 } 0803 void MainWindow::updateUi() 0804 { 0805 auto isGM= m_gameController->localIsGM(); 0806 m_ui->m_addVectorialMap->setEnabled(isGM); 0807 m_ui->m_openVectorialMap->setEnabled(isGM); 0808 m_ui->m_openCharacterSheet->setEnabled(isGM); 0809 0810 m_ui->m_openCampaignAction->setEnabled(isGM); 0811 m_ui->m_closeAction->setEnabled(isGM); 0812 m_ui->m_saveCampaignAction->setEnabled(isGM); 0813 m_ui->m_saveCampaignAsAct->setEnabled(isGM); 0814 m_ui->m_connectionLinkAct->setVisible(m_gameController->networkController()->hosting()); 0815 m_ui->m_changeProfileAct->setEnabled(false); 0816 m_ui->m_disconnectAction->setEnabled(true); 0817 0818 if(isGM) 0819 { 0820 auto act= m_ui->m_historyMenu->menuAction(); 0821 m_ui->menubar->removeAction(act); 0822 } 0823 else 0824 { 0825 auto act= m_ui->m_campaignMenu->menuAction(); 0826 m_ui->menubar->removeAction(act); 0827 } 0828 } 0829 void MainWindow::showUpdateNotification() 0830 { 0831 QMessageBox::information(this, tr("Update Notification"), 0832 tr("The %1 version has been released. " 0833 "Please take a look at <a " 0834 "href=\"http://www.rolisteam.org/download\">Download page</a> for " 0835 "more " 0836 "information") 0837 .arg(m_gameController->remoteVersion())); 0838 } 0839 0840 void MainWindow::notifyAboutAddedPlayer(Player* player) const 0841 { 0842 m_gameController->addFeatureLog(tr("%1 just joins the game.").arg(player->name()), logns::cat::network); 0843 if(player->userVersion().compare(m_gameController->version()) != 0) 0844 { 0845 m_gameController->addErrorLog( 0846 tr("%1 has not the right version: %2.").arg(player->name(), player->userVersion()), logns::cat::network); 0847 } 0848 } 0849 0850 void MainWindow::notifyAboutDeletedPlayer(Player* player) const 0851 { 0852 m_gameController->addFeatureLog(tr("%1 just leaves the game.").arg(player->name()), logns::cat::network); 0853 } 0854 0855 void MainWindow::readSettings() 0856 { 0857 QSettings settings(Core::settings::KEY_ROLISTEAM, 0858 QString(Core::settings::KEY_PREF_DIR).arg(m_gameController->version())); 0859 0860 restoreState(settings.value(Core::settings::KEY_WINDOW_STATE).toByteArray()); 0861 bool maxi= settings.value(Core::settings::KEY_MAXIMIZED, false).toBool(); 0862 m_ui->m_mediaTitleAct->setChecked(settings.value(Core::settings::KEY_MEDIA_TITLE, false).toBool()); 0863 if(!maxi) 0864 { 0865 restoreGeometry(settings.value(Core::settings::KEY_GEOMETRY).toByteArray()); 0866 } 0867 0868 m_antagonistWidget->setFullMode(settings.value(Core::settings::KEY_ANTA_FULLMODE, false).toBool()); 0869 m_antagonistWidget->setMinimalMode(settings.value(Core::settings::KEY_ANTA_MINIMODE, true).toBool()); 0870 0871 auto size= settings.beginReadArray(Core::settings::KEY_ANTA_ARRAY); 0872 auto& acts= m_antagonistWidget->columnsActions(); 0873 for(int i= 0; i < size; ++i) 0874 { 0875 settings.setArrayIndex(i); 0876 auto& act= acts[i]; 0877 act->setChecked(settings.value(Core::settings::KEY_ANTA_COL, true).toBool()); 0878 } 0879 0880 // read recent scenario 0881 auto ctrl= m_gameController->contentController(); 0882 SettingsHelper::readHistoryModel(ctrl->historyModel()); 0883 m_dockLogUtil->initSetting(); 0884 } 0885 void MainWindow::writeSettings() 0886 { 0887 QSettings settings(Core::settings::KEY_ROLISTEAM, 0888 QString(Core::settings::KEY_PREF_DIR).arg(m_gameController->version())); 0889 settings.setValue(Core::settings::KEY_GEOMETRY, saveGeometry()); 0890 settings.setValue(Core::settings::KEY_WINDOW_STATE, saveState()); 0891 settings.setValue(Core::settings::KEY_MAXIMIZED, isMaximized()); 0892 settings.setValue(Core::settings::KEY_MEDIA_TITLE, m_ui->m_mediaTitleAct->isChecked()); 0893 0894 settings.setValue(Core::settings::KEY_ANTA_MINIMODE, m_antagonistWidget->minimalMode()); 0895 settings.setValue(Core::settings::KEY_ANTA_FULLMODE, m_antagonistWidget->fullMode()); 0896 0897 settings.beginWriteArray(Core::settings::KEY_ANTA_ARRAY); 0898 auto& acts= m_antagonistWidget->columnsActions(); 0899 int i= 0; 0900 for(auto const& act : acts) 0901 { 0902 settings.setArrayIndex(i); 0903 i++; 0904 settings.setValue(Core::settings::KEY_ANTA_COL, act->isChecked()); 0905 } 0906 settings.endArray(); 0907 0908 auto ctrl= m_gameController->contentController(); 0909 if(!m_gameController->localIsGM()) 0910 SettingsHelper::writeHistoryModel(ctrl->historyModel()); 0911 for(auto& gmtool : m_gmToolBoxList) 0912 { 0913 gmtool->writeSettings(); 0914 } 0915 } 0916 void MainWindow::parseCommandLineArguments(const QStringList& list) 0917 { 0918 if(list.isEmpty()) 0919 return; 0920 QCommandLineParser parser; 0921 parser.addHelpOption(); 0922 parser.addVersionOption(); 0923 0924 QCommandLineOption port(QStringList() << "p" 0925 << "port", 0926 tr("Set rolisteam to use <port> for the connection"), "port"); 0927 QCommandLineOption hostname(QStringList() << "s" 0928 << "server", 0929 tr("Set rolisteam to connect to <server>."), "server"); 0930 QCommandLineOption role(QStringList() << "r" 0931 << "role", 0932 tr("Define the <role>: gm or pc"), "role"); 0933 QCommandLineOption reset(QStringList() << "reset-settings", 0934 tr("Erase the settings and use the default parameters")); 0935 QCommandLineOption user(QStringList() << "u" 0936 << "user", 0937 tr("Define the <username>"), "username"); 0938 QCommandLineOption websecurity(QStringList() << "w" 0939 << "disable-web-security", 0940 tr("Remove limit to PDF file size")); 0941 QCommandLineOption translation(QStringList() << "t" 0942 << "translation", 0943 QObject::tr("path to the translation file: <translationfile>"), "translationfile"); 0944 QCommandLineOption url(QStringList() << "l" 0945 << "link", 0946 QObject::tr("Define URL to connect to server: <url>"), "url"); 0947 0948 parser.addOption(port); 0949 parser.addOption(hostname); 0950 parser.addOption(role); 0951 parser.addOption(reset); 0952 parser.addOption(user); 0953 parser.addOption(translation); 0954 parser.addOption(websecurity); 0955 parser.addOption(url); 0956 0957 parser.process(list); 0958 0959 bool hasPort= parser.isSet(port); 0960 bool hasHostname= parser.isSet(hostname); 0961 bool hasRole= parser.isSet(role); 0962 bool hasUser= parser.isSet(user); 0963 bool hasUrl= parser.isSet(url); 0964 bool hasResetSetting= parser.isSet(reset); 0965 0966 QString portValue; 0967 QString hostnameValue; 0968 QString roleValue; 0969 QString username; 0970 QString urlString; 0971 QString passwordValue; 0972 if(hasPort) 0973 { 0974 portValue= parser.value(port); 0975 } 0976 if(hasHostname) 0977 { 0978 hostnameValue= parser.value(hostname); 0979 } 0980 if(hasRole) 0981 { 0982 roleValue= parser.value(role); 0983 } 0984 if(hasUser) 0985 { 0986 username= parser.value(user); 0987 } 0988 if(hasResetSetting) 0989 { 0990 QSettings settings("rolisteam", QString("rolisteam_%1/preferences").arg(m_gameController->version())); 0991 settings.clear(); 0992 } 0993 if(hasUrl) 0994 { 0995 urlString= parser.value(url); 0996 // auto list = urlString.split("/",QString::SkipEmptyParts); 0997 QRegularExpression ex("^rolisteam://(.*)/([0-9]+)/(.*)$"); 0998 QRegularExpressionMatch match= ex.match(urlString); 0999 // rolisteam://IP/port/password 1000 // if(list.size() == 4) 1001 if(match.hasMatch()) 1002 { 1003 hostnameValue= match.captured(1); 1004 portValue= match.captured(2); 1005 passwordValue= match.captured(3); 1006 QByteArray pass= QByteArray::fromBase64(passwordValue.toUtf8()); 1007 m_commandLineProfile.reset(new CommandLineProfile({hostnameValue, portValue.toInt(), pass})); 1008 } 1009 } 1010 } 1011 1012 void MainWindow::cleanUpData() 1013 { 1014 m_gameController->clear(); 1015 1016 ChannelListPanel* roomPanel= qobject_cast<ChannelListPanel*>(m_roomPanelDockWidget->widget()); 1017 if(nullptr != roomPanel) 1018 { 1019 roomPanel->cleanUp(); 1020 } 1021 } 1022 1023 void MainWindow::postConnection() 1024 { 1025 m_ui->m_changeProfileAct->setEnabled(false); 1026 m_ui->m_disconnectAction->setEnabled(true); 1027 1028 setUpNetworkConnection(); 1029 updateWindowTitle(); 1030 updateUi(); 1031 } 1032 1033 void MainWindow::openGenericContent() 1034 { 1035 QAction* action= static_cast<QAction*>(sender()); 1036 Core::ContentType type= static_cast<Core::ContentType>(action->data().toInt()); 1037 1038 QString folder= m_preferences->value(Core::preferences::KEY_OPEN_DIRECTORY, QDir::homePath()).toString(); 1039 QString title= tr("Open %1").arg(helper::utils::typeToString(type)); 1040 QStringList filepath= QFileDialog::getOpenFileNames(this, title, folder, helper::utils::filterForType(type, false)); 1041 QStringList list= filepath; 1042 1043 for(auto const& path : list) 1044 { 1045 m_gameController->openMedia( 1046 {{Core::keys::KEY_URL, QUrl::fromUserInput(path)}, 1047 {Core::keys::KEY_TYPE, QVariant::fromValue(type)}, 1048 {Core::keys::KEY_NAME, utils::IOHelper::shortNameFromPath(path)}, 1049 {Core::keys::KEY_OWNERID, m_gameController->playerController()->localPlayer()->uuid()}}); 1050 } 1051 } 1052 1053 void MainWindow::openImage() 1054 { 1055 ImageSelectorController ctrl(false, ImageSelectorController::All); 1056 ImageSelectorDialog dialog(&ctrl, this); 1057 if(QDialog::Accepted != dialog.exec()) 1058 return; 1059 1060 std::map<QString, QVariant> args( 1061 {{Core::keys::KEY_NAME, ctrl.title()}, 1062 {Core::keys::KEY_URL, ctrl.address()}, 1063 {Core::keys::KEY_OWNERID, m_gameController->playerController()->localPlayer()->uuid()}, 1064 {Core::keys::KEY_TYPE, QVariant::fromValue(Core::ContentType::PICTURE)}, 1065 {Core::keys::KEY_DATA, ctrl.finalImageData()}}); 1066 1067 m_gameController->openMedia(args); 1068 } 1069 1070 void MainWindow::updateFileHistoryMenu() 1071 { 1072 auto const& ctrl= m_gameController->contentController(); 1073 auto const& model= ctrl->historyModel(); 1074 auto const& data= model->data(); 1075 1076 m_ui->m_historyMenu->clear(); 1077 m_ui->m_historyMenu->addAction(m_ui->m_manageHistoryAct); 1078 m_ui->m_historyMenu->addAction(m_ui->m_cleanHistoryAct); 1079 m_ui->m_historyMenu->addSeparator(); 1080 std::for_each(std::begin(data), std::end(data), 1081 [this](const history::LinkInfo& info) 1082 { 1083 auto action= new QAction(info.displayName, this); 1084 action->setData(info.id); 1085 action->setIcon(QIcon(helper::utils::typeToIconPath(info.type))); 1086 m_ui->m_historyMenu->addAction(action); 1087 connect(action, &QAction::triggered, this, &MainWindow::openFileFromHistory); 1088 }); 1089 1090 SettingsHelper::writeHistoryModel(ctrl->historyModel()); 1091 } 1092 1093 void MainWindow::openFileFromHistory() 1094 { 1095 auto act= qobject_cast<QAction*>(sender()); 1096 auto id= act->data().toString(); 1097 auto const& ctrl= m_gameController->contentController(); 1098 auto const& model= ctrl->historyModel(); 1099 auto info= model->idToPath(id); 1100 if(!info.url.isEmpty()) 1101 { 1102 std::map<QString, QVariant> map{{Core::keys::KEY_URL, info.url}, 1103 {Core::keys::KEY_NAME, info.displayName}, 1104 {Core::keys::KEY_TYPE, QVariant::fromValue(info.type)}}; 1105 if(info.type == Core::ContentType::PICTURE) 1106 { 1107 ImageSelectorController* ctrl= new ImageSelectorController(false, ImageSelectorController::All); 1108 connect(ctrl, &ImageSelectorController::imageDataChanged, this, 1109 [this, ctrl, map]() 1110 { 1111 std::map<QString, QVariant> map2(map); 1112 auto data= ctrl->finalImageData(); 1113 map2.insert({Core::keys::KEY_DATA, data}); 1114 m_gameController->openMedia(map2); 1115 ctrl->deleteLater(); 1116 }); 1117 ctrl->downloadImageFrom(info.url); 1118 } 1119 else 1120 { 1121 m_gameController->openMedia(map); 1122 } 1123 } 1124 } 1125 1126 void MainWindow::updateWindowTitle() 1127 { 1128 auto networkCtrl= m_gameController->networkController(); 1129 1130 auto const connectionStatus= m_gameController->connected() ? tr("Connected") : tr("Not Connected"); 1131 auto const networkStatus= networkCtrl->hosting() ? tr("Server") : tr("Client"); 1132 1133 if(networkCtrl->isGM()) 1134 { 1135 auto camp= m_gameController->campaign(); 1136 setWindowTitle(QStringLiteral("%6[*] - v%2 - %3 - %4 - %5 - %1") 1137 .arg(m_preferences->value("applicationName", "Rolisteam").toString(), 1138 m_gameController->version(), connectionStatus, networkStatus, tr("GM"), camp->name())); 1139 } 1140 else 1141 { 1142 setWindowTitle(QStringLiteral("%1 - v%2[*] - %3 - %4 - %5") 1143 .arg(m_preferences->value("applicationName", "Rolisteam").toString(), 1144 m_gameController->version(), connectionStatus, networkStatus, tr("Player"))); 1145 } 1146 1147 setWindowIcon(QIcon::fromTheme("500-symbole")); 1148 } 1149 1150 void MainWindow::dragEnterEvent(QDragEnterEvent* event) 1151 { 1152 if(event->mimeData()->hasUrls() || event->mimeData()->hasImage()) 1153 { 1154 event->acceptProposedAction(); 1155 } 1156 QMainWindow::dragEnterEvent(event); 1157 } 1158 1159 void MainWindow::dropEvent(QDropEvent* event) 1160 { 1161 const QMimeData* data= event->mimeData(); 1162 if(!data->hasUrls() && !data->hasImage()) 1163 return; 1164 1165 qDebug() << "data has url and image" << data->hasImage() << data->hasUrls(); 1166 1167 if(data->hasImage()) 1168 { 1169 auto contentCtrl= m_gameController->contentController(); 1170 auto img= qvariant_cast<QImage>(data->imageData()); 1171 qDebug() << img.isNull() << img; 1172 1173 auto name= tr("Unknown"); 1174 if(data->hasText()) 1175 { 1176 name= data->text(); 1177 } 1178 1179 contentCtrl->openMedia( 1180 {{Core::keys::KEY_TYPE, QVariant::fromValue(Core::ContentType::PICTURE)}, 1181 {Core::keys::KEY_DATA, IOHelper::imageToData(img)}, 1182 {Core::keys::KEY_NAME, name}, 1183 {Core::keys::KEY_OWNERID, m_gameController->playerController()->localPlayer()->uuid()}}); 1184 } 1185 else if(data->hasUrls()) 1186 { 1187 QList<QUrl> list= data->urls(); 1188 auto contentCtrl= m_gameController->contentController(); 1189 for(const auto& url : list) 1190 { 1191 auto path= url.toLocalFile(); 1192 if(!path.isEmpty()) // local file 1193 { 1194 1195 Core::ContentType type= helper::utils::extensionToContentType(path); 1196 if(type == Core::ContentType::UNKNOWN) 1197 continue; 1198 qCInfo(WidgetClient) 1199 << QStringLiteral("MainWindow: dropEvent for %1").arg(helper::utils::typeToString(type)); 1200 contentCtrl->openMedia( 1201 {{Core::keys::KEY_URL, url}, 1202 {Core::keys::KEY_TYPE, QVariant::fromValue(type)}, 1203 {Core::keys::KEY_NAME, utils::IOHelper::shortNameFromPath(path)}, 1204 {Core::keys::KEY_OWNERID, m_gameController->playerController()->localPlayer()->uuid()}}); 1205 } 1206 else // remote 1207 { 1208 auto urltext= url.toString(QUrl::None); 1209 Core::ContentType type= helper::utils::extensionToContentType(urltext); 1210 if(type != Core::ContentType::PICTURE) 1211 continue; 1212 1213 #ifdef HAVE_QT_NETWORK 1214 auto downloader= new NetworkDownloader(url); 1215 connect( 1216 downloader, &NetworkDownloader::finished, this, 1217 [this, contentCtrl, type, url, urltext, downloader](const QByteArray& data) 1218 { 1219 contentCtrl->openMedia( 1220 {{Core::keys::KEY_URL, urltext}, 1221 {Core::keys::KEY_PATH, urltext}, 1222 {Core::keys::KEY_TYPE, QVariant::fromValue(type)}, 1223 {Core::keys::KEY_DATA, data}, 1224 {Core::keys::KEY_NAME, utils::IOHelper::shortNameFromPath(url.fileName())}, 1225 {Core::keys::KEY_OWNERID, m_gameController->playerController()->localPlayer()->uuid()}}); 1226 downloader->deleteLater(); 1227 }); 1228 downloader->download(); 1229 #endif 1230 } 1231 } 1232 } 1233 event->acceptProposedAction(); 1234 } 1235 1236 void MainWindow::showShortCutEditor() 1237 { 1238 ShortcutVisitor visitor; 1239 visitor.registerWidget(this, "mainwindow", true); 1240 1241 ShortCutEditorDialog dialog; 1242 dialog.setModel(visitor.getModel()); 1243 dialog.exec(); 1244 } 1245 1246 void MainWindow::openImageAs(const QPixmap& pix, Core::ContentType type) 1247 { 1248 auto viewer= qobject_cast<MediaContainer*>(sender()); 1249 QString title(tr("Export from %1")); 1250 QString sourceName= tr("unknown"); 1251 if(nullptr != viewer) 1252 { 1253 // sourceName= viewer->getUriName(); 1254 } 1255 1256 // MediaContainer* destination= nullptr; 1257 if(type == Core::ContentType::VECTORIALMAP) 1258 { 1259 /* auto media= newDocument(type, false); 1260 auto vmapFrame= dynamic_cast<VMapFrame*>(media);*/ 1261 // if(vmapFrame) 1262 { 1263 /*auto vmap= vmapFrame->getMap(); 1264 vmap->addImageItem(pix.toImage()); 1265 destination= media;*/ 1266 } 1267 } 1268 else if(type == Core::ContentType::PICTURE) 1269 { 1270 /* auto img= new Image(m_mdiArea); 1271 auto imgPix= pix.toImage(); 1272 img->setImage(imgPix); 1273 destination= img;*/ 1274 } 1275 // if(destination) 1276 // destination->setUriName(title.arg(sourceName)); 1277 1278 // destination->setRemote(false); 1279 // destination->setCleverUri(new CleverURI(sourceName, "", type)); 1280 // addMediaToMdiArea(destination, true); 1281 } 1282 void MainWindow::focusInEvent(QFocusEvent* event) 1283 { 1284 QMainWindow::focusInEvent(event); 1285 if(m_isOut) 1286 { 1287 m_gameController->addSearchLog(QStringLiteral("Rolisteam gets focus."), logns::cat::usability); 1288 m_isOut= false; 1289 } 1290 } 1291 void MainWindow::focusOutEvent(QFocusEvent* event) 1292 { 1293 QMainWindow::focusOutEvent(event); 1294 if(!isActiveWindow()) 1295 { 1296 m_gameController->addSearchLog(QStringLiteral("User gives focus to another windows."), logns::cat::usability); 1297 m_isOut= true; 1298 } 1299 }