Mercurial > hg > sonic-visualiser
comparison main/MainWindow.cpp @ 456:4bccf2014f80
Merge from branch "templating"
author | Chris Cannam |
---|---|
date | Sun, 26 Jun 2011 19:56:01 +0100 |
parents | 868f73825b37 e3644cd9cf99 |
children | b3b9cc8f5466 a6cbec451508 |
comparison
equal
deleted
inserted
replaced
452:fa0c3e79ea8e | 456:4bccf2014f80 |
---|---|
28 #include "data/osc/OSCQueue.h" | 28 #include "data/osc/OSCQueue.h" |
29 #include "framework/Document.h" | 29 #include "framework/Document.h" |
30 #include "framework/TransformUserConfigurator.h" | 30 #include "framework/TransformUserConfigurator.h" |
31 #include "view/ViewManager.h" | 31 #include "view/ViewManager.h" |
32 #include "base/Preferences.h" | 32 #include "base/Preferences.h" |
33 #include "base/ResourceFinder.h" | |
33 #include "layer/WaveformLayer.h" | 34 #include "layer/WaveformLayer.h" |
34 #include "layer/TimeRulerLayer.h" | 35 #include "layer/TimeRulerLayer.h" |
35 #include "layer/TimeInstantLayer.h" | 36 #include "layer/TimeInstantLayer.h" |
36 #include "layer/TimeValueLayer.h" | 37 #include "layer/TimeValueLayer.h" |
37 #include "layer/NoteLayer.h" | 38 #include "layer/NoteLayer.h" |
110 #include <QDateTime> | 111 #include <QDateTime> |
111 #include <QProcess> | 112 #include <QProcess> |
112 #include <QCheckBox> | 113 #include <QCheckBox> |
113 #include <QRegExp> | 114 #include <QRegExp> |
114 #include <QScrollArea> | 115 #include <QScrollArea> |
116 #include <QDesktopServices> | |
117 #include <QFileSystemWatcher> | |
115 | 118 |
116 #include <iostream> | 119 #include <iostream> |
117 #include <cstdio> | 120 #include <cstdio> |
118 #include <errno.h> | 121 #include <errno.h> |
119 | 122 |
135 m_playbackMenu(0), | 138 m_playbackMenu(0), |
136 m_existingLayersMenu(0), | 139 m_existingLayersMenu(0), |
137 m_sliceMenu(0), | 140 m_sliceMenu(0), |
138 m_recentFilesMenu(0), | 141 m_recentFilesMenu(0), |
139 m_recentTransformsMenu(0), | 142 m_recentTransformsMenu(0), |
143 m_templatesMenu(0), | |
140 m_rightButtonMenu(0), | 144 m_rightButtonMenu(0), |
141 m_rightButtonLayerMenu(0), | 145 m_rightButtonLayerMenu(0), |
142 m_rightButtonTransformsMenu(0), | 146 m_rightButtonTransformsMenu(0), |
143 m_rightButtonPlaybackMenu(0), | 147 m_rightButtonPlaybackMenu(0), |
144 m_soloAction(0), | 148 m_soloAction(0), |
156 m_playControlsSpacer(0), | 160 m_playControlsSpacer(0), |
157 m_playControlsWidth(0), | 161 m_playControlsWidth(0), |
158 m_preferencesDialog(0), | 162 m_preferencesDialog(0), |
159 m_layerTreeDialog(0), | 163 m_layerTreeDialog(0), |
160 m_activityLog(new ActivityLog()), | 164 m_activityLog(new ActivityLog()), |
161 m_keyReference(new KeyReference()) | 165 m_keyReference(new KeyReference()), |
166 m_templateWatcher(0) | |
162 { | 167 { |
163 Profiler profiler("MainWindow::MainWindow"); | 168 Profiler profiler("MainWindow::MainWindow"); |
164 | 169 |
165 setWindowTitle(tr("Sonic Visualiser")); | 170 setWindowTitle(tr("Sonic Visualiser")); |
166 | 171 |
386 action->setStatusTip(tr("Abandon the current Sonic Visualiser session and start a new one")); | 391 action->setStatusTip(tr("Abandon the current Sonic Visualiser session and start a new one")); |
387 connect(action, SIGNAL(triggered()), this, SLOT(newSession())); | 392 connect(action, SIGNAL(triggered()), this, SLOT(newSession())); |
388 m_keyReference->registerShortcut(action); | 393 m_keyReference->registerShortcut(action); |
389 menu->addAction(action); | 394 menu->addAction(action); |
390 toolbar->addAction(action); | 395 toolbar->addAction(action); |
391 | 396 /* |
392 icon = il.load("fileopensession"); | 397 icon = il.load("fileopensession"); |
393 action = new QAction(icon, tr("&Open Session..."), this); | 398 action = new QAction(icon, tr("&Open Session..."), this); |
394 action->setShortcut(tr("Ctrl+O")); | 399 action->setShortcut(tr("Ctrl+O")); |
395 action->setStatusTip(tr("Open a previously saved Sonic Visualiser session file")); | 400 action->setStatusTip(tr("Open a previously saved Sonic Visualiser session file")); |
396 connect(action, SIGNAL(triggered()), this, SLOT(openSession())); | 401 connect(action, SIGNAL(triggered()), this, SLOT(openSession())); |
397 m_keyReference->registerShortcut(action); | 402 m_keyReference->registerShortcut(action); |
398 menu->addAction(action); | 403 menu->addAction(action); |
399 | 404 */ |
400 icon = il.load("fileopen"); | 405 icon = il.load("fileopen"); |
401 icon.addPixmap(il.loadPixmap("fileopen-22")); | 406 icon.addPixmap(il.loadPixmap("fileopen-22")); |
402 | |
403 action = new QAction(icon, tr("&Open..."), this); | 407 action = new QAction(icon, tr("&Open..."), this); |
408 action->setShortcut(tr("Ctrl+O")); | |
404 action->setStatusTip(tr("Open a session file, audio file, or layer")); | 409 action->setStatusTip(tr("Open a session file, audio file, or layer")); |
405 connect(action, SIGNAL(triggered()), this, SLOT(openSomething())); | 410 connect(action, SIGNAL(triggered()), this, SLOT(openSomething())); |
406 toolbar->addAction(action); | 411 toolbar->addAction(action); |
412 menu->addAction(action); | |
413 | |
414 // We want this one to go on the toolbar now, if we add it at all, | |
415 // but on the menu later | |
416 QAction *iaction = new QAction(tr("&Import More Audio..."), this); | |
417 iaction->setShortcut(tr("Ctrl+I")); | |
418 iaction->setStatusTip(tr("Import an extra audio file into a new pane")); | |
419 connect(iaction, SIGNAL(triggered()), this, SLOT(importMoreAudio())); | |
420 connect(this, SIGNAL(canImportMoreAudio(bool)), iaction, SLOT(setEnabled(bool))); | |
421 m_keyReference->registerShortcut(iaction); | |
422 | |
423 action = new QAction(tr("Open Lo&cation..."), this); | |
424 action->setShortcut(tr("Ctrl+Shift+O")); | |
425 action->setStatusTip(tr("Open or import a file from a remote URL")); | |
426 connect(action, SIGNAL(triggered()), this, SLOT(openLocation())); | |
427 m_keyReference->registerShortcut(action); | |
428 menu->addAction(action); | |
429 | |
430 m_recentFilesMenu = menu->addMenu(tr("Open &Recent")); | |
431 m_recentFilesMenu->setTearOffEnabled(true); | |
432 setupRecentFilesMenu(); | |
433 connect(&m_recentFiles, SIGNAL(recentChanged()), | |
434 this, SLOT(setupRecentFilesMenu())); | |
435 | |
436 menu->addSeparator(); | |
407 | 437 |
408 icon = il.load("filesave"); | 438 icon = il.load("filesave"); |
409 icon.addPixmap(il.loadPixmap("filesave-22")); | 439 icon.addPixmap(il.loadPixmap("filesave-22")); |
410 action = new QAction(icon, tr("&Save Session"), this); | 440 action = new QAction(icon, tr("&Save Session"), this); |
411 action->setShortcut(tr("Ctrl+S")); | 441 action->setShortcut(tr("Ctrl+S")); |
425 menu->addAction(action); | 455 menu->addAction(action); |
426 toolbar->addAction(action); | 456 toolbar->addAction(action); |
427 | 457 |
428 menu->addSeparator(); | 458 menu->addSeparator(); |
429 | 459 |
460 /* | |
430 icon = il.load("fileopenaudio"); | 461 icon = il.load("fileopenaudio"); |
431 action = new QAction(icon, tr("&Import Audio File..."), this); | 462 action = new QAction(icon, tr("&Import Audio File..."), this); |
432 action->setShortcut(tr("Ctrl+I")); | 463 action->setShortcut(tr("Ctrl+I")); |
433 action->setStatusTip(tr("Import an existing audio file")); | 464 action->setStatusTip(tr("Import an existing audio file")); |
434 connect(action, SIGNAL(triggered()), this, SLOT(importAudio())); | 465 connect(action, SIGNAL(triggered()), this, SLOT(importAudio())); |
435 m_keyReference->registerShortcut(action); | 466 m_keyReference->registerShortcut(action); |
436 menu->addAction(action); | 467 menu->addAction(action); |
437 | 468 */ |
438 action = new QAction(tr("Import Secondary Audio File..."), this); | 469 |
439 action->setShortcut(tr("Ctrl+Shift+I")); | 470 // the Import action we made earlier |
440 action->setStatusTip(tr("Import an extra audio file as a separate layer")); | 471 menu->addAction(iaction); |
441 connect(action, SIGNAL(triggered()), this, SLOT(importMoreAudio())); | |
442 connect(this, SIGNAL(canImportMoreAudio(bool)), action, SLOT(setEnabled(bool))); | |
443 m_keyReference->registerShortcut(action); | |
444 menu->addAction(action); | |
445 | 472 |
446 action = new QAction(tr("&Export Audio File..."), this); | 473 action = new QAction(tr("&Export Audio File..."), this); |
447 action->setStatusTip(tr("Export selection as an audio file")); | 474 action->setStatusTip(tr("Export selection as an audio file")); |
448 connect(action, SIGNAL(triggered()), this, SLOT(exportAudio())); | 475 connect(action, SIGNAL(triggered()), this, SLOT(exportAudio())); |
449 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool))); | 476 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool))); |
473 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool))); | 500 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool))); |
474 menu->addAction(action); | 501 menu->addAction(action); |
475 | 502 |
476 menu->addSeparator(); | 503 menu->addSeparator(); |
477 | 504 |
478 action = new QAction(tr("Open Lo&cation..."), this); | 505 QString templatesMenuLabel = tr("Apply Session Template"); |
479 action->setShortcut(tr("Ctrl+Shift+O")); | 506 m_templatesMenu = menu->addMenu(templatesMenuLabel); |
480 action->setStatusTip(tr("Open or import a file from a remote URL")); | 507 m_templatesMenu->setTearOffEnabled(true); |
481 connect(action, SIGNAL(triggered()), this, SLOT(openLocation())); | 508 // We need to have a main model for this option to be useful: |
482 m_keyReference->registerShortcut(action); | 509 // canExportAudio captures that |
483 menu->addAction(action); | 510 connect(this, SIGNAL(canExportAudio(bool)), m_templatesMenu, SLOT(setEnabled(bool))); |
484 | 511 |
485 menu->addSeparator(); | 512 // Set up the menu in a moment, after m_manageTemplatesAction constructed |
486 | 513 |
487 m_recentFilesMenu = menu->addMenu(tr("&Recent Files")); | 514 action = new QAction(tr("Export Session as Template..."), this); |
488 m_recentFilesMenu->setTearOffEnabled(true); | 515 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAsTemplate())); |
489 setupRecentFilesMenu(); | 516 // We need to have something in the session for this to be useful: |
490 connect(&m_recentFiles, SIGNAL(recentChanged()), | 517 // canDeleteCurrentLayer captures that |
491 this, SLOT(setupRecentFilesMenu())); | 518 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool))); |
492 | 519 menu->addAction(action); |
493 menu->addSeparator(); | 520 |
521 m_manageTemplatesAction = new QAction(tr("Manage Exported Templates"), this); | |
522 connect(m_manageTemplatesAction, SIGNAL(triggered()), this, SLOT(manageSavedTemplates())); | |
523 menu->addAction(m_manageTemplatesAction); | |
524 | |
525 setupTemplatesMenu(); | |
526 | |
494 action = new QAction(tr("&Preferences..."), this); | 527 action = new QAction(tr("&Preferences..."), this); |
495 action->setStatusTip(tr("Adjust the application preferences")); | 528 action->setStatusTip(tr("Adjust the application preferences")); |
496 connect(action, SIGNAL(triggered()), this, SLOT(preferences())); | 529 connect(action, SIGNAL(triggered()), this, SLOT(preferences())); |
497 menu->addAction(action); | 530 menu->addAction(action); |
498 | 531 |
1615 m_recentFilesMenu->addAction(action); | 1648 m_recentFilesMenu->addAction(action); |
1616 } | 1649 } |
1617 } | 1650 } |
1618 | 1651 |
1619 void | 1652 void |
1653 MainWindow::setupTemplatesMenu() | |
1654 { | |
1655 m_templatesMenu->clear(); | |
1656 | |
1657 QAction *defaultAction = new QAction(tr("Standard Waveform"), this); | |
1658 defaultAction->setObjectName("default"); | |
1659 connect(defaultAction, SIGNAL(triggered()), this, SLOT(applyTemplate())); | |
1660 m_templatesMenu->addAction(defaultAction); | |
1661 | |
1662 m_templatesMenu->addSeparator(); | |
1663 | |
1664 QAction *action = 0; | |
1665 | |
1666 QStringList templates = ResourceFinder().getResourceFiles("templates", "svt"); | |
1667 | |
1668 bool havePersonal = false; | |
1669 | |
1670 // (ordered by name) | |
1671 std::set<QString> byName; | |
1672 foreach (QString t, templates) { | |
1673 if (!t.startsWith(":")) havePersonal = true; | |
1674 byName.insert(QFileInfo(t).baseName()); | |
1675 } | |
1676 | |
1677 foreach (QString t, byName) { | |
1678 if (t.toLower() == "default") continue; | |
1679 action = new QAction(t, this); | |
1680 connect(action, SIGNAL(triggered()), this, SLOT(applyTemplate())); | |
1681 m_templatesMenu->addAction(action); | |
1682 } | |
1683 | |
1684 if (!templates.empty()) m_templatesMenu->addSeparator(); | |
1685 | |
1686 if (!m_templateWatcher) { | |
1687 m_templateWatcher = new QFileSystemWatcher(this); | |
1688 m_templateWatcher->addPath(ResourceFinder().getResourceSaveDir("templates")); | |
1689 connect(m_templateWatcher, SIGNAL(directoryChanged(const QString &)), | |
1690 this, SLOT(setupTemplatesMenu())); | |
1691 } | |
1692 | |
1693 QAction *setDefaultAction = new QAction(tr("Choose Default Template..."), this); | |
1694 setDefaultAction->setObjectName("set_default_template"); | |
1695 connect(setDefaultAction, SIGNAL(triggered()), this, SLOT(preferences())); | |
1696 m_templatesMenu->addSeparator(); | |
1697 m_templatesMenu->addAction(setDefaultAction); | |
1698 | |
1699 m_manageTemplatesAction->setEnabled(havePersonal); | |
1700 } | |
1701 | |
1702 | |
1703 void | |
1620 MainWindow::setupRecentTransformsMenu() | 1704 MainWindow::setupRecentTransformsMenu() |
1621 { | 1705 { |
1622 m_recentTransformsMenu->clear(); | 1706 m_recentTransformsMenu->clear(); |
1623 vector<QString> transforms = m_recentTransforms.getRecent(); | 1707 vector<QString> transforms = m_recentTransforms.getRecent(); |
1624 for (size_t i = 0; i < transforms.size(); ++i) { | 1708 for (size_t i = 0; i < transforms.size(); ++i) { |
2147 MainWindow::importAudio() | 2231 MainWindow::importAudio() |
2148 { | 2232 { |
2149 QString path = getOpenFileName(FileFinder::AudioFile); | 2233 QString path = getOpenFileName(FileFinder::AudioFile); |
2150 | 2234 |
2151 if (path != "") { | 2235 if (path != "") { |
2152 if (openAudio(path, ReplaceMainModel) == FileOpenFailed) { | 2236 if (openAudio(path, ReplaceSession) == FileOpenFailed) { |
2153 emit hideSplash(); | 2237 emit hideSplash(); |
2154 QMessageBox::critical(this, tr("Failed to open file"), | 2238 QMessageBox::critical(this, tr("Failed to open file"), |
2155 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); | 2239 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); |
2156 } | 2240 } |
2157 } | 2241 } |
2671 | 2755 |
2672 QString path = getOpenFileName(FileFinder::AnyFile); | 2756 QString path = getOpenFileName(FileFinder::AnyFile); |
2673 | 2757 |
2674 if (path.isEmpty()) return; | 2758 if (path.isEmpty()) return; |
2675 | 2759 |
2676 FileOpenStatus status = open(path, AskUser); | 2760 FileOpenStatus status = open(path, ReplaceSession); |
2677 | 2761 |
2678 if (status == FileOpenFailed) { | 2762 if (status == FileOpenFailed) { |
2679 emit hideSplash(); | 2763 emit hideSplash(); |
2680 QMessageBox::critical(this, tr("Failed to open file"), | 2764 QMessageBox::critical(this, tr("Failed to open file"), |
2681 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path)); | 2765 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path)); |
2703 | 2787 |
2704 settings.setValue("lastremote", text); | 2788 settings.setValue("lastremote", text); |
2705 | 2789 |
2706 if (text.isEmpty()) return; | 2790 if (text.isEmpty()) return; |
2707 | 2791 |
2708 FileOpenStatus status = open(text); | 2792 FileOpenStatus status = open(text, AskUser); |
2709 | 2793 |
2710 if (status == FileOpenFailed) { | 2794 if (status == FileOpenFailed) { |
2711 emit hideSplash(); | 2795 emit hideSplash(); |
2712 QMessageBox::critical(this, tr("Failed to open location"), | 2796 QMessageBox::critical(this, tr("Failed to open location"), |
2713 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text)); | 2797 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text)); |
2731 } | 2815 } |
2732 | 2816 |
2733 QString path = action->text(); | 2817 QString path = action->text(); |
2734 if (path == "") return; | 2818 if (path == "") return; |
2735 | 2819 |
2736 FileOpenStatus status = open(path); | 2820 FileOpenStatus status = open(path, ReplaceSession); |
2737 | 2821 |
2738 if (status == FileOpenFailed) { | 2822 if (status == FileOpenFailed) { |
2739 emit hideSplash(); | 2823 emit hideSplash(); |
2740 QMessageBox::critical(this, tr("Failed to open location"), | 2824 QMessageBox::critical(this, tr("Failed to open location"), |
2741 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path)); | 2825 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path)); |
2742 } else if (status == FileOpenWrongMode) { | 2826 } else if (status == FileOpenWrongMode) { |
2743 emit hideSplash(); | 2827 emit hideSplash(); |
2744 QMessageBox::critical(this, tr("Failed to open location"), | 2828 QMessageBox::critical(this, tr("Failed to open location"), |
2745 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path)); | 2829 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path)); |
2746 } | 2830 } |
2831 } | |
2832 | |
2833 void | |
2834 MainWindow::applyTemplate() | |
2835 { | |
2836 QObject *s = sender(); | |
2837 QAction *action = qobject_cast<QAction *>(s); | |
2838 | |
2839 if (!action) { | |
2840 std::cerr << "WARNING: MainWindow::applyTemplate: sender is not an action" | |
2841 << std::endl; | |
2842 return; | |
2843 } | |
2844 | |
2845 QString n = action->objectName(); | |
2846 if (n == "") n = action->text(); | |
2847 | |
2848 if (n == "") { | |
2849 std::cerr << "WARNING: MainWindow::applyTemplate: sender has no name" | |
2850 << std::endl; | |
2851 return; | |
2852 } | |
2853 | |
2854 QString mainModelLocation; | |
2855 WaveFileModel *mm = getMainModel(); | |
2856 if (mm) mainModelLocation = mm->getLocation(); | |
2857 if (mainModelLocation != "") { | |
2858 openAudio(mainModelLocation, ReplaceSession, n); | |
2859 } else { | |
2860 openSessionTemplate(n); | |
2861 } | |
2862 } | |
2863 | |
2864 void | |
2865 MainWindow::saveSessionAsTemplate() | |
2866 { | |
2867 QString name = QInputDialog::getText | |
2868 (this, tr("Enter template name"), | |
2869 tr("Please enter a name for the saved template:")); | |
2870 if (name == "") return; | |
2871 | |
2872 name.replace(QRegExp("[^\\w\\s\\.\"'-]"), "_"); | |
2873 | |
2874 ResourceFinder rf; | |
2875 QString dir = rf.getResourceSaveDir("templates"); | |
2876 QString filename = QString("%1/%2.svt").arg(dir).arg(name); | |
2877 if (QFile(filename).exists()) { | |
2878 if (QMessageBox::warning(this, | |
2879 tr("Template file exists"), | |
2880 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name), | |
2881 QMessageBox::Ok | QMessageBox::Cancel, | |
2882 QMessageBox::Cancel) != QMessageBox::Ok) { | |
2883 return; | |
2884 } | |
2885 } | |
2886 | |
2887 saveSessionTemplate(filename); | |
2888 } | |
2889 | |
2890 void | |
2891 MainWindow::manageSavedTemplates() | |
2892 { | |
2893 ResourceFinder rf; | |
2894 QDesktopServices::openUrl("file:" + rf.getResourceSaveDir("templates")); | |
2747 } | 2895 } |
2748 | 2896 |
2749 void | 2897 void |
2750 MainWindow::paneAdded(Pane *pane) | 2898 MainWindow::paneAdded(Pane *pane) |
2751 { | 2899 { |
3912 } | 4060 } |
3913 | 4061 |
3914 void | 4062 void |
3915 MainWindow::preferences() | 4063 MainWindow::preferences() |
3916 { | 4064 { |
4065 bool goToTemplateTab = | |
4066 (sender() && sender()->objectName() == "set_default_template"); | |
4067 | |
3917 if (!m_preferencesDialog.isNull()) { | 4068 if (!m_preferencesDialog.isNull()) { |
3918 m_preferencesDialog->show(); | 4069 m_preferencesDialog->show(); |
3919 m_preferencesDialog->raise(); | 4070 m_preferencesDialog->raise(); |
4071 if (goToTemplateTab) { | |
4072 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab); | |
4073 } | |
3920 return; | 4074 return; |
3921 } | 4075 } |
3922 | 4076 |
3923 m_preferencesDialog = new PreferencesDialog(this); | 4077 m_preferencesDialog = new PreferencesDialog(this); |
3924 | 4078 |
3929 // without resetting its own widgets, so its state will be | 4083 // without resetting its own widgets, so its state will be |
3930 // incorrect when next shown unless we construct it afresh | 4084 // incorrect when next shown unless we construct it afresh |
3931 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose); | 4085 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose); |
3932 | 4086 |
3933 m_preferencesDialog->show(); | 4087 m_preferencesDialog->show(); |
4088 if (goToTemplateTab) { | |
4089 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab); | |
4090 } | |
3934 } | 4091 } |
3935 | 4092 |
3936 void | 4093 void |
3937 MainWindow::mouseEnteredWidget() | 4094 MainWindow::mouseEnteredWidget() |
3938 { | 4095 { |