1 /*
2 Copyright 2006-2019 The QElectroTech Team
3 This file is part of QElectroTech.
4
5 QElectroTech is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "qetapp.h"
19 #include "aboutqet.h"
20 #include "configdialog.h"
21 #include "configpages.h"
22 #include "qetdiagrameditor.h"
23 #include "qetelementeditor.h"
24 #include "elementscollectioncache.h"
25 #include "titleblocktemplate.h"
26 #include "qettemplateeditor.h"
27 #include "qetproject.h"
28 #include "qtextorientationspinboxwidget.h"
29 #include "recentfiles.h"
30 #include "qeticons.h"
31 #include "templatescollection.h"
32 #include "generalconfigurationpage.h"
33 #include "qetmessagebox.h"
34 #include "projectview.h"
35 #include "elementpicturefactory.h"
36
37 #include <cstdlib>
38 #include <iostream>
39 #define QUOTE(x) STRINGIFY(x)
40 #define STRINGIFY(x) #x
41 #include <QProcessEnvironment>
42 #include "factory/elementfactory.h"
43
44 #include <KAutoSaveFile>
45
46 #ifdef QET_ALLOW_OVERRIDE_CED_OPTION
47 QString QETApp::common_elements_dir = QString();
48 #endif
49 #ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION
50 QString QETApp::common_tbt_dir_ = QString();
51 #endif
52 #ifdef QET_ALLOW_OVERRIDE_CD_OPTION
53 QString QETApp::config_dir = QString();
54 #endif
55 QString QETApp::lang_dir = QString();
56 TitleBlockTemplatesFilesCollection *QETApp::m_common_tbt_collection;
57 TitleBlockTemplatesFilesCollection *QETApp::m_custom_tbt_collection;
58 ElementsCollectionCache *QETApp::collections_cache_ = nullptr;
59 QMap<uint, QETProject *> QETApp::registered_projects_ = QMap<uint, QETProject *>();
60 uint QETApp::next_project_id = 0;
61 RecentFiles *QETApp::m_projects_recent_files = nullptr;
62 RecentFiles *QETApp::m_elements_recent_files = nullptr;
63 TitleBlockTemplate *QETApp::default_titleblock_template_ = nullptr;
64 QString QETApp::m_user_common_elements_dir = QString();
65 QString QETApp::m_user_custom_elements_dir = QString();
66 QString QETApp::m_user_custom_tbt_dir = QString();
67 QETApp *QETApp::m_qetapp = nullptr;
68
69
70 /**
71 * @brief QETApp::QETApp
72 */
QETApp()73 QETApp::QETApp() :
74 m_splash_screen(nullptr),
75 non_interactive_execution_(false)
76 {
77 m_qetapp = this;
78 parseArguments();
79 if (non_interactive_execution_) {
80 std::exit(EXIT_SUCCESS);
81 }
82 initConfiguration();
83 initLanguage();
84 QET::Icons::initIcons();
85 initStyle();
86 initSplashScreen();
87 initSystemTray();
88
89 connect(&signal_map, SIGNAL(mapped(QWidget *)), this, SLOT(invertMainWindowVisibility(QWidget *)));
90 qApp->setQuitOnLastWindowClosed(false);
91 connect(qApp, &QApplication::lastWindowClosed, this, &QETApp::checkRemainingWindows);
92
93 setSplashScreenStep(tr("Chargement... Initialisation du cache des collections d'éléments", "splash screen caption"));
94 if (!collections_cache_) {
95 QString cache_path = QETApp::configDir() + "/elements_cache.sqlite";
96 collections_cache_ = new ElementsCollectionCache(cache_path, this);
97 collections_cache_->setLocale(langFromSetting());
98 }
99
100 if (qet_arguments_.files().isEmpty())
101 {
102 setSplashScreenStep(tr("Chargement... Éditeur de schéma", "splash screen caption"));
103 new QETDiagramEditor();
104 } else
105 {
106 setSplashScreenStep(tr("Chargement... Ouverture des fichiers", "splash screen caption"));
107 openFiles(qet_arguments_);
108 }
109
110 buildSystemTrayMenu();
111 if (m_splash_screen) {
112 m_splash_screen -> hide();
113 }
114
115 checkBackupFiles();
116 }
117
118 /**
119 * @brief QETApp::~QETApp
120 */
~QETApp()121 QETApp::~QETApp()
122 {
123 m_elements_recent_files->save();
124 m_projects_recent_files->save();
125
126 delete m_splash_screen;
127 delete m_elements_recent_files;
128 delete m_projects_recent_files;
129 delete m_qsti;
130
131 if (m_custom_tbt_collection)
132 delete m_custom_tbt_collection;
133 if (m_common_tbt_collection)
134 delete m_common_tbt_collection;
135
136 ElementFactory::dropInstance();
137 ElementPictureFactory::dropInstance();
138 }
139
140 /**
141 @return l'instance de la QETApp
142 */
instance()143 QETApp *QETApp::instance()
144 {
145 return m_qetapp;
146 }
147
148 /**
149 Change le langage utilise par l'application.
150 @param desired_language langage voulu
151 */
setLanguage(const QString & desired_language)152 void QETApp::setLanguage(const QString &desired_language) {
153 QString languages_path = languagesPath();
154
155 // load Qt library translations
156 QString qt_l10n_path = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
157 if (!qtTranslator.load("qt_" + desired_language, qt_l10n_path)) {
158 qtTranslator.load("qt_" + desired_language, languages_path);
159 }
160 qApp->installTranslator(&qtTranslator);
161
162 // charge les traductions pour l'application QET
163 if (!qetTranslator.load("qet_" + desired_language, languages_path)) {
164 // en cas d'echec, on retombe sur les chaines natives pour le francais
165 if (desired_language != "fr") {
166 // utilisation de la version anglaise par defaut
167 qetTranslator.load("qet_en", languages_path);
168 }
169 }
170 qApp->installTranslator(&qetTranslator);
171
172 QString ltr_special_string = tr(
173 "LTR",
174 "Translate this string to RTL if you are translating to a Right-to-Left language, else translate to LTR"
175 );
176 if (ltr_special_string == "RTL") switchLayout(Qt::RightToLeft);
177 }
178
179 /**
180 * @brief QETApp::langFromSetting
181 * @return the langage found in setting file
182 * if nothing was found return the system local.
183 */
langFromSetting()184 QString QETApp::langFromSetting()
185 {
186 QSettings settings;
187 QString system_language = settings.value("lang", "system").toString();
188 if(system_language == "system") {system_language = QLocale::system().name().left(2);}
189 return system_language;
190 }
191 /**
192 Switches the application to the provided layout.
193 */
switchLayout(Qt::LayoutDirection direction)194 void QETApp::switchLayout(Qt::LayoutDirection direction) {
195 qApp->setLayoutDirection(direction);
196 }
197
198 /**
199 Gere les evenements relatifs au QSystemTrayIcon
200 @param reason un entier representant l'evenement survenu sur le systray
201 */
systray(QSystemTrayIcon::ActivationReason reason)202 void QETApp::systray(QSystemTrayIcon::ActivationReason reason) {
203 if (!QSystemTrayIcon::isSystemTrayAvailable()) return;
204 switch(reason) {
205 case QSystemTrayIcon::Context:
206 // affichage du menu
207 buildSystemTrayMenu();
208 m_qsti -> contextMenu() -> show();
209 break;
210 case QSystemTrayIcon::DoubleClick:
211 case QSystemTrayIcon::Trigger:
212 // reduction ou restauration de l'application
213 fetchWindowStats(diagramEditors(), elementEditors(), titleBlockTemplateEditors());
214 if (every_editor_reduced) restoreEveryEditor(); else reduceEveryEditor();
215 break;
216 case QSystemTrayIcon::Unknown:
217 default: // ne rien faire
218 break;
219 }
220 }
221
222 /// Reduit toutes les fenetres de l'application dans le systray
reduceEveryEditor()223 void QETApp::reduceEveryEditor() {
224 reduceDiagramEditors();
225 reduceElementEditors();
226 reduceTitleBlockTemplateEditors();
227 every_editor_reduced = true;
228 }
229
230 /// Restaure toutes les fenetres de l'application dans le systray
restoreEveryEditor()231 void QETApp::restoreEveryEditor() {
232 restoreDiagramEditors();
233 restoreElementEditors();
234 restoreTitleBlockTemplateEditors();
235 every_editor_reduced = false;
236 }
237
238 /// Reduit tous les editeurs de schemas dans le systray
reduceDiagramEditors()239 void QETApp::reduceDiagramEditors() {
240 setMainWindowsVisible<QETDiagramEditor>(false);
241 }
242
243 /// Restaure tous les editeurs de schemas dans le systray
restoreDiagramEditors()244 void QETApp::restoreDiagramEditors() {
245 setMainWindowsVisible<QETDiagramEditor>(true);
246 }
247
248 /// Reduit tous les editeurs d'element dans le systray
reduceElementEditors()249 void QETApp::reduceElementEditors() {
250 setMainWindowsVisible<QETElementEditor>(false);
251 }
252
253 /// Restaure tous les editeurs d'element dans le systray
restoreElementEditors()254 void QETApp::restoreElementEditors() {
255 setMainWindowsVisible<QETElementEditor>(true);
256 }
257
258 /// Reduce all known template editors
reduceTitleBlockTemplateEditors()259 void QETApp::reduceTitleBlockTemplateEditors() {
260 setMainWindowsVisible<QETTitleBlockTemplateEditor>(false);
261 }
262
263 /// Restore all known template editors
restoreTitleBlockTemplateEditors()264 void QETApp::restoreTitleBlockTemplateEditors() {
265 setMainWindowsVisible<QETTitleBlockTemplateEditor>(true);
266 }
267
268 /// lance un nouvel editeur de schemas
newDiagramEditor()269 void QETApp::newDiagramEditor() {
270 new QETDiagramEditor();
271 }
272
273 /// lance un nouvel editeur d'element
newElementEditor()274 void QETApp::newElementEditor() {
275 new QETElementEditor();
276 }
277
278 /**
279 @return the collection cache provided by the application itself.
280 */
collectionCache()281 ElementsCollectionCache *QETApp::collectionCache() {
282 return(collections_cache_);
283 }
284
285 /**
286 * @brief QETApp::elementInfoKeys
287 * @return all available key for describe an element
288 */
elementInfoKeys()289 QStringList QETApp::elementInfoKeys()
290 {
291 QStringList info_list;
292 info_list << "formula"
293 << "label"
294 << "plant"
295 << "location"
296
297 << "comment"
298 << "function"
299 << "tension-protocol"
300 << "auxiliary1"
301 << "auxiliary2"
302
303 << "description"
304 << "designation"
305 << "manufacturer"
306 << "manufacturer-reference"
307 << "machine-manufacturer-reference"
308 << "supplier"
309 << "quantity"
310 << "unity";
311 return info_list;
312 }
313
314 /**
315 * @brief ElementsProperties::translatedInfo
316 * Return the translated information key given by @info
317 * If @info don't match, return an empty string
318 * @param info the key to be translated
319 * @return
320 */
elementTranslatedInfoKey(const QString & info)321 QString QETApp::elementTranslatedInfoKey(const QString &info)
322 {
323 if (info == "formula") return tr("Formule du label");
324 else if (info == "label") return tr("Label");
325 else if (info == "plant") return tr("Installation");
326 else if (info == "location") return tr("Localisation");
327
328 else if (info == "comment") return tr("Commentaire");
329 else if (info == "function") return tr("Fonction");
330 else if (info == "tension-protocol") return tr("Tension / Protocole");
331 else if (info == "auxiliary1") return tr("Bloc auxiliaire 1");
332 else if (info == "auxiliary2") return tr("Bloc auxiliaire 2");
333
334 else if (info == "description") return tr("Description textuelle");
335 else if (info == "designation") return tr("Numéro d'article");
336 else if (info == "manufacturer") return tr("Fabricant");
337 else if (info == "manufacturer-reference") return tr("Numéro de commande");
338 else if (info == "machine-manufacturer-reference") return tr("Numéro interne");
339 else if (info == "supplier") return tr("Fournisseur");
340 else if (info == "quantity") return tr("Quantité");
341 else if (info == "unity") return tr("Unité");
342
343
344
345
346 return (info);
347 }
348
349 /**
350 * @brief QETApp::elementInfoToVar
351 * @param info
352 * @return var in form %{my-var} corresponding to the info, if there is not available var for the given info
353 * the returned var is %{void}
354 */
elementInfoToVar(const QString & info)355 QString QETApp::elementInfoToVar(const QString &info)
356 {
357 if (info == "formula") return QString("%{formula}");
358 else if (info == "label") return QString("%{label}");
359 else if (info == "plant") return QString("%{plant}");
360 else if (info == "comment") return QString("%{comment}");
361 else if (info == "description") return QString("%{description}");
362 else if (info == "designation") return QString("%{designation}");
363 else if (info == "manufacturer") return QString("%{manufacturer}");
364 else if (info == "manufacturer-reference") return QString("%{manufacturer-reference}");
365 else if (info == "supplier") return QString("%{supplier}");
366 else if (info == "quantity") return QString("%{quantity}");
367 else if (info == "unity") return QString("%{unity}");
368 else if (info == "auxiliary1") return QString("%{auxiliary1}");
369 else if (info == "auxiliary2") return QString("%{auxiliary2}");
370 else if (info == "machine-manufacturer-reference") return QString("%{machine-manufacturer-reference}");
371 else if (info == "location") return QString("%{location}");
372 else if (info == "function") return QString("%{function}");
373 else if (info == "tension-protocol") return QString("%{tension-protocol}");
374
375 return (QString ("%{void}"));
376 }
377
378 /**
379 * @brief QETApp::conductorInfoKeys
380 * @return the conductor information keys
381 */
conductorInfoKeys()382 QStringList QETApp::conductorInfoKeys()
383 {
384 QStringList keys;
385 keys.append("formula");
386 keys.append("text");
387 keys.append("function");
388 keys.append("tension/protocol");
389
390 return keys;
391 }
392
393 /**
394 * @brief QETApp::conductorTranslatedInfoKey
395 * @param key
396 * @return the translated information key given by @key
397 * If @key don't match, return an empty string
398 */
conductorTranslatedInfoKey(const QString & key)399 QString QETApp::conductorTranslatedInfoKey(const QString &key)
400 {
401 if (key == "formula") return tr("Formule du texte");
402 else if (key == "text") return tr("Texte");
403 else if (key == "function") return tr("Fonction");
404 else if (key == "tension/protocol") return tr("Tension / Protocole");
405 return QString();
406 }
407
408 /**
409 * @brief QETApp::diagramInfoKeys
410 * @return the diagram default information keys
411 */
diagramInfoKeys()412 QStringList QETApp::diagramInfoKeys()
413 {
414 QStringList list;
415 list.append("title");
416 list.append("author");
417 list.append("filename");
418 list.append("folio");
419 list.append("plant");
420 list.append("locmach");
421 list.append("indexrev");
422
423 return list;
424 }
425
426 /**
427 * @brief QETApp::diagramTranslatedInfoKey
428 * @param key
429 * @return the translated information key given by @key
430 * If @key don't match, return an empty string
431 */
diagramTranslatedInfoKey(const QString & key)432 QString QETApp::diagramTranslatedInfoKey(const QString &key)
433 {
434 if (key == "title") return tr("Titre");
435 else if (key == "author") return tr("Auteur");
436 else if (key == "filename") return tr("Fichier");
437 else if (key == "folio") return tr("Folio");
438 else if (key == "plant") return tr("Installation");
439 else if (key == "locmach") return tr("Localisation");
440 else if (key == "indexrev") return tr("Indice Rev");
441 else return QString();
442 }
443
444 /**
445 @return the common title block templates collection, i.e. the one provided
446 by QElecrotTech
447 */
commonTitleBlockTemplatesCollection()448 TitleBlockTemplatesFilesCollection *QETApp::commonTitleBlockTemplatesCollection() {
449 if (!m_common_tbt_collection) {
450 m_common_tbt_collection = new TitleBlockTemplatesFilesCollection(QETApp::commonTitleBlockTemplatesDir());
451 m_common_tbt_collection -> setTitle(tr("Cartouches QET", "title of the title block templates collection provided by QElectroTech"));
452 m_common_tbt_collection -> setProtocol(QETAPP_COMMON_TBT_PROTOCOL);
453 m_common_tbt_collection -> setCollection(QET::QetCollection::Common);
454 }
455 return(m_common_tbt_collection);
456 }
457
458 /**
459 @return the custom title block templates collection, i.e. the one managed
460 by the end user
461 */
customTitleBlockTemplatesCollection()462 TitleBlockTemplatesFilesCollection *QETApp::customTitleBlockTemplatesCollection() {
463 if (!m_custom_tbt_collection) {
464 m_custom_tbt_collection = new TitleBlockTemplatesFilesCollection(QETApp::customTitleBlockTemplatesDir());
465 m_custom_tbt_collection -> setTitle(tr("Cartouches utilisateur", "title of the user's title block templates collection"));
466 m_custom_tbt_collection -> setProtocol(QETAPP_CUSTOM_TBT_PROTOCOL);
467 m_custom_tbt_collection -> setCollection(QET::QetCollection::Custom);
468 }
469 return(m_custom_tbt_collection);
470 }
471
472 /**
473 @return the list of all available title block tempaltes collections,
474 beginning with the common and custom ones, plus the projects-embedded ones.
475 */
availableTitleBlockTemplatesCollections()476 QList<TitleBlockTemplatesCollection *> QETApp::availableTitleBlockTemplatesCollections() {
477 QList<TitleBlockTemplatesCollection *> collections_list;
478
479 collections_list << commonTitleBlockTemplatesCollection();
480 collections_list << customTitleBlockTemplatesCollection();
481
482 foreach(QETProject *opened_project, registered_projects_) {
483 collections_list << opened_project -> embeddedTitleBlockTemplatesCollection();
484 }
485
486 return(collections_list);
487 }
488
489 /**
490 @param protocol Protocol string
491 @return the templates collection matching the provided protocol, or 0 if none could be found
492 */
titleBlockTemplatesCollection(const QString & protocol)493 TitleBlockTemplatesCollection *QETApp::titleBlockTemplatesCollection(const QString &protocol) {
494 if (protocol == QETAPP_COMMON_TBT_PROTOCOL) {
495 return(m_common_tbt_collection);
496 } else if (protocol == QETAPP_CUSTOM_TBT_PROTOCOL) {
497 return(m_custom_tbt_collection);
498 } else {
499 QETProject *project = QETApp::projectFromString(protocol);
500 if (project) {
501 return(project -> embeddedTitleBlockTemplatesCollection());
502 }
503 }
504 return(nullptr);
505 }
506
507 /**
508 * @brief QETApp::commonElementsDir
509 * @return the dir path of the common elements collection.
510 */
commonElementsDir()511 QString QETApp::commonElementsDir()
512 {
513 if (m_user_common_elements_dir.isEmpty())
514 {
515 QSettings settings;
516 QString path = settings.value("elements-collections/common-collection-path", "default").toString();
517 if (path != "default" && !path.isEmpty())
518 {
519 QDir dir(path);
520 if (dir.exists())
521 {
522 m_user_common_elements_dir = path;
523 return m_user_common_elements_dir;
524 }
525 }
526 else {
527 m_user_common_elements_dir = "default";
528 }
529 }
530 else if (m_user_common_elements_dir != "default") {
531 return m_user_common_elements_dir;
532 }
533
534 #ifdef QET_ALLOW_OVERRIDE_CED_OPTION
535 if (common_elements_dir != QString()) return(common_elements_dir);
536 #endif
537 #ifndef QET_COMMON_COLLECTION_PATH
538 // en l'absence d'option de compilation, on utilise le dossier elements, situe a cote du binaire executable
539 return(QCoreApplication::applicationDirPath() + "/elements/");
540 #else
541 #ifndef QET_COMMON_COLLECTION_PATH_RELATIVE_TO_BINARY_PATH
542 // l'option de compilation represente un chemin absolu ou relatif classique
543 return(QUOTE(QET_COMMON_COLLECTION_PATH));
544 #else
545 // l'option de compilation represente un chemin relatif au dossier contenant le binaire executable
546 return(QCoreApplication::applicationDirPath() + "/" + QUOTE(QET_COMMON_COLLECTION_PATH));
547 #endif
548 #endif
549 }
550
551 /**
552 * @brief QETApp::customElementsDir
553 * @return the dir path of user elements collection
554 */
customElementsDir()555 QString QETApp::customElementsDir()
556 {
557 if (m_user_custom_elements_dir.isEmpty())
558 {
559 QSettings settings;
560 QString path = settings.value("elements-collections/custom-collection-path", "default").toString();
561 if (path != "default" && !path.isEmpty())
562 {
563 QDir dir(path);
564 if (dir.exists())
565 {
566 m_user_custom_elements_dir = path;
567 return m_user_custom_elements_dir;
568 }
569 }
570 else {
571 m_user_custom_elements_dir = "default";
572 }
573 }
574 else if (m_user_custom_elements_dir != "default") {
575 return m_user_custom_elements_dir;
576 }
577
578 return(configDir() + "elements/");
579 }
580
581 /**
582 * @brief QETApp::commonElementsDirN
583 * like QString QETApp::commonElementsDir but without "/" at the end
584 * @return
585 */
commonElementsDirN()586 QString QETApp::commonElementsDirN()
587 {
588 QString path = commonElementsDir();
589 if (path.endsWith("/")) path.remove(path.length()-1, 1);
590 return path;
591 }
592
593 /**
594 * @brief QETApp::customElementsDirN
595 * like QString QETApp::customElementsDir but without "/" at the end
596 * @return
597 */
customElementsDirN()598 QString QETApp::customElementsDirN()
599 {
600 QString path = customElementsDir();
601 if (path.endsWith("/")) path.remove(path.length()-1, 1);
602 return path;
603 }
604
605 /**
606 * @brief QETApp::resetUserElementsDir
607 * Reset the path of the user common and custom elements dir.
608 * Use this function when the user path (common and/or custom) change.
609 */
resetUserElementsDir()610 void QETApp::resetUserElementsDir()
611 {
612 m_user_common_elements_dir.clear();
613 m_user_custom_elements_dir.clear();
614 m_user_custom_tbt_dir.clear();
615 }
616
617 /**
618 @return the path of the directory containing the common title block
619 templates collection.
620 */
commonTitleBlockTemplatesDir()621 QString QETApp::commonTitleBlockTemplatesDir() {
622 #ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION
623 if (common_tbt_dir_ != QString()) return(common_tbt_dir_);
624 #endif
625 #ifndef QET_COMMON_TBT_PATH
626 // without any compile-time option, use the "titleblocks" directory next to the executable binary
627 return(QCoreApplication::applicationDirPath() + "/titleblocks/");
628 #else
629 #ifndef QET_COMMON_COLLECTION_PATH_RELATIVE_TO_BINARY_PATH
630 // the compile-time option represents a usual path (be it absolute or relative)
631 return(QUOTE(QET_COMMON_TBT_PATH));
632 #else
633 // the compile-time option represents a path relative to the directory that contains the executable binary
634 return(QCoreApplication::applicationDirPath() + "/" + QUOTE(QET_COMMON_TBT_PATH));
635 #endif
636 #endif
637 }
638
639 /**
640 @return the path of the directory containing the custom title block
641 templates collection.
642 */
customTitleBlockTemplatesDir()643 QString QETApp::customTitleBlockTemplatesDir() {
644 if (m_user_custom_tbt_dir.isEmpty())
645 {
646 QSettings settings;
647 QString path = settings.value("elements-collections/custom-tbt-path", "default").toString();
648 if (path != "default" && !path.isEmpty())
649 {
650 QDir dir(path);
651 if (dir.exists())
652 {
653 m_user_custom_tbt_dir = path;
654 return m_user_custom_tbt_dir;
655 }
656 }
657 else {
658 m_user_custom_tbt_dir = "default";
659 }
660 }
661 else if (m_user_custom_tbt_dir != "default") {
662 return m_user_custom_tbt_dir;
663 }
664
665 return(configDir() + "titleblocks/");
666 }
667
668 /**
669 Renvoie le dossier de configuration de QET, c-a-d le chemin du dossier dans
670 lequel QET lira les informations de configuration et de personnalisation
671 propres a l'utilisateur courant. Ce dossier est generalement
672 C:\\Documents And Settings\\utilisateur\\Application Data\\qet sous Windows et
673 ~/.qet sous les systemes type UNIX.
674 @return Le chemin du dossier de configuration de QElectroTech
675 */
configDir()676 QString QETApp::configDir() {
677 #ifdef QET_ALLOW_OVERRIDE_CD_OPTION
678 if (config_dir != QString()) return(config_dir);
679 #endif
680 #ifdef Q_OS_WIN32
681 // recupere l'emplacement du dossier Application Data
682 // char *app_data_env = getenv("APPDATA");
683 // QString app_data_str(app_data_env);
684 QProcess * process = new QProcess();
685 QString app_data_str = (process->processEnvironment()).value("APPDATA");
686 // delete app_data_env;
687 delete process;
688 if (app_data_str.isEmpty()) {
689 app_data_str = QDir::homePath() + "/Application Data";
690 }
691 return(app_data_str + "/qet/");
692 #else
693 return(QDir::homePath() + "/.qet/");
694 #endif
695 }
696
697 /**
698 Permet de connaitre le chemin absolu du fichier *.elmt correspondant a un
699 chemin symbolique (du type custom://outils_pervers/sado_maso/contact_bizarre)
700 @param sym_path Chaine de caracteres representant le chemin absolu du fichier
701 @return Une chaine de caracteres vide en cas d'erreur ou le chemin absolu du
702 fichier *.elmt.
703 */
realPath(const QString & sym_path)704 QString QETApp::realPath(const QString &sym_path) {
705 QString directory;
706 if (sym_path.startsWith("common://")) {
707 directory = commonElementsDir();
708 } else if (sym_path.startsWith("custom://")) {
709 directory = customElementsDir();
710 } else if (sym_path.startsWith(QETAPP_COMMON_TBT_PROTOCOL "://")) {
711 directory = commonTitleBlockTemplatesDir();
712 } else if (sym_path.startsWith(QETAPP_CUSTOM_TBT_PROTOCOL "://")) {
713 directory = customTitleBlockTemplatesDir();
714 } else return(QString());
715 return(directory + QDir::toNativeSeparators(sym_path.right(sym_path.length() - 9)));
716 }
717
718 /**
719 Construit le chemin symbolique (du type custom://outils_pervers/sado_maso/
720 contact_bizarre) correspondant a un fichier.
721 @param real_path Chaine de caracteres representant le chemin symbolique du fichier
722 @return Une chaine de caracteres vide en cas d'erreur ou le chemin
723 symbolique designant l'element.
724 */
symbolicPath(const QString & real_path)725 QString QETApp::symbolicPath(const QString &real_path) {
726 // recupere les dossier common et custom
727 QString commond = commonElementsDir();
728 QString customd = customElementsDir();
729 QString chemin;
730 // analyse le chemin de fichier passe en parametre
731 if (real_path.startsWith(commond)) {
732 chemin = "common://" + real_path.right(real_path.length() - commond.length());
733 } else if (real_path.startsWith(customd)) {
734 chemin = "custom://" + real_path.right(real_path.length() - customd.length());
735 } else chemin = QString();
736 return(chemin);
737 }
738
739 /**
740 @return the list of file extensions QElectroTech is able to open and
741 supposed to handle. Note they are provided with no leading point.
742 */
handledFileExtensions()743 QStringList QETApp::handledFileExtensions() {
744 static QStringList ext;
745 if (!ext.count()) {
746 ext << "qet";
747 ext << "elmt";
748 ext << QString(TITLEBLOCKS_FILE_EXTENSION).remove(QRegExp("^\\."));
749 }
750 return(ext);
751 }
752
753 /**
754 @param an URLs list
755 @return the list of filepaths QElectroTech is able to open.
756 */
handledFiles(const QList<QUrl> & urls)757 QStringList QETApp::handledFiles(const QList<QUrl> &urls) {
758 QList<QString> filepaths;
759 foreach (QUrl url, urls) {
760 if (url.scheme() != "file") continue;
761 QString local_path = url.toLocalFile();
762 QFileInfo local_path_info(local_path);
763 QString local_path_ext = local_path_info.completeSuffix();
764 if (handledFileExtensions().contains(local_path_ext)) {
765 filepaths << local_path;
766 }
767 }
768 return(filepaths);
769 }
770
771 /**
772 @param filepath Un chemin de fichier
773 Note : si filepath est une chaine vide, cette methode retourne 0.
774 @return le QETDiagramEditor editant le fichier filepath, ou 0 si ce fichier
775 n'est pas edite par l'application.
776 */
diagramEditorForFile(const QString & filepath)777 QETDiagramEditor *QETApp::diagramEditorForFile(const QString &filepath) {
778 if (filepath.isEmpty()) return(nullptr);
779
780 QETApp *qet_app(QETApp::instance());
781 foreach (QETDiagramEditor *diagram_editor, qet_app -> diagramEditors()) {
782 if (diagram_editor -> viewForFile(filepath)) {
783 return(diagram_editor);
784 }
785 }
786
787 return(nullptr);
788 }
789
790 /**
791 * @brief QETApp::diagramEditorAncestorOf
792 * @param child
793 * @return the parent QETDiagramEditor (or grandparent and so on to any level) of the given child.
794 * If not return nullptr;
795 */
diagramEditorAncestorOf(const QWidget * child)796 QETDiagramEditor *QETApp::diagramEditorAncestorOf (const QWidget *child)
797 {
798 foreach (QETDiagramEditor *qde, QETApp::diagramEditors()) {
799 if (qde->isAncestorOf(child)) {
800 return qde;
801 }
802 }
803
804 return nullptr;
805 }
806
807 #ifdef QET_ALLOW_OVERRIDE_CED_OPTION
808 /**
809 Redefinit le chemin du dossier des elements communs
810 @param new_ced Nouveau chemin du dossier des elements communs
811 */
overrideCommonElementsDir(const QString & new_ced)812 void QETApp::overrideCommonElementsDir(const QString &new_ced) {
813 QFileInfo new_ced_info(new_ced);
814 if (new_ced_info.isDir()) {
815 common_elements_dir = new_ced_info.absoluteFilePath();
816 if (!common_elements_dir.endsWith("/")) common_elements_dir += "/";
817 }
818 }
819 #endif
820
821 #ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION
822 /**
823 Define the path of the directory containing the common title block
824 tempaltes collection.
825 */
overrideCommonTitleBlockTemplatesDir(const QString & new_ctbtd)826 void QETApp::overrideCommonTitleBlockTemplatesDir(const QString &new_ctbtd) {
827 QFileInfo new_ctbtd_info(new_ctbtd);
828 if (new_ctbtd_info.isDir()) {
829 common_tbt_dir_ = new_ctbtd_info.absoluteFilePath();
830 if (!common_tbt_dir_.endsWith("/")) common_tbt_dir_ += "/";
831 }
832 }
833 #endif
834
835 #ifdef QET_ALLOW_OVERRIDE_CD_OPTION
836 /**
837 Redefinit le chemin du dossier de configuration
838 @param new_cd Nouveau chemin du dossier de configuration
839 */
overrideConfigDir(const QString & new_cd)840 void QETApp::overrideConfigDir(const QString &new_cd) {
841 QFileInfo new_cd_info(new_cd);
842 if (new_cd_info.isDir()) {
843 config_dir = new_cd_info.absoluteFilePath();
844 if (!config_dir.endsWith("/")) config_dir += "/";
845 }
846 }
847 #endif
848
849 /**
850 Redefinit le chemin du dossier contenant les fichiers de langue
851 @param new_ld Nouveau chemin du dossier contenant les fichiers de langue
852 */
overrideLangDir(const QString & new_ld)853 void QETApp::overrideLangDir(const QString &new_ld) {
854 QFileInfo new_ld_info(new_ld);
855 if (new_ld_info.isDir()) {
856 lang_dir = new_ld_info.absoluteFilePath();
857 if (!lang_dir.endsWith("/")) lang_dir += "/";
858 }
859 }
860
861 /**
862 @return Le chemin du dossier contenant les fichiers de langue
863 */
languagesPath()864 QString QETApp::languagesPath() {
865 if (!lang_dir.isEmpty()) {
866 return(lang_dir);
867 } else {
868 #ifndef QET_LANG_PATH
869 // en l'absence d'option de compilation, on utilise le dossier lang, situe a cote du binaire executable
870 return(QCoreApplication::applicationDirPath() + "/lang/");
871 #else
872 #ifndef QET_LANG_PATH_RELATIVE_TO_BINARY_PATH
873 // l'option de compilation represente un chemin absolu ou relatif classique
874 return(QUOTE(QET_LANG_PATH));
875 #else
876 // l'option de compilation represente un chemin relatif au dossier contenant le binaire executable
877 return(QCoreApplication::applicationDirPath() + "/" + QUOTE(QET_LANG_PATH));
878 #endif
879 #endif
880 }
881 }
882
883 /**
884 Ferme tous les editeurs
885 @return true si l'utilisateur a accepte toutes les fermetures, false sinon
886 */
closeEveryEditor()887 bool QETApp::closeEveryEditor() {
888 // s'assure que toutes les fenetres soient visibles avant de quitter
889 restoreEveryEditor();
890 foreach(QETProject *project, registered_projects_) {
891 project -> close();
892 }
893 bool every_window_closed = true;
894 foreach(QETDiagramEditor *e, diagramEditors()) {
895 every_window_closed = every_window_closed && e -> close();
896 }
897 foreach(QETElementEditor *e, elementEditors()) {
898 every_window_closed = every_window_closed && e -> close();
899 }
900 return(every_window_closed);
901 }
902
903 /**
904 * @brief QETApp::diagramTextsFont
905 * The font to use
906 * By default the font is "sans Serif" and size 9.
907 * @param size : the size of font
908 * @return the font to use
909 */
diagramTextsFont(qreal size)910 QFont QETApp::diagramTextsFont(qreal size)
911 {
912 QSettings settings;
913
914 //Font to use
915 QString diagram_texts_family = settings.value("diagramfont", "Sans Serif").toString();
916 qreal diagram_texts_size = settings.value("diagramsize", 9.0).toDouble();
917
918 if (size != -1.0) {
919 diagram_texts_size = size;
920 }
921 QFont diagram_texts_font = QFont(diagram_texts_family);
922 diagram_texts_font.setPointSizeF(diagram_texts_size);
923 if (diagram_texts_size <= 4.0) {
924 diagram_texts_font.setWeight(QFont::Light);
925 }
926 return(diagram_texts_font);
927 }
928 /**
929 * @brief QETApp::diagramTextsItemFont
930 * the font for to use in independent text item
931 * @param size of font
932 * @return
933 */
diagramTextsItemFont(qreal size)934 QFont QETApp::diagramTextsItemFont(qreal size)
935 {
936 QSettings settings;
937
938 //Font to use
939 QString diagram_texts_item_family = settings.value("diagramitemfont", "Sans Serif").toString();
940 qreal diagram_texts_item_size = settings.value("diagramitemsize", 9.0).toDouble();
941 qreal diagram_texts_item_weight = settings.value("diagramitemweight").toDouble();
942 QString diagram_texts_item_style = settings.value("diagramitemstyle", "normal").toString();
943
944 if (size != -1.0) {
945 diagram_texts_item_size = size;
946 }
947 QFont diagram_texts_item_font = QFont(diagram_texts_item_family);
948 diagram_texts_item_font.setPointSizeF(diagram_texts_item_size);
949 diagram_texts_item_font.setWeight(diagram_texts_item_weight);
950 diagram_texts_item_font.setStyleName(diagram_texts_item_style);
951 if (diagram_texts_item_size <= 4.0) {
952 diagram_texts_item_font.setWeight(QFont::Light);
953 }
954 return(diagram_texts_item_font);
955 }
956 /**
957 * @brief QETApp::dynamicTextsFont
958 * the defaukt font of dynamic element text item
959 * @param size
960 * @return
961 */
dynamicTextsItemFont(qreal size)962 QFont QETApp::dynamicTextsItemFont(qreal size)
963 {
964 QSettings settings;
965 //Font to use
966 QFont font_ = diagramTextsItemFont();
967 if (settings.contains("diagrameditor/dynamic_text_font")) {
968 font_.fromString(settings.value("diagrameditor/dynamic_text_font").toString());
969 }
970 if (size > 0) {
971 font_.setPointSizeF(size);
972 }
973 return(font_);
974 }
975
976 /**
977 * @brief QETApp::foliolistTextsFont
978 * the font for to use in summary pages
979 * @param size
980 * @return
981 */
foliolistTextsFont(qreal size)982 QFont QETApp::foliolistTextsFont(qreal size)
983 {
984 QSettings settings;
985
986 //Font to use
987 QString foliolist_texts_family = settings.value("foliolistfont", "Sans Serif").toString();
988 qreal foliolist_texts_size = settings.value("foliolistsize", 9.0).toDouble();
989
990 if (size != -1.0) {
991 foliolist_texts_size = size;
992 }
993 QFont foliolist_texts_font = QFont(foliolist_texts_family);
994 foliolist_texts_font.setPointSizeF(foliolist_texts_size);
995 if (foliolist_texts_size <= 4.0) {
996 foliolist_texts_font.setWeight(QFont::Light);
997 }
998 return(foliolist_texts_font);
999 }
1000
1001 /**
1002 * @brief QETApp::indiTextsItemFont
1003 * The default font to use for independent text item
1004 * @param size
1005 * @return
1006 */
indiTextsItemFont(qreal size)1007 QFont QETApp::indiTextsItemFont(qreal size)
1008 {
1009 QSettings settings;
1010 //Font to use
1011 QFont font_ = diagramTextsItemFont();
1012 if (settings.contains("diagrameditor/independent_text_font")) {
1013 font_.fromString(settings.value("diagrameditor/independent_text_font").toString());
1014 }
1015 if (size > 0) {
1016 font_.setPointSizeF(size);
1017 }
1018 return(font_);
1019 }
1020
1021
1022 /**
1023 @return les editeurs de schemas
1024 */
diagramEditors()1025 QList<QETDiagramEditor *> QETApp::diagramEditors() {
1026 return(QETApp::instance() -> detectWindows<QETDiagramEditor>());
1027 }
1028
1029 /**
1030 @return les editeurs d'elements
1031 */
elementEditors()1032 QList<QETElementEditor *> QETApp::elementEditors() {
1033 return(QETApp::instance() -> detectWindows<QETElementEditor>());
1034 }
1035
1036 /**
1037 @return the title block template editors
1038 */
titleBlockTemplateEditors()1039 QList<QETTitleBlockTemplateEditor *> QETApp::titleBlockTemplateEditors() {
1040 return(QETApp::instance() -> detectWindows<QETTitleBlockTemplateEditor>());
1041 }
1042
1043 /**
1044 @param project Opened project object.
1045 @return the list of title block template editors which are currently
1046 editing a template embedded within \a project.
1047 */
titleBlockTemplateEditors(QETProject * project)1048 QList<QETTitleBlockTemplateEditor *> QETApp::titleBlockTemplateEditors(QETProject *project) {
1049 QList<QETTitleBlockTemplateEditor *> editors;
1050 if (!project) return(editors);
1051
1052 // foreach known template editor
1053 foreach (QETTitleBlockTemplateEditor *tbt_editor, titleBlockTemplateEditors()) {
1054 if (tbt_editor -> location().parentProject() == project) {
1055 editors << tbt_editor;
1056 }
1057 }
1058
1059 return(editors);
1060 }
1061
1062 /**
1063 Instancie un QTextOrientationSpinBoxWidget et configure :
1064 * sa police de caracteres
1065 * ses chaines de caracteres
1066 A noter que la suppression du widget ainsi alloue est a la charge de
1067 l'appelant.
1068 @return un QTextOrientationSpinBoxWidget adapte pour une utilisation
1069 "directe" dans QET.
1070 @see QTextOrientationSpinBoxWidget
1071 */
createTextOrientationSpinBoxWidget()1072 QTextOrientationSpinBoxWidget *QETApp::createTextOrientationSpinBoxWidget() {
1073 QTextOrientationSpinBoxWidget *widget = new QTextOrientationSpinBoxWidget();
1074 widget -> orientationWidget() -> setFont(QETApp::diagramTextsFont());
1075 widget -> orientationWidget() -> setUsableTexts(QList<QString>()
1076 << QETApp::tr("Q", "Single-letter example text - translate length, not meaning")
1077 << QETApp::tr("QET", "Small example text - translate length, not meaning")
1078 << QETApp::tr("Schema", "Normal example text - translate length, not meaning")
1079 << QETApp::tr("Electrique", "Normal example text - translate length, not meaning")
1080 << QETApp::tr("QElectroTech", "Long example text - translate length, not meaning")
1081 );
1082 return(widget);
1083 }
1084
1085 /**
1086 @return the default titleblock template for diagrams
1087 */
defaultTitleBlockTemplate()1088 TitleBlockTemplate *QETApp::defaultTitleBlockTemplate() {
1089 if (!QETApp::default_titleblock_template_) {
1090 TitleBlockTemplate *titleblock_template = new TitleBlockTemplate(QETApp::instance());
1091 if (titleblock_template -> loadFromXmlFile(":/titleblocks/default.titleblock")) {
1092 QETApp::default_titleblock_template_ = titleblock_template;
1093 }
1094 }
1095 return(default_titleblock_template_);
1096 }
1097
1098
1099 /**
1100 @param project un projet
1101 @return les editeurs d'elements editant un element appartenant au projet
1102 project
1103 */
elementEditors(QETProject * project)1104 QList<QETElementEditor *> QETApp::elementEditors(QETProject *project) {
1105 QList<QETElementEditor *> editors;
1106 if (!project) return(editors);
1107
1108 // pour chaque editeur d'element...
1109 foreach(QETElementEditor *elmt_editor, elementEditors()) {
1110 // on recupere l'emplacement de l'element qu'il edite
1111 ElementsLocation elmt_editor_loc(elmt_editor -> location());
1112
1113 // il se peut que l'editeur edite un element non enregistre ou un fichier
1114 if (elmt_editor_loc.isNull()) continue;
1115
1116 if (elmt_editor_loc.project() == project) {
1117 editors << elmt_editor;
1118 }
1119 }
1120
1121 return(editors);
1122 }
1123
receiveMessage(int instanceId,QByteArray message)1124 void QETApp::receiveMessage(int instanceId, QByteArray message)
1125 {
1126 Q_UNUSED(instanceId);
1127
1128 QString str(message);
1129
1130 if (str.startsWith("launched-with-args: "))
1131 {
1132 QString my_message(str.mid(20));
1133 QStringList args_list = QET::splitWithSpaces(my_message);
1134 openFiles(QETArguments(args_list));
1135 }
1136 }
1137
1138 /**
1139 @param T a class inheriting QMainWindow
1140 @return the list of windows of type T
1141 */
detectWindows() const1142 template <class T> QList<T *> QETApp::detectWindows() const {
1143 QList<T *> windows;
1144 foreach(QWidget *widget, qApp->topLevelWidgets()) {
1145 if (!widget -> isWindow()) continue;
1146 if (T *window = qobject_cast<T *>(widget)) {
1147 windows << window;
1148 }
1149 }
1150 return(windows);
1151 }
1152
1153 /**
1154 @param T a class inheriting QMainWindow
1155 @param visible whether detected main windows should be visible
1156 */
setMainWindowsVisible(bool visible)1157 template <class T> void QETApp::setMainWindowsVisible(bool visible) {
1158 foreach(T *e, detectWindows<T>()) {
1159 setMainWindowVisible(e, visible);
1160 }
1161 }
1162
1163 /**
1164 @return La liste des fichiers recents pour les projets
1165 */
projectsRecentFiles()1166 RecentFiles *QETApp::projectsRecentFiles() {
1167 return(m_projects_recent_files);
1168 }
1169
1170 /**
1171 @return La liste des fichiers recents pour les elements
1172 */
elementsRecentFiles()1173 RecentFiles *QETApp::elementsRecentFiles() {
1174 return(m_elements_recent_files);
1175 }
1176
1177 /**
1178 Affiche ou cache une fenetre (editeurs de schemas / editeurs d'elements)
1179 @param window fenetre a afficher / cacher
1180 @param visible true pour affiche la fenetre, false sinon
1181 */
setMainWindowVisible(QMainWindow * window,bool visible)1182 void QETApp::setMainWindowVisible(QMainWindow *window, bool visible) {
1183 if (window -> isVisible() == visible) return;
1184 if (!visible) {
1185 window_geometries.insert(window, window -> saveGeometry());
1186 window_states.insert(window, window -> saveState());
1187 window -> hide();
1188 // cache aussi les toolbars et les docks
1189 foreach (QWidget *qw, floatingToolbarsAndDocksForMainWindow(window)) {
1190 qw -> hide();
1191 }
1192 } else {
1193 window -> show();
1194 #ifndef Q_OS_WIN32
1195 window -> restoreGeometry(window_geometries[window]);
1196 #endif
1197 window -> restoreState(window_states[window]);
1198 }
1199 }
1200
1201 /**
1202 Affiche une fenetre (editeurs de schemas / editeurs d'elements) si
1203 celle-ci est cachee ou la cache si elle est affichee.
1204 @param window fenetre a afficher / cacher
1205 */
invertMainWindowVisibility(QWidget * window)1206 void QETApp::invertMainWindowVisibility(QWidget *window) {
1207 if (QMainWindow *w = qobject_cast<QMainWindow *>(window)) setMainWindowVisible(w, !w -> isVisible());
1208 }
1209
1210 /**
1211 Autodetec Windows style
1212 @param Windows style
1213 */
1214 #if defined(Q_OS_WIN) && defined(Q_OS_WINCE)
1215
1216 if defined(Q_OS_WIN)
1217 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA
1218 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
1219 style = QLatin1String("WindowsVista");
1220 else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
1221 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
1222 style = QLatin1String("WindowsXP");
1223 else
1224 style = QLatin1String("Windows"); // default styles for Windows
1225 #endif
1226
1227
1228 /**
1229 Change la palette de l'application
1230 @param use true pour utiliser les couleurs du systeme, false pour utiliser celles du theme en cours
1231 */
useSystemPalette(bool use)1232 void QETApp::useSystemPalette(bool use) {
1233 if (use) {
1234 qApp->setPalette(initial_palette_);
1235 qApp->setStyleSheet(
1236 "QTabBar::tab:!selected { background-color: transparent; }"
1237 "QAbstractScrollArea#mdiarea {"
1238 "background-color -> setPalette(initial_palette_);"
1239 "}"
1240 );
1241 } else {
1242 QFile file(configDir() + "style.css");
1243 file.open(QFile::ReadOnly);
1244 QString styleSheet = QLatin1String(file.readAll());
1245 qApp->setStyleSheet(styleSheet);
1246 file.close();
1247 }
1248 }
1249
1250 /**
1251 Demande la fermeture de toutes les fenetres ; si l'utilisateur les accepte,
1252 l'application quitte
1253 */
quitQET()1254 void QETApp::quitQET() {
1255 if (closeEveryEditor()) {
1256 qApp->quit();
1257 }
1258 }
1259
1260 /**
1261 Verifie s'il reste des fenetres (cachees ou non) et quitte s'il n'en reste
1262 plus.
1263 */
checkRemainingWindows()1264 void QETApp::checkRemainingWindows() {
1265 /* petite bidouille : le slot se rappelle apres 500 ms d'attente
1266 afin de compenser le fait que certaines fenetres peuvent encore
1267 paraitre vivantes alors qu'elles viennent d'etre fermees
1268 */
1269 static bool sleep = true;
1270 if (sleep) {
1271 QTimer::singleShot(500, this, SLOT(checkRemainingWindows()));
1272 } else {
1273 if (!diagramEditors().count() && !elementEditors().count()) {
1274 qApp->quit();
1275 }
1276 }
1277 sleep = !sleep;
1278 }
1279
1280 /**
1281 Ouvre les fichiers passes en arguments
1282 @param args Objet contenant des arguments ; les fichiers
1283 @see openProjectFiles openElementFiles
1284 */
openFiles(const QETArguments & args)1285 void QETApp::openFiles(const QETArguments &args) {
1286 openProjectFiles(args.projectFiles());
1287 openElementFiles(args.elementFiles());
1288 openTitleBlockTemplateFiles(args.titleBlockTemplateFiles());
1289 }
1290
1291 /**
1292 Ouvre une liste de fichiers.
1293 Les fichiers sont ouverts dans le premier editeur de schemas visible venu.
1294 Sinon, le premier editeur de schemas existant venu devient visible et est
1295 utilise. S'il n'y a aucun editeur de schemas ouvert, un nouveau est cree et
1296 utilise.
1297 @param files_list Fichiers a ouvrir
1298 */
openProjectFiles(const QStringList & files_list)1299 void QETApp::openProjectFiles(const QStringList &files_list) {
1300 if (files_list.isEmpty()) return;
1301
1302 // liste des editeurs de schema ouverts
1303 QList<QETDiagramEditor *> diagrams_editors = diagramEditors();
1304
1305 // s'il y a des editeur de schemas ouvert, on cherche ceux qui sont visibles
1306 if (diagrams_editors.count()) {
1307 QList<QETDiagramEditor *> visible_diagrams_editors;
1308 foreach(QETDiagramEditor *de, diagrams_editors) {
1309 if (de -> isVisible()) visible_diagrams_editors << de;
1310 }
1311
1312 // on choisit soit le premier visible soit le premier tout court
1313 QETDiagramEditor *de_open;
1314 if (visible_diagrams_editors.count()) {
1315 de_open = visible_diagrams_editors.first();
1316 } else {
1317 de_open = diagrams_editors.first();
1318 de_open -> setVisible(true);
1319 }
1320
1321 // ouvre les fichiers dans l'editeur ainsi choisi
1322 foreach(QString file, files_list) {
1323 de_open -> openAndAddProject(file);
1324 }
1325 } else {
1326 // cree un nouvel editeur qui ouvrira les fichiers
1327 new QETDiagramEditor(files_list);
1328 }
1329 }
1330
1331 /**
1332 Ouvre les fichiers elements passes en parametre. Si un element est deja
1333 ouvert, la fenetre qui l'edite est activee.
1334 @param files_list Fichiers a ouvrir
1335 */
openElementFiles(const QStringList & files_list)1336 void QETApp::openElementFiles(const QStringList &files_list) {
1337 if (files_list.isEmpty()) return;
1338
1339 // evite autant que possible les doublons dans la liste fournie
1340 QSet<QString> files_set;
1341 foreach(QString file, files_list) {
1342 QString canonical_filepath = QFileInfo(file).canonicalFilePath();
1343 if (!canonical_filepath.isEmpty()) files_set << canonical_filepath;
1344 }
1345 // a ce stade, tous les fichiers dans le Set existent et sont a priori differents
1346 if (files_set.isEmpty()) return;
1347
1348 // liste des editeurs d'element ouverts
1349 QList<QETElementEditor *> element_editors = elementEditors();
1350
1351 // on traite les fichiers a la queue leu leu...
1352 foreach(QString element_file, files_set) {
1353 bool already_opened_in_existing_element_editor = false;
1354 foreach(QETElementEditor *element_editor, element_editors) {
1355 if (element_editor -> isEditing(element_file)) {
1356 // ce fichier est deja ouvert dans un editeur
1357 already_opened_in_existing_element_editor = true;
1358 element_editor -> setVisible(true);
1359 element_editor -> raise();
1360 element_editor -> activateWindow();
1361 break;
1362 }
1363 }
1364 if (!already_opened_in_existing_element_editor) {
1365 // ce fichier n'est ouvert dans aucun editeur
1366 QETElementEditor *element_editor = new QETElementEditor();
1367 element_editor -> fromFile(element_file);
1368 }
1369 }
1370 }
1371
1372 /**
1373 Ouvre les elements dont l'emplacement est passe en parametre. Si un element
1374 est deja ouvert, la fentre qui l'edite est activee.
1375 @param locations_list Emplacements a ouvrir
1376 */
openElementLocations(const QList<ElementsLocation> & locations_list)1377 void QETApp::openElementLocations(const QList<ElementsLocation> &locations_list) {
1378 if (locations_list.isEmpty()) return;
1379
1380 // liste des editeurs d'element ouverts
1381 QList<QETElementEditor *> element_editors = elementEditors();
1382
1383 // on traite les emplacements a la queue leu leu...
1384 foreach(ElementsLocation element_location, locations_list) {
1385 bool already_opened_in_existing_element_editor = false;
1386 foreach(QETElementEditor *element_editor, element_editors) {
1387 if (element_editor -> isEditing(element_location)) {
1388 // cet emplacement est deja ouvert dans un editeur
1389 already_opened_in_existing_element_editor = true;
1390 element_editor -> setVisible(true);
1391 element_editor -> raise();
1392 element_editor -> activateWindow();
1393 break;
1394 }
1395 }
1396 if (!already_opened_in_existing_element_editor) {
1397 // cet emplacement n'est ouvert dans aucun editeur
1398 QETElementEditor *element_editor = new QETElementEditor();
1399 element_editor -> fromLocation(element_location);
1400 }
1401 }
1402 }
1403
1404 /**
1405 Launch a new title block template editor to edit the given template
1406 @param location location of the title block template to be edited
1407
1408 @param duplicate if true, the template is opened for duplication, which means
1409 the user will be prompter for a new template name.
1410 @see QETTitleBlockTemplateEditor::setOpenForDuplication()
1411 */
openTitleBlockTemplate(const TitleBlockTemplateLocation & location,bool duplicate)1412 void QETApp::openTitleBlockTemplate(const TitleBlockTemplateLocation &location, bool duplicate) {
1413 QETTitleBlockTemplateEditor *qet_template_editor = new QETTitleBlockTemplateEditor();
1414 qet_template_editor -> setOpenForDuplication(duplicate);
1415 qet_template_editor -> edit(location);
1416 qet_template_editor -> show();
1417 }
1418
1419 /**
1420 Launch a new title block template editor to edit the given template
1421 @param filepath Path of the .titleblock file to be opened
1422 */
openTitleBlockTemplate(const QString & filepath)1423 void QETApp::openTitleBlockTemplate(const QString &filepath) {
1424 QETTitleBlockTemplateEditor *qet_template_editor = new QETTitleBlockTemplateEditor();
1425 qet_template_editor -> edit(filepath);
1426 qet_template_editor -> show();
1427 }
1428
1429 /**
1430 Open provided title block template files. If a title block template is already
1431 opened, the adequate window is activated.
1432 @param files_list Files to be opened
1433 */
openTitleBlockTemplateFiles(const QStringList & files_list)1434 void QETApp::openTitleBlockTemplateFiles(const QStringList &files_list) {
1435 if (files_list.isEmpty()) return;
1436
1437 // avoid duplicates in the provided files list
1438 QSet<QString> files_set;
1439 foreach (QString file, files_list) {
1440 QString canonical_filepath = QFileInfo(file).canonicalFilePath();
1441 if (!canonical_filepath.isEmpty()) files_set << canonical_filepath;
1442 }
1443 // here, we can assume all files in the set exist and are different
1444 if (files_set.isEmpty()) return;
1445
1446 // opened title block template editors
1447 QList<QETTitleBlockTemplateEditor *> tbt_editors = titleBlockTemplateEditors();
1448
1449 foreach(QString tbt_file, files_set) {
1450 bool already_opened_in_existing_tbt_editor = false;
1451 foreach(QETTitleBlockTemplateEditor *tbt_editor, tbt_editors) {
1452 if (tbt_editor -> isEditing(tbt_file)) {
1453 // this file is already opened
1454 already_opened_in_existing_tbt_editor = true;
1455 tbt_editor -> setVisible(true);
1456 tbt_editor -> raise();
1457 tbt_editor -> activateWindow();
1458 break;
1459 }
1460 }
1461 if (!already_opened_in_existing_tbt_editor) {
1462 // this file is not opened yet
1463 openTitleBlockTemplate(tbt_file);
1464 }
1465 }
1466 }
1467
1468 /**
1469 Permet a l'utilisateur de configurer QET en lancant un dialogue approprie.
1470 @see ConfigDialog
1471 */
configureQET()1472 void QETApp::configureQET() {
1473 // determine le widget parent a utiliser pour le dialogue
1474 QWidget *parent_widget = qApp->activeWindow();
1475
1476 // cree le dialogue
1477 ConfigDialog cd;
1478 cd.setWindowTitle(tr("Configurer QElectroTech", "window title"));
1479 cd.setWindowModality(Qt::WindowModal);
1480 cd.addPage(new GeneralConfigurationPage());
1481 cd.addPage(new NewDiagramPage());
1482 cd.addPage(new ExportConfigPage());
1483 cd.addPage(new PrintConfigPage());
1484
1485
1486 // associe le dialogue a un eventuel widget parent
1487 if (parent_widget) {
1488 cd.setParent(parent_widget, cd.windowFlags());
1489 }
1490
1491 // affiche le dialogue puis evite de le lier a un quelconque widget parent
1492 cd.exec();
1493 cd.setParent(nullptr, cd.windowFlags());
1494 }
1495
1496 /**
1497 * @brief QETApp::aboutQET
1498 * Open the dialog about qet.
1499 */
aboutQET()1500 void QETApp::aboutQET()
1501 {
1502 AboutQET aq(qApp->activeWindow());
1503
1504 #ifdef Q_OS_MACOS
1505 aq.setWindowFlags(Qt::Sheet);
1506 #endif
1507 aq.exec();
1508 }
1509
1510 /**
1511 @param window fenetre dont il faut trouver les barres d'outils et dock flottants
1512 @return les barres d'outils et dock flottants de la fenetre
1513 */
floatingToolbarsAndDocksForMainWindow(QMainWindow * window) const1514 QList<QWidget *> QETApp::floatingToolbarsAndDocksForMainWindow(QMainWindow *window) const {
1515 QList<QWidget *> widgets;
1516 foreach(QWidget *qw, qApp->topLevelWidgets()) {
1517 if (!qw -> isWindow()) continue;
1518 if (qobject_cast<QToolBar *>(qw) || qobject_cast<QDockWidget *>(qw)) {
1519 if (qw -> parent() == window) widgets << qw;
1520 }
1521 }
1522 return(widgets);
1523 }
1524
1525 /**
1526 Parse les arguments suivants :
1527 * --common-elements-dir=
1528 * --config-dir
1529 * --help
1530 * --version
1531 * -v
1532 * --license
1533 Les autres arguments sont normalement des chemins de fichiers.
1534 S'ils existent, ils sont juste memorises dans l'attribut arguments_files_.
1535 Sinon, ils sont memorises dans l'attribut arguments_options_.
1536 */
parseArguments()1537 void QETApp::parseArguments() {
1538 // recupere les arguments
1539 QList<QString> arguments_list(qApp->arguments());
1540
1541 // enleve le premier argument : il s'agit du fichier binaire
1542 arguments_list.takeFirst();
1543
1544 // analyse les arguments
1545 qet_arguments_ = QETArguments(arguments_list);
1546
1547 #ifdef QET_ALLOW_OVERRIDE_CED_OPTION
1548 if (qet_arguments_.commonElementsDirSpecified()) {
1549 overrideCommonElementsDir(qet_arguments_.commonElementsDir());
1550 }
1551 #endif
1552 #ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION
1553 if (qet_arguments_.commonTitleBlockTemplatesDirSpecified()) {
1554 overrideCommonTitleBlockTemplatesDir(qet_arguments_.commonTitleBlockTemplatesDir());
1555 }
1556 #endif
1557 #ifdef QET_ALLOW_OVERRIDE_CD_OPTION
1558 if (qet_arguments_.configDirSpecified()) {
1559 overrideConfigDir(qet_arguments_.configDir());
1560 }
1561 #endif
1562
1563 if (qet_arguments_.langDirSpecified()) {
1564 overrideLangDir(qet_arguments_.langDir());
1565 }
1566
1567 if (qet_arguments_.printLicenseRequested()) {
1568 printLicense();
1569 non_interactive_execution_ = true;
1570 }
1571 if (qet_arguments_.printHelpRequested()) {
1572 printHelp();
1573 non_interactive_execution_ = true;
1574 }
1575 if (qet_arguments_.printVersionRequested()) {
1576 printVersion();
1577 non_interactive_execution_ = true;
1578 }
1579 }
1580
1581 /**
1582 Initialise le splash screen si et seulement si l'execution est interactive.
1583 Autrement, l'attribut splash_screen_ vaut 0.
1584 */
initSplashScreen()1585 void QETApp::initSplashScreen() {
1586 if (non_interactive_execution_) return;
1587 m_splash_screen = new QSplashScreen(QPixmap(":/ico/splash.png"));
1588 m_splash_screen -> show();
1589 setSplashScreenStep(tr("Chargement...", "splash screen caption"));
1590 }
1591
1592 /**
1593 Change le texte du splash screen et prend en compte les evenements.
1594 Si l'application s'execute de facon non interactive, cette methode ne fait
1595 rien.
1596 */
setSplashScreenStep(const QString & message)1597 void QETApp::setSplashScreenStep(const QString &message) {
1598 if (!m_splash_screen) return;
1599 if (!message.isEmpty()) {
1600 m_splash_screen -> showMessage(message, Qt::AlignBottom | Qt::AlignLeft);
1601 }
1602 qApp->processEvents();
1603 }
1604
1605 /**
1606 Determine et applique le langage a utiliser pour l'application
1607 */
initLanguage()1608 void QETApp::initLanguage() {
1609 setLanguage(langFromSetting());
1610 }
1611
1612 /**
1613 * @brief QETApp::initStyle
1614 * Setup the gui style
1615 */
initStyle()1616 void QETApp::initStyle() {
1617 initial_palette_ = qApp->palette();
1618
1619 //Apply or not the system style
1620 QSettings settings;
1621 useSystemPalette(settings.value("usesystemcolors", true).toBool());
1622 }
1623
1624 /**
1625 Lit et prend en compte la configuration de l'application.
1626 Cette methode creera, si necessaire :
1627 * le dossier de configuration
1628 * le dossier de la collection perso
1629 * the directory for custom title blocks
1630 */
initConfiguration()1631 void QETApp::initConfiguration() {
1632 // cree les dossiers de configuration si necessaire
1633 QDir config_dir(QETApp::configDir());
1634 if (!config_dir.exists()) config_dir.mkpath(QETApp::configDir());
1635
1636 QDir custom_elements_dir(QETApp::customElementsDir());
1637 if (!custom_elements_dir.exists()) custom_elements_dir.mkpath(QETApp::customElementsDir());
1638
1639 QDir custom_tbt_dir(QETApp::customTitleBlockTemplatesDir());
1640 if (!custom_tbt_dir.exists()) custom_tbt_dir.mkpath(QETApp::customTitleBlockTemplatesDir());
1641
1642 // fichiers recents
1643 // note : les icones doivent etre initialisees avant ces instructions (qui creent des menus en interne)
1644 m_projects_recent_files = new RecentFiles("projects");
1645 m_projects_recent_files -> setIconForFiles(QET::Icons::ProjectFile);
1646 m_elements_recent_files = new RecentFiles("elements");
1647 m_elements_recent_files -> setIconForFiles(QET::Icons::Element);
1648 }
1649
1650 /**
1651 Construit l'icone dans le systray et son menu
1652 */
initSystemTray()1653 void QETApp::initSystemTray() {
1654 setSplashScreenStep(tr("Chargement... icône du systray", "splash screen caption"));
1655 // initialisation des menus de l'icone dans le systray
1656 menu_systray = new QMenu(tr("QElectroTech", "systray menu title"));
1657
1658 quitter_qet = new QAction(QET::Icons::ApplicationExit, tr("&Quitter"), this);
1659 reduce_appli = new QAction(QET::Icons::Hide, tr("&Masquer"), this);
1660 restore_appli = new QAction(QET::Icons::Restore, tr("&Restaurer"), this);
1661 reduce_diagrams = new QAction(QET::Icons::Hide, tr("&Masquer tous les éditeurs de schéma"), this);
1662 restore_diagrams = new QAction(QET::Icons::Restore, tr("&Restaurer tous les éditeurs de schéma"), this);
1663 reduce_elements = new QAction(QET::Icons::Hide, tr("&Masquer tous les éditeurs d'élément"), this);
1664 restore_elements = new QAction(QET::Icons::Restore, tr("&Restaurer tous les éditeurs d'élément"), this);
1665 reduce_templates = new QAction(QET::Icons::Hide, tr("&Masquer tous les éditeurs de cartouche", "systray submenu entry"), this);
1666 restore_templates = new QAction(QET::Icons::Restore, tr("&Restaurer tous les éditeurs de cartouche", "systray submenu entry"), this);
1667 new_diagram = new QAction(QET::Icons::WindowNew, tr("&Nouvel éditeur de schéma"), this);
1668 new_element = new QAction(QET::Icons::WindowNew, tr("&Nouvel éditeur d'élément"), this);
1669
1670 quitter_qet -> setStatusTip(tr("Ferme l'application QElectroTech"));
1671 reduce_appli -> setToolTip(tr("Réduire QElectroTech dans le systray"));
1672 restore_appli -> setToolTip(tr("Restaurer QElectroTech"));
1673
1674 connect(quitter_qet, SIGNAL(triggered()), this, SLOT(quitQET()));
1675 connect(reduce_appli, SIGNAL(triggered()), this, SLOT(reduceEveryEditor()));
1676 connect(restore_appli, SIGNAL(triggered()), this, SLOT(restoreEveryEditor()));
1677 connect(reduce_diagrams, SIGNAL(triggered()), this, SLOT(reduceDiagramEditors()));
1678 connect(restore_diagrams, SIGNAL(triggered()), this, SLOT(restoreDiagramEditors()));
1679 connect(reduce_elements, SIGNAL(triggered()), this, SLOT(reduceElementEditors()));
1680 connect(restore_elements, SIGNAL(triggered()), this, SLOT(restoreElementEditors()));
1681 connect(reduce_templates, SIGNAL(triggered()), this, SLOT(reduceTitleBlockTemplateEditors()));
1682 connect(restore_templates,SIGNAL(triggered()), this, SLOT(restoreTitleBlockTemplateEditors()));
1683 connect(new_diagram, SIGNAL(triggered()), this, SLOT(newDiagramEditor()));
1684 connect(new_element, SIGNAL(triggered()), this, SLOT(newElementEditor()));
1685
1686 // initialisation de l'icone du systray
1687 m_qsti = new QSystemTrayIcon(QET::Icons::QETLogo, this);
1688 m_qsti -> setToolTip(tr("QElectroTech", "systray icon tooltip"));
1689 connect(m_qsti, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(systray(QSystemTrayIcon::ActivationReason)));
1690 m_qsti -> setContextMenu(menu_systray);
1691 m_qsti -> show();
1692 }
1693
1694 /**
1695 Add a list of \a windows to \a menu.
1696 This template function assumes it will be given a QList of pointers to
1697 objects inheriting the QMainWindow class.
1698 @param T the class inheriting QMainWindow
1699 @param menu the menu windows will be added to
1700 @param windows A list of top-level windows.
1701 */
addWindowsListToMenu(QMenu * menu,const QList<T * > & windows)1702 template <class T> void QETApp::addWindowsListToMenu(QMenu *menu, const QList<T *> &windows) {
1703 menu -> addSeparator();
1704 foreach (QMainWindow *window, windows) {
1705 QAction *current_menu = menu -> addAction(window -> windowTitle());
1706 current_menu -> setCheckable(true);
1707 current_menu -> setChecked(window -> isVisible());
1708 connect(current_menu, SIGNAL(triggered()), &signal_map, SLOT(map()));
1709 signal_map.setMapping(current_menu, window);
1710 }
1711 }
1712
1713 /**
1714 @param url The location of a collection item (title block template,
1715 element, category, ...).
1716 @return the id of the project mentionned in the URL, or -1 if none could be
1717 found.
1718 */
projectIdFromString(const QString & url)1719 int QETApp::projectIdFromString(const QString &url) {
1720 QRegExp embedded("^project([0-9]+)\\+embed.*$", Qt::CaseInsensitive);
1721 if (embedded.exactMatch(url)) {
1722 bool conv_ok = false;
1723 int project_id = embedded.capturedTexts().at(1).toInt(&conv_ok);
1724 if (conv_ok) {
1725 return(project_id);
1726 }
1727 }
1728 return(-1);
1729 }
1730
1731 /**
1732 @param url The location of a collection item (title block template,
1733 element, category, ...).
1734 @return the project mentionned in the URL, or 0 if none could be
1735 found.
1736 */
projectFromString(const QString & url)1737 QETProject *QETApp::projectFromString(const QString &url) {
1738 int project_id = projectIdFromString(url);
1739 if (project_id == -1) return(nullptr);
1740 return(project(project_id));
1741 }
1742
1743 /// construit le menu de l'icone dans le systray
buildSystemTrayMenu()1744 void QETApp::buildSystemTrayMenu() {
1745 menu_systray -> clear();
1746
1747 // recupere les editeurs
1748 QList<QETDiagramEditor *> diagrams = diagramEditors();
1749 QList<QETElementEditor *> elements = elementEditors();
1750 QList<QETTitleBlockTemplateEditor *> tbtemplates = titleBlockTemplateEditors();
1751 fetchWindowStats(diagrams, elements, tbtemplates);
1752
1753 // ajoute le bouton reduire / restaurer au menu
1754 menu_systray -> addAction(every_editor_reduced ? restore_appli : reduce_appli);
1755
1756 // ajoute les editeurs de schemas dans un sous-menu
1757 QMenu *diagrams_submenu = menu_systray -> addMenu(tr("Éditeurs de schémas"));
1758 diagrams_submenu -> addAction(reduce_diagrams);
1759 diagrams_submenu -> addAction(restore_diagrams);
1760 diagrams_submenu -> addAction(new_diagram);
1761 reduce_diagrams -> setEnabled(!diagrams.isEmpty() && !every_diagram_reduced);
1762 restore_diagrams -> setEnabled(!diagrams.isEmpty() && !every_diagram_visible);
1763 addWindowsListToMenu<QETDiagramEditor>(diagrams_submenu, diagrams);
1764
1765 // ajoute les editeurs d'elements au menu
1766 QMenu *elements_submenu = menu_systray -> addMenu(tr("Éditeurs d'élément"));
1767 elements_submenu -> addAction(reduce_elements);
1768 elements_submenu -> addAction(restore_elements);
1769 elements_submenu -> addAction(new_element);
1770 reduce_elements -> setEnabled(!elements.isEmpty() && !every_element_reduced);
1771 restore_elements -> setEnabled(!elements.isEmpty() && !every_element_visible);
1772 elements_submenu -> addSeparator();
1773 addWindowsListToMenu<QETElementEditor>(elements_submenu, elements);
1774
1775 // add title block template editors in a submenu
1776 QMenu *tbtemplates_submenu = menu_systray -> addMenu(tr("Éditeurs de cartouche", "systray menu entry"));
1777 tbtemplates_submenu -> addAction(reduce_templates);
1778 tbtemplates_submenu -> addAction(restore_templates);
1779 reduce_templates -> setEnabled(!tbtemplates.isEmpty() && !every_template_reduced);
1780 restore_templates -> setEnabled(!tbtemplates.isEmpty() && !every_template_visible);
1781 addWindowsListToMenu<QETTitleBlockTemplateEditor>(tbtemplates_submenu, tbtemplates);
1782
1783 // ajoute le bouton quitter au menu
1784 menu_systray -> addSeparator();
1785 menu_systray -> addAction(quitter_qet);
1786 }
1787
1788 /**
1789 * @brief QETApp::checkBackupFiles
1790 * Check for backup files.
1791 * If backup was found, open a dialog and ask user what to do.
1792 */
checkBackupFiles()1793 void QETApp::checkBackupFiles()
1794 {
1795 QList<KAutoSaveFile *> stale_files = KAutoSaveFile::allStaleFiles();
1796
1797 //Remove from the list @stale_files, the stales file of opened project
1798 const QList<KAutoSaveFile *> sf = stale_files;
1799 for (KAutoSaveFile *kasf : sf)
1800 {
1801 for (QETProject *project : registeredProjects().values())
1802 {
1803 //We must to adjust with the flag QUrl::StripTrailingSlash to compar a path formated like the path returned by KAutoSaveFile
1804 const QString path = QUrl::fromLocalFile(project->filePath()).adjusted(QUrl::RemoveScheme | QUrl::StripTrailingSlash).path();
1805 if (kasf->managedFile() == path) {
1806 stale_files.removeOne(kasf);
1807 }
1808 }
1809 }
1810
1811 if (stale_files.isEmpty()) {
1812 return;
1813 }
1814
1815 QString text;
1816 if(stale_files.size() == 1) {
1817 text.append(tr("<b>Le fichier de restauration suivant a été trouvé,<br>"
1818 "Voulez-vous l'ouvrir ?</b><br>"));
1819 } else {
1820 text.append(tr("<b>Les fichiers de restauration suivant on été trouvé,<br>"
1821 "Voulez-vous les ouvrir ?</b><br>"));
1822 }
1823 for(const KAutoSaveFile *kasf : stale_files)
1824 {
1825 #ifdef Q_OS_WIN
1826 //Remove the first character '/' before the name of the drive
1827 text.append("<br>" + kasf->managedFile().path().remove(0,1));
1828 #else
1829 text.append("<br>" + kasf->managedFile().path());
1830 #endif
1831 }
1832
1833 //Open backup file
1834 if (QET::QetMessageBox::question(nullptr, tr("Fichier de restauration"), text, QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok)
1835 {
1836 //If there is opened editors, we find those who are visible
1837 if (diagramEditors().count())
1838 {
1839 diagramEditors().first()->setVisible(true);
1840 diagramEditors().first()->openBackupFiles(stale_files);
1841 }
1842 else
1843 {
1844 QETDiagramEditor *editor = new QETDiagramEditor();
1845 editor->openBackupFiles(stale_files);
1846 }
1847 }
1848 else //Clear backup file
1849 {
1850 //Remove the stale files
1851 for (KAutoSaveFile *stale : stale_files)
1852 {
1853 stale->open(QIODevice::ReadWrite);
1854 delete stale;
1855 }
1856 }
1857 }
1858
1859 /// Met a jour les booleens concernant l'etat des fenetres
fetchWindowStats(const QList<QETDiagramEditor * > & diagrams,const QList<QETElementEditor * > & elements,const QList<QETTitleBlockTemplateEditor * > & tbtemplates)1860 void QETApp::fetchWindowStats(
1861 const QList<QETDiagramEditor *> &diagrams,
1862 const QList<QETElementEditor *> &elements,
1863 const QList<QETTitleBlockTemplateEditor *> &tbtemplates
1864 ) {
1865 // compte le nombre de schemas visibles
1866 int visible_diagrams = 0;
1867 foreach(QMainWindow *w, diagrams) if (w -> isVisible()) ++ visible_diagrams;
1868 every_diagram_reduced = !visible_diagrams;
1869 every_diagram_visible = visible_diagrams == diagrams.count();
1870
1871 // compte le nombre de schemas visibles
1872 int visible_elements = 0;
1873 foreach(QMainWindow *w, elements) if (w -> isVisible()) ++ visible_elements;
1874 every_element_reduced = !visible_elements;
1875 every_element_visible = visible_elements == elements.count();
1876
1877 // count visible template editors
1878 int visible_templates = 0;
1879 foreach(QMainWindow *window, tbtemplates) {
1880 if (window -> isVisible()) ++ visible_templates;
1881 }
1882 every_template_reduced = !visible_templates;
1883 every_template_visible = visible_templates == tbtemplates.count();
1884
1885 // determine si tous les elements sont reduits
1886 every_editor_reduced = every_element_reduced && every_diagram_reduced;
1887 }
1888
1889 #ifdef Q_OS_DARWIN
1890 /**
1891 Gere les evenements, en particulier l'evenement FileOpen sous MacOs.
1892 @param e Evenement a gerer
1893 */
eventFiltrer(QObject * object,QEvent * e)1894 bool QETApp::eventFiltrer(QObject *object, QEvent *e) {
1895 // gere l'ouverture de fichiers (sous MacOs)
1896 if (e -> type() == QEvent::FileOpen) {
1897 // nom du fichier a ouvrir
1898 QString filename = static_cast<QFileOpenEvent *>(e) -> file();
1899 openFiles(QStringList() << filename);
1900 return(true);
1901 } else {
1902 return QObject::eventFilter(object, e);
1903 }
1904 }
1905 #endif
1906
1907 /**
1908 Affiche l'aide et l'usage sur la sortie standard
1909 */
printHelp()1910 void QETApp::printHelp() {
1911 QString help(
1912 tr("Usage : ") + QFileInfo(qApp->applicationFilePath()).fileName() + tr(" [options] [fichier]...\n\n") +
1913 tr("QElectroTech, une application de réalisation de schémas électriques.\n\n"
1914 "Options disponibles : \n"
1915 " --help Afficher l'aide sur les options\n"
1916 " -v, --version Afficher la version\n"
1917 " --license Afficher la licence\n")
1918 #ifdef QET_ALLOW_OVERRIDE_CED_OPTION
1919 + tr(" --common-elements-dir=DIR Definir le dossier de la collection d'elements\n")
1920 #endif
1921 #ifdef QET_ALLOW_OVERRIDE_CTBTD_OPTION
1922 + tr(" --common-tbt-dir=DIR Definir le dossier de la collection de modeles de cartouches\n")
1923 #endif
1924 #ifdef QET_ALLOW_OVERRIDE_CD_OPTION
1925 + tr(" --config-dir=DIR Definir le dossier de configuration\n")
1926 #endif
1927 + tr(" --lang-dir=DIR Definir le dossier contenant les fichiers de langue\n")
1928 );
1929 std::cout << qPrintable(help) << std::endl;
1930 }
1931
1932 /**
1933 Affiche la version sur la sortie standard
1934 */
printVersion()1935 void QETApp::printVersion() {
1936 std::cout << qPrintable(QET::displayedVersion) << std::endl;
1937 }
1938
1939 /**
1940 Affiche la licence sur la sortie standard
1941 */
printLicense()1942 void QETApp::printLicense() {
1943 std::cout << qPrintable(QET::license()) << std::endl;
1944 }
1945
1946 /**
1947 @return la liste des projets avec leurs ids associes
1948 */
registeredProjects()1949 QMap<uint, QETProject *> QETApp::registeredProjects() {
1950 return(registered_projects_);
1951 }
1952
1953 /**
1954 @param project Projet a enregistrer aupres de l'application
1955 @return true si le projet a pu etre enregistre, false sinon
1956 L'echec de l'enregistrement d'un projet signifie generalement qu'il est deja enregistre.
1957 */
registerProject(QETProject * project)1958 bool QETApp::registerProject(QETProject *project) {
1959 // le projet doit sembler valide
1960 if (!project) return(false);
1961
1962 // si le projet est deja enregistre, renvoie false
1963 if (projectId(project) != -1) return(false);
1964
1965 // enregistre le projet
1966 registered_projects_.insert(next_project_id ++, project);
1967 return(true);
1968 }
1969
1970 /**
1971 Annule l'enregistrement du projet project
1972 @param project Projet dont il faut annuler l'enregistrement
1973 @return true si l'annulation a reussi, false sinon
1974 L'echec de cette methode signifie generalement que le projet n'etait pas enregistre.
1975 */
unregisterProject(QETProject * project)1976 bool QETApp::unregisterProject(QETProject *project) {
1977 int project_id = projectId(project);
1978
1979 // si le projet n'est pas enregistre, renvoie false
1980 if (project_id == -1) return(false);
1981
1982 // annule l'enregistrement du projet
1983 return(registered_projects_.remove(project_id) == 1);
1984 }
1985
1986 /**
1987 @param id Id du projet voulu
1988 @return le projet correspond a l'id passe en parametre
1989 */
project(const uint & id)1990 QETProject *QETApp::project(const uint &id) {
1991 if (registered_projects_.contains(id)) {
1992 return(registered_projects_[id]);
1993 } else {
1994 return(nullptr);
1995 }
1996 }
1997
1998 /**
1999 @param project Projet dont on souhaite recuperer l'id
2000 @return l'id du projet en parametre si celui-ci est enregistre, -1 sinon
2001 */
projectId(const QETProject * project)2002 int QETApp::projectId(const QETProject *project) {
2003 foreach(int id, registered_projects_.keys()) {
2004 if (registered_projects_[id] == project) {
2005 return(id);
2006 }
2007 }
2008 return(-1);
2009 }
2010