scide: DocManager - report warnings via the status bar
[supercollider.git] / editors / sc-ide / widgets / main_window.cpp
blob01995e09c86740213e05210b4b0ea613270ba869
1 /*
2 SuperCollider Qt IDE
3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "cmd_line.hpp"
22 #include "doc_list.hpp"
23 #include "documents_dialog.hpp"
24 #include "find_replace_tool.hpp"
25 #include "goto_line_tool.hpp"
26 #include "lookup_dialog.hpp"
27 #include "main_window.hpp"
28 #include "multi_editor.hpp"
29 #include "popup_text_input.hpp"
30 #include "post_window.hpp"
31 #include "session_switch_dialog.hpp"
32 #include "sessions_dialog.hpp"
33 #include "tool_box.hpp"
34 #include "../core/main.hpp"
35 #include "../core/doc_manager.hpp"
36 #include "../core/session_manager.hpp"
37 #include "../core/sc_server.hpp"
38 #include "code_editor/editor.hpp"
39 #include "settings/dialog.hpp"
41 #include <QAction>
42 #include <QApplication>
43 #include <QFileDialog>
44 #include <QFileInfo>
45 #include <QGridLayout>
46 #include <QInputDialog>
47 #include <QMenu>
48 #include <QMenuBar>
49 #include <QMessageBox>
50 #include <QPointer>
51 #include <QShortcut>
52 #include <QStatusBar>
53 #include <QVBoxLayout>
54 #include <QUrl>
56 namespace ScIDE {
58 MainWindow * MainWindow::mInstance = 0;
60 MainWindow::MainWindow(Main * main) :
61 mMain(main),
62 mClockLabel(0),
63 mDocDialog(0)
65 Q_ASSERT(!mInstance);
66 mInstance = this;
68 setAcceptDrops(true);
70 setCorner( Qt::BottomLeftCorner, Qt::LeftDockWidgetArea );
72 // Construct status bar:
74 mLangStatus = new StatusLabel();
75 mLangStatus->setText("Inactive");
76 mServerStatus = new StatusLabel();
77 onServerStatusReply(0, 0, 0, 0, 0, 0);
79 mStatusBar = statusBar();
80 mStatusBar->addPermanentWidget( new QLabel("Interpreter:") );
81 mStatusBar->addPermanentWidget( mLangStatus );
82 mStatusBar->addPermanentWidget( new QLabel("Server:") );
83 mStatusBar->addPermanentWidget( mServerStatus );
85 // Code editor
86 mEditors = new MultiEditor(main);
88 // Tools
90 mCmdLine = new CmdLine("Command Line:");
91 connect(mCmdLine, SIGNAL(invoked(QString, bool)),
92 main->scProcess(), SLOT(evaluateCode(QString, bool)));
94 mFindReplaceTool = new TextFindReplacePanel;
96 mGoToLineTool = new GoToLineTool();
97 connect(mGoToLineTool, SIGNAL(activated(int)), this, SLOT(hideToolBox()));
99 mToolBox = new ToolBox;
100 mToolBox->addWidget(mCmdLine);
101 mToolBox->addWidget(mFindReplaceTool);
102 mToolBox->addWidget(mGoToLineTool);
103 mToolBox->hide();
105 // Docks
106 mDocListDock = new DocumentsDock(main->documentManager(), this);
107 mDocListDock->setObjectName("documents-dock");
108 addDockWidget(Qt::RightDockWidgetArea, mDocListDock);
109 mDocListDock->hide();
112 mPostDock = new PostDock(this);
113 mPostDock->setObjectName("post-dock");
114 addDockWidget(Qt::LeftDockWidgetArea, mPostDock);
116 // Layout
118 QVBoxLayout *center_box = new QVBoxLayout;
119 center_box->setContentsMargins(0,0,0,0);
120 center_box->setSpacing(0);
121 center_box->addWidget(mEditors);
122 center_box->addWidget(mToolBox);
124 QWidget *central = new QWidget;
125 central->setLayout(center_box);
126 setCentralWidget(central);
128 // Session management
129 connect(main->sessionManager(), SIGNAL(saveSessionRequest(Session*)),
130 this, SLOT(saveSession(Session*)));
131 connect(main->sessionManager(), SIGNAL(switchSessionRequest(Session*)),
132 this, SLOT(switchSession(Session*)));
133 connect(main->sessionManager(), SIGNAL(currentSessionNameChanged()),
134 this, SLOT(updateWindowTitle()));
135 // A system for easy evaluation of pre-defined code:
136 connect(&mCodeEvalMapper, SIGNAL(mapped(QString)),
137 this, SIGNAL(evaluateCode(QString)));
138 connect(this, SIGNAL(evaluateCode(QString,bool)),
139 main->scProcess(), SLOT(evaluateCode(QString,bool)));
140 // Interpreter: post output
141 connect(main->scProcess(), SIGNAL( scPost(QString) ),
142 mPostDock->mPostWindow, SLOT( post(QString) ) );
143 // Interpreter: monitor running state
144 connect(main->scProcess(), SIGNAL( stateChanged(QProcess::ProcessState) ),
145 this, SLOT( onInterpreterStateChanged(QProcess::ProcessState) ) );
146 // Interpreter: forward status messages
147 connect(main->scProcess(), SIGNAL(statusMessage(const QString&)),
148 this, SLOT(showStatusMessage(const QString&)));
150 // Document list interaction
151 connect(mDocListDock->list(), SIGNAL(clicked(Document*)),
152 mEditors, SLOT(setCurrent(Document*)));
153 connect(mEditors, SIGNAL(currentDocumentChanged(Document*)),
154 mDocListDock->list(), SLOT(setCurrent(Document*)),
155 Qt::QueuedConnection);
157 // Update actions on document change
158 connect(mEditors, SIGNAL(currentDocumentChanged(Document*)),
159 this, SLOT(onCurrentDocumentChanged(Document*)));
160 // Document management
161 DocumentManager *docMng = main->documentManager();
162 connect(docMng, SIGNAL(changedExternally(Document*)),
163 this, SLOT(onDocumentChangedExternally(Document*)));
164 connect(docMng, SIGNAL(recentsChanged()),
165 this, SLOT(updateRecentDocsMenu()));
167 connect(main, SIGNAL(applySettingsRequest(Settings::Manager*)),
168 this, SLOT(applySettings(Settings::Manager*)));
170 // ToolBox
171 connect(mToolBox->closeButton(), SIGNAL(clicked()), this, SLOT(hideToolBox()));
173 connect(main->scResponder(), SIGNAL(serverRunningChanged(bool,QString,int)), this, SLOT(onServerRunningChanged(bool,QString,int)));
174 connect(main->scServer(), SIGNAL(updateServerStatus(int,int,int,int,float,float)), this, SLOT(onServerStatusReply(int,int,int,int,float,float)));
176 createActions();
177 createMenus();
179 // Must be called after createAtions(), because it accesses an action:
180 onServerRunningChanged(false, "", 0);
182 mServerStatus->addAction( action(ToggleServerRunning) );
183 mServerStatus->setContextMenuPolicy(Qt::ActionsContextMenu);
185 // Initialize recent documents menu
186 updateRecentDocsMenu();
188 QIcon icon;
189 icon.addFile(":/icons/sc-cube-128");
190 icon.addFile(":/icons/sc-cube-48");
191 icon.addFile(":/icons/sc-cube-32");
192 icon.addFile(":/icons/sc-cube-16");
193 QApplication::setWindowIcon(icon);
195 updateWindowTitle();
198 void MainWindow::createActions()
200 Settings::Manager *settings = mMain->settings();
201 settings->beginGroup("IDE/shortcuts");
203 QAction *act;
205 // File
206 mActions[Quit] = act = new QAction(
207 QIcon::fromTheme("application-exit"), tr("&Quit..."), this);
208 act->setShortcut(tr("Ctrl+Q", "Quit application"));
209 act->setStatusTip(tr("Quit SuperCollider IDE"));
210 QObject::connect( act, SIGNAL(triggered()), this, SLOT(onQuit()) );
212 mActions[DocNew] = act = new QAction(
213 QIcon::fromTheme("document-new"), tr("&New"), this);
214 act->setShortcut(tr("Ctrl+N", "New document"));
215 act->setStatusTip(tr("Create a new document"));
216 connect(act, SIGNAL(triggered()), this, SLOT(newDocument()));
218 mActions[DocOpen] = act = new QAction(
219 QIcon::fromTheme("document-open"), tr("&Open..."), this);
220 act->setShortcut(tr("Ctrl+O", "Open document"));
221 act->setStatusTip(tr("Open an existing file"));
222 connect(act, SIGNAL(triggered()), this, SLOT(openDocument()));
224 mActions[DocSave] = act = new QAction(
225 QIcon::fromTheme("document-save"), tr("&Save"), this);
226 act->setShortcut(tr("Ctrl+S", "Save document"));
227 act->setStatusTip(tr("Save the current document"));
228 connect(act, SIGNAL(triggered()), this, SLOT(saveDocument()));
230 mActions[DocSaveAs] = act = new QAction(
231 QIcon::fromTheme("document-save-as"), tr("Save &As..."), this);
232 act->setShortcut(tr("Ctrl+Shift+S", "Save &As..."));
233 act->setStatusTip(tr("Save the current document into a different file"));
234 connect(act, SIGNAL(triggered()), this, SLOT(saveDocumentAs()));
236 mActions[DocSaveAll] = act = new QAction(
237 QIcon::fromTheme("document-save"), tr("Save All..."), this);
238 act->setShortcut(tr("Ctrl+Alt+S", "Save all documents"));
239 act->setStatusTip(tr("Save all open documents"));
240 connect(act, SIGNAL(triggered()), this, SLOT(saveAllDocuments()));
242 mActions[DocClose] = act = new QAction(
243 QIcon::fromTheme("window-close"), tr("&Close"), this);
244 act->setShortcut(tr("Ctrl+W", "Close document"));
245 act->setStatusTip(tr("Close the current document"));
246 connect(act, SIGNAL(triggered()), this, SLOT(closeDocument()));
248 mActions[DocCloseAll] = act = new QAction(
249 QIcon::fromTheme("window-close"), tr("Close All..."), this);
250 act->setShortcut(tr("Ctrl+Shift+W", "Close all documents"));
251 act->setStatusTip(tr("Close all documents"));
252 connect(act, SIGNAL(triggered()), this, SLOT(closeAllDocuments()));
254 mActions[DocReload] = act = new QAction(
255 QIcon::fromTheme("view-refresh"), tr("&Reload"), this);
256 act->setShortcut(tr("F5", "Reload document"));
257 act->setStatusTip(tr("Reload the current document"));
258 connect(act, SIGNAL(triggered()), this, SLOT(reloadDocument()));
260 mActions[ClearRecentDocs] = act = new QAction(tr("Clear", "Clear recent documents"), this);
261 connect(act, SIGNAL(triggered()),
262 Main::instance()->documentManager(), SLOT(clearRecents()));
264 // Sessions
265 mActions[NewSession] = act = new QAction(
266 QIcon::fromTheme("document-new"), tr("&New Session"), this);
267 act->setStatusTip(tr("Open a new session"));
268 connect(act, SIGNAL(triggered()), this, SLOT(newSession()));
270 mActions[SaveSessionAs] = act = new QAction(
271 QIcon::fromTheme("document-save-as"), tr("Save Session &As..."), this);
272 act->setStatusTip(tr("Save the current session with a different name"));
273 connect(act, SIGNAL(triggered()), this, SLOT(saveCurrentSessionAs()));
275 mActions[ManageSessions] = act = new QAction(
276 tr("&Manage Sessions..."), this);
277 connect(act, SIGNAL(triggered()), this, SLOT(openSessionsDialog()));
279 mActions[OpenSessionSwitchDialog] = act = new QAction(
280 tr("&Switch Session..."), this);
281 connect(act, SIGNAL(triggered()), this, SLOT(showSwitchSessionDialog()));
282 act->setShortcut(tr("Ctrl+Shift+Q", "Switch Session"));
284 // Edit
285 mActions[Find] = act = new QAction(
286 QIcon::fromTheme("edit-find"), tr("&Find..."), this);
287 act->setShortcut(tr("Ctrl+F", "Find"));
288 act->setStatusTip(tr("Find text in document"));
289 connect(act, SIGNAL(triggered()), this, SLOT(showFindTool()));
291 mActions[Replace] = act = new QAction(
292 QIcon::fromTheme("edit-replace"), tr("&Replace..."), this);
293 act->setShortcut(tr("Ctrl+R", "Replace"));
294 act->setStatusTip(tr("Find and replace text in document"));
295 connect(act, SIGNAL(triggered()), this, SLOT(showReplaceTool()));
297 // View
298 mActions[ShowCmdLine] = act = new QAction(tr("&Command Line"), this);
299 act->setStatusTip(tr("Command line for quick code evaluation"));
300 act->setShortcut(tr("Ctrl+E", "Show command line"));
301 connect(act, SIGNAL(triggered()), this, SLOT(showCmdLine()));
303 mActions[ShowGoToLineTool] = act = new QAction(tr("&Go To Line"), this);
304 act->setStatusTip(tr("Tool to jump to a line by number"));
305 act->setShortcut(tr("Ctrl+G", "Show go-to-line tool"));
306 connect(act, SIGNAL(triggered()), this, SLOT(showGoToLineTool()));
308 mActions[CloseToolBox] = act = new QAction(
309 QIcon::fromTheme("window-close"), tr("&Close Tool Panel"), this);
310 act->setStatusTip(tr("Close any open tool panel"));
311 act->setShortcut(tr("Esc", "Close tool box"));
312 connect(act, SIGNAL(triggered()), this, SLOT(hideToolBox()));
314 mActions[ShowFullScreen] = act = new QAction(tr("&Full Screen"), this);
315 act->setCheckable(false);
316 act->setShortcut(tr("Ctrl+Shift+F", "Show ScIDE in Full Screen"));
317 connect(act, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
319 mActions[ClearPostWindow] = act = new QAction(
320 QIcon::fromTheme("window-clearpostwindow"), tr("Clear Post Window"), this);
321 act->setStatusTip(tr("Clear Post Window"));
322 act->setShortcut(tr("Ctrl+Shift+C", "Clear Post Window"));
323 connect(act, SIGNAL(triggered()), mPostDock->mPostWindow, SLOT(clear()));
325 mActions[LookupReferences] = act = new QAction(
326 QIcon::fromTheme("window-lookupreferences"), tr("Lookup References"), this);
327 act->setShortcut(tr("Ctrl+Shift+U", "Lookup References"));
328 connect(act, SIGNAL(triggered()), this, SLOT(lookupReferences()));
330 mActions[LookupDefinition] = act = new QAction(
331 QIcon::fromTheme("window-lookupdefinition"), tr("Lookup Definition"), this);
332 act->setShortcut(tr("Ctrl+Shift+I", "Lookup Definition"));
333 connect(act, SIGNAL(triggered()), this, SLOT(lookupDefinition()));
335 mActions[LookupDocumentation] = act = new QAction(
336 QIcon::fromTheme("window-lookupDocumentation"), tr("Lookup Documentation"), this);
337 act->setShortcut(tr("Ctrl+Shift+D", "Lookup Documentation"));
338 connect(act, SIGNAL(triggered()), this, SLOT(lookupDocumentation()));
340 // Language
341 mActions[OpenDefinition] = act = new QAction(tr("Open Class/Method Definition"), this);
342 act->setShortcut(tr("Ctrl+I", "Open definition of selected class or method"));
343 connect(act, SIGNAL(triggered(bool)), this, SLOT(openDefinition()));
345 mActions[FindReferences] = act = new QAction(tr("Find References"), this);
346 act->setShortcut(tr("Ctrl+U", "Find References"));
347 connect(act, SIGNAL(triggered(bool)), this, SLOT(findReferences()));
349 // Settings
350 mActions[ShowSettings] = act = new QAction(tr("&Configure IDE..."), this);
351 act->setStatusTip(tr("Show configuration dialog"));
352 connect(act, SIGNAL(triggered()), this, SLOT(showSettings()));
355 // Help
356 mActions[Help] = act = new QAction(
357 QIcon::fromTheme("system-help"), tr("Open Help Browser"), this);
358 act->setStatusTip(tr("Open help."));
359 connect(act, SIGNAL(triggered()), this, SLOT(openHelp()));
361 mActions[HelpForSelection] = act = new QAction(
362 QIcon::fromTheme("system-help"), tr("&Help for Selection"), this);
363 act->setShortcut(tr("Ctrl+D", "Help for selection"));
364 act->setStatusTip(tr("Find help for selected text"));
365 connect(act, SIGNAL(triggered()), this, SLOT(openDocumentation()));
367 // Server
368 mActions[ToggleServerRunning] = act = new QAction(this);
369 connect(act, SIGNAL(triggered()), this, SLOT(toggleServerRunning()));
371 settings->endGroup(); // IDE/shortcuts;
373 // Add actions to settings
374 for (int i = 0; i < ActionCount; ++i)
375 settings->addAction( mActions[i] );
378 void MainWindow::createMenus()
380 QMenu *menu;
381 QMenu *submenu;
383 menu = new QMenu(tr("&File"), this);
384 menu->addAction( mActions[DocNew] );
385 menu->addAction( mActions[DocOpen] );
386 mRecentDocsMenu = menu->addMenu(tr("Open Recent", "Open a recent document"));
387 connect(mRecentDocsMenu, SIGNAL(triggered(QAction*)),
388 this, SLOT(onRecentDocAction(QAction*)));
389 menu->addAction( mActions[DocSave] );
390 menu->addAction( mActions[DocSaveAs] );
391 menu->addAction( mActions[DocSaveAll] );
392 menu->addSeparator();
393 menu->addAction( mActions[DocReload] );
394 menu->addSeparator();
395 menu->addAction( mActions[DocClose] );
396 menu->addAction( mActions[DocCloseAll] );
397 menu->addSeparator();
398 menu->addAction( mActions[Quit] );
400 menuBar()->addMenu(menu);
402 menu = new QMenu(tr("&Session"), this);
403 menu->addAction( mActions[NewSession] );
404 menu->addAction( mActions[SaveSessionAs] );
405 submenu = menu->addMenu(tr("&Open Session"));
406 connect(submenu, SIGNAL(triggered(QAction*)),
407 this, SLOT(onOpenSessionAction(QAction*)));
408 mSessionsMenu = submenu;
409 updateSessionsMenu();
410 menu->addSeparator();
411 menu->addAction( mActions[ManageSessions] );
412 menu->addAction( mActions[OpenSessionSwitchDialog] );
414 menuBar()->addMenu(menu);
416 menu = new QMenu(tr("&Edit"), this);
417 menu->addAction( mEditors->action(MultiEditor::Undo) );
418 menu->addAction( mEditors->action(MultiEditor::Redo) );
419 menu->addSeparator();
420 menu->addAction( mEditors->action(MultiEditor::Cut) );
421 menu->addAction( mEditors->action(MultiEditor::Copy) );
422 menu->addAction( mEditors->action(MultiEditor::Paste) );
423 menu->addSeparator();
424 menu->addAction( mActions[Find] );
425 menu->addAction( mActions[Replace] );
426 menu->addSeparator();
427 menu->addAction( mEditors->action(MultiEditor::IndentLineOrRegion) );
428 menu->addAction( mEditors->action(MultiEditor::ToggleComment) );
429 menu->addAction( mEditors->action(MultiEditor::ToggleOverwriteMode) );
430 menu->addAction( mEditors->action(MultiEditor::SelectRegion) );
431 menu->addSeparator();
432 menu->addAction( mActions[OpenDefinition] );
433 menu->addAction( mActions[FindReferences] );
435 menuBar()->addMenu(menu);
437 menu = new QMenu(tr("&View"), this);
438 submenu = new QMenu(tr("&Docks"), this);
439 submenu->addAction( mPostDock->toggleViewAction() );
440 submenu->addAction( mDocListDock->toggleViewAction() );
441 menu->addMenu(submenu);
442 menu->addSeparator();
443 submenu = menu->addMenu(tr("&Tool Panels"));
444 submenu->addAction( mActions[Find] );
445 submenu->addAction( mActions[Replace] );
446 submenu->addAction( mActions[ShowCmdLine] );
447 submenu->addAction( mActions[ShowGoToLineTool] );
448 submenu->addSeparator();
449 submenu->addAction( mActions[CloseToolBox] );
450 menu->addSeparator();
451 menu->addAction( mEditors->action(MultiEditor::EnlargeFont) );
452 menu->addAction( mEditors->action(MultiEditor::ShrinkFont) );
453 menu->addAction( mEditors->action(MultiEditor::ResetFontSize) );
454 menu->addSeparator();
455 menu->addAction( mEditors->action(MultiEditor::ShowWhitespace) );
456 menu->addSeparator();
457 menu->addAction( mEditors->action(MultiEditor::NextDocument) );
458 menu->addAction( mEditors->action(MultiEditor::PreviousDocument) );
459 menu->addSeparator();
460 menu->addAction( mEditors->action(MultiEditor::SplitHorizontally) );
461 menu->addAction( mEditors->action(MultiEditor::SplitVertically) );
462 menu->addAction( mEditors->action(MultiEditor::RemoveCurrentSplit) );
463 menu->addAction( mEditors->action(MultiEditor::RemoveAllSplits) );
464 menu->addSeparator();
465 menu->addAction( mActions[ClearPostWindow] );
466 menu->addSeparator();
467 menu->addAction( mActions[ShowFullScreen] );
468 menu->addSeparator();
469 menu->addAction( mActions[LookupDocumentation] );
470 menu->addAction( mActions[LookupDefinition] );
471 menu->addAction( mActions[LookupReferences] );
473 menuBar()->addMenu(menu);
475 menu = new QMenu(tr("&Language"), this);
476 menu->addAction( mMain->scProcess()->action(SCProcess::StartSCLang) );
477 menu->addAction( mMain->scProcess()->action(SCProcess::StopSCLang) );
478 menu->addAction( mMain->scProcess()->action(SCProcess::RestartSCLang) );
479 menu->addAction( mMain->scProcess()->action(SCProcess::RecompileClassLibrary) );
480 menu->addSeparator();
481 menu->addAction( mEditors->action(MultiEditor::EvaluateCurrentDocument) );
482 menu->addAction( mEditors->action(MultiEditor::EvaluateRegion) );
483 menu->addAction( mEditors->action(MultiEditor::EvaluateLine) );
484 menu->addSeparator();
485 menu->addAction( mMain->scProcess()->action(ScIDE::SCProcess::RunMain) );
486 menu->addAction( mMain->scProcess()->action(ScIDE::SCProcess::StopMain) );
488 menuBar()->addMenu(menu);
490 menu = new QMenu(tr("&Settings"), this);
491 menu->addAction( mActions[ShowSettings] );
493 menuBar()->addMenu(menu);
495 menu = new QMenu(tr("&Help"), this);
496 menu->addAction( mActions[Help] );
497 menu->addAction( mActions[HelpForSelection] );
499 menuBar()->addMenu(menu);
502 void MainWindow::saveWindowState()
504 Settings::Manager *settings = Main::settings();
505 settings->beginGroup("IDE/mainWindow");
506 settings->setValue("geometry", this->saveGeometry().toBase64());
507 settings->setValue("state", this->saveState().toBase64());
508 settings->endGroup();
511 void MainWindow::restoreWindowState()
513 Settings::Manager *settings = Main::settings();
514 settings->beginGroup("IDE/mainWindow");
516 QByteArray geom = QByteArray::fromBase64( settings->value("geometry").value<QByteArray>() );
517 if (!geom.isEmpty())
518 restoreGeometry(geom);
519 else
520 setWindowState( windowState() & ~Qt::WindowFullScreen | Qt::WindowMaximized );
522 QByteArray state = QByteArray::fromBase64( settings->value("state").value<QByteArray>() );
523 if (!state.isEmpty())
524 restoreState(state);
526 settings->endGroup();
529 void MainWindow::newSession()
531 if (promptSaveDocs())
532 mMain->sessionManager()->newSession();
535 void MainWindow::saveCurrentSessionAs()
537 QString name = QInputDialog::getText( this,
538 "Save Current Session",
539 "Enter a name for the session:" );
541 if (name.isEmpty()) return;
543 mMain->sessionManager()->saveSessionAs(name);
545 updateSessionsMenu();
548 void MainWindow::onOpenSessionAction( QAction * action )
550 openSession(action->text());
553 void MainWindow::switchSession( Session *session )
555 if (session) {
556 session->beginGroup("mainWindow");
557 QByteArray geom = QByteArray::fromBase64( session->value("geometry").value<QByteArray>() );
558 QByteArray state = QByteArray::fromBase64( session->value("state").value<QByteArray>() );
559 session->endGroup();
561 // Workaround for Qt bug 4397:
562 setWindowState(Qt::WindowNoState);
564 if (!geom.isEmpty())
565 restoreGeometry(geom);
566 if (!state.isEmpty())
567 restoreState(state);
569 updateClockWidget(isFullScreen());
572 mEditors->switchSession(session);
574 updateWindowTitle();
577 void MainWindow::saveSession( Session *session )
579 session->beginGroup("mainWindow");
580 session->setValue("geometry", this->saveGeometry().toBase64());
581 session->setValue("state", this->saveState().toBase64());
582 session->endGroup();
584 mEditors->saveSession(session);
587 void MainWindow::openSessionsDialog()
589 QPointer<MainWindow> mainwin(this);
590 SessionsDialog dialog(mMain->sessionManager(), this);
591 dialog.exec();
592 if (mainwin)
593 mainwin->updateSessionsMenu();
596 QAction *MainWindow::action( ActionRole role )
598 Q_ASSERT( role < ActionCount );
599 return mActions[role];
602 bool MainWindow::quit()
604 if (!promptSaveDocs())
605 return false;
607 saveWindowState();
609 mMain->quit();
611 return true;
614 void MainWindow::onQuit()
616 quit();
619 void MainWindow::onCurrentDocumentChanged( Document * doc )
621 updateWindowTitle();
623 mActions[DocSave]->setEnabled(doc);
624 mActions[DocSaveAs]->setEnabled(doc);
625 mActions[DocClose]->setEnabled(doc);
627 CodeEditor *editor = mEditors->currentEditor();
628 mFindReplaceTool->setEditor( editor );
629 mGoToLineTool->setEditor( editor );
632 void MainWindow::onDocumentChangedExternally( Document *doc )
634 if (mDocDialog)
635 return;
637 mDocDialog = new DocumentsDialog(DocumentsDialog::ExternalChange, this);
638 mDocDialog->addDocument(doc);
639 connect(mDocDialog, SIGNAL(finished(int)), this, SLOT(onDocDialogFinished()));
640 mDocDialog->open();
643 void MainWindow::onDocDialogFinished()
645 mDocDialog->deleteLater();
646 mDocDialog = 0;
649 void MainWindow::updateRecentDocsMenu()
651 mRecentDocsMenu->clear();
653 const QStringList &recent = mMain->documentManager()->recents();
655 foreach( const QString & path, recent )
656 mRecentDocsMenu->addAction(path);
658 if (!recent.isEmpty()) {
659 mRecentDocsMenu->addSeparator();
660 mRecentDocsMenu->addAction(mActions[ClearRecentDocs]);
664 void MainWindow::onRecentDocAction( QAction *action )
666 mMain->documentManager()->open(action->text());
669 void MainWindow::onInterpreterStateChanged( QProcess::ProcessState state )
671 QString text;
672 QColor color;
674 switch(state) {
675 case QProcess::NotRunning:
676 text = "Inactive";
677 color = Qt::white;
678 break;
679 case QProcess::Starting:
680 text = "Booting";
681 color = QColor(255,255,0);
682 break;
683 case QProcess::Running:
684 text = "Active";
685 color = Qt::green;
686 break;
689 mLangStatus->setText(text);
690 mLangStatus->setTextColor(color);
694 void MainWindow::onServerStatusReply(int ugens, int synths, int groups, int synthDefs, float avgCPU, float peakCPU)
696 QString statusString =
697 QString("%1% %2% %3u %4s %5g %6d")
698 .arg(avgCPU, 5, 'f', 2)
699 .arg(peakCPU, 5, 'f', 2)
700 .arg(ugens, 4)
701 .arg(synths, 4)
702 .arg(groups, 4)
703 .arg(synthDefs, 4);
705 mServerStatus->setText(statusString);
708 void MainWindow::onServerRunningChanged(bool running, const QString &, int)
710 QAction *serverStatusAction = mActions[ToggleServerRunning];
712 mServerStatus->setTextColor( running ? Qt::green : Qt::white);
713 if (!running) {
714 onServerStatusReply(0, 0, 0, 0, 0, 0);
716 serverStatusAction->setText( tr("&Boot Server") );
717 serverStatusAction->setStatusTip(tr("Boot sound synthesis server"));
718 } else {
719 serverStatusAction->setText( tr("&Quit Server") );
720 serverStatusAction->setStatusTip(tr("Quit sound synthesis server"));
724 void MainWindow::closeEvent(QCloseEvent *event)
726 if(!quit()) event->ignore();
729 bool MainWindow::close( Document *doc )
731 if (doc->textDocument()->isModified())
733 QMessageBox::StandardButton ret;
734 ret = QMessageBox::warning(
735 mInstance,
736 tr("SuperCollider IDE"),
737 tr("There are unsaved changes in document '%1'.\n\n"
738 "Do you want to save it?").arg(doc->title()),
739 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
740 QMessageBox::Save // the default
743 switch (ret) {
744 case QMessageBox::Cancel:
745 return false;
746 case QMessageBox::Save:
747 if (!MainWindow::save(doc))
748 return false;
749 break;
750 default:;
754 Main::instance()->documentManager()->close(doc);
755 return true;
758 bool MainWindow::reload( Document *doc )
760 if (doc->filePath().isEmpty())
761 return false;
763 if (doc->textDocument()->isModified())
765 QMessageBox::StandardButton ret;
766 ret = QMessageBox::warning(
767 mInstance,
768 tr("SuperCollider IDE"),
769 tr("There are unsaved changes in document '%1'.\n\n"
770 "Do you want to reload it?").arg(doc->title()),
771 QMessageBox::Yes | QMessageBox::No,
772 QMessageBox::No // the default
774 if (ret == QMessageBox::No)
775 return false;
778 return Main::instance()->documentManager()->reload(doc);
781 bool MainWindow::save( Document *doc, bool forceChoose )
783 DocumentManager *mng = Main::instance()->documentManager();
784 if (forceChoose || doc->filePath().isEmpty()) {
785 QFileDialog dialog(mInstance);
786 dialog.setAcceptMode( QFileDialog::AcceptSave );
788 QStringList filters = (QStringList()
789 << "SuperCollider Document(*.scd)"
790 << "SuperCollider Class file(*.sc)"
791 << "SCDoc(*.schelp)"
792 << "All files(*)");
794 dialog.setNameFilters(filters);
795 dialog.setDefaultSuffix("scd");
797 if (dialog.exec() == QDialog::Accepted)
798 return mng->saveAs(doc, dialog.selectedFiles()[0]);
799 else
800 return false;
801 } else
802 return mng->save(doc);
805 void MainWindow::newDocument()
807 mMain->documentManager()->create();
810 void MainWindow::openDocument()
812 QFileDialog dialog (this, Qt::Dialog);
813 dialog.setModal(true);
814 dialog.setWindowModality(Qt::ApplicationModal);
816 dialog.setFileMode( QFileDialog::ExistingFiles );
818 CodeEditor * currentEditor = mEditors->currentEditor();
819 if (currentEditor) {
820 Document * currentDocument = currentEditor->document();
821 QFileInfo filePath (currentDocument->filePath());
822 dialog.setDirectory(filePath.dir());
825 QStringList filters;
826 filters
827 << "All files(*)"
828 << "SuperCollider(*.scd *.sc)"
829 << "SCDoc(*.schelp)";
830 dialog.setNameFilters(filters);
832 if (dialog.exec())
834 QStringList filenames = dialog.selectedFiles();
835 foreach(QString filename, filenames)
836 mMain->documentManager()->open(filename);
840 void MainWindow::saveDocument()
842 CodeEditor *editor = mEditors->currentEditor();
843 if(!editor) return;
845 Document *doc = editor->document();
846 Q_ASSERT(doc);
848 MainWindow::save(doc);
851 void MainWindow::saveDocumentAs()
853 CodeEditor *editor = mEditors->currentEditor();
854 if(!editor) return;
856 Document *doc = editor->document();
857 Q_ASSERT(doc);
859 MainWindow::save(doc, true);
862 void MainWindow::saveAllDocuments()
864 QList<Document*> docs = mMain->documentManager()->documents();
865 foreach (Document *doc, docs)
866 if (!MainWindow::save(doc))
867 return;
870 void MainWindow::reloadDocument()
872 CodeEditor *editor = mEditors->currentEditor();
873 if(!editor) return;
875 Q_ASSERT(editor->document());
876 MainWindow::reload(editor->document());
879 void MainWindow::closeDocument()
881 CodeEditor *editor = mEditors->currentEditor();
882 if(!editor) return;
884 Q_ASSERT(editor->document());
885 MainWindow::close( editor->document() );
888 void MainWindow::closeAllDocuments()
890 if (promptSaveDocs()) {
891 QList<Document*> docs = mMain->documentManager()->documents();
892 foreach (Document *doc, docs)
893 mMain->documentManager()->close(doc);
897 bool MainWindow::promptSaveDocs()
899 QList<Document*> docs = mMain->documentManager()->documents();
900 QList<Document*> unsavedDocs;
901 foreach(Document* doc, docs)
902 if(doc->textDocument()->isModified())
903 unsavedDocs.append(doc);
905 if (unsavedDocs.count())
907 DocumentsDialog dialog(unsavedDocs, DocumentsDialog::Quit, this);
909 if (!dialog.exec())
910 return false;
913 return true;
916 void MainWindow::updateWindowTitle()
918 Session *session = mMain->sessionManager()->currentSession();
919 CodeEditor *editor = mEditors->currentEditor();
920 Document *doc = editor ? editor->document() : 0;
922 QString title;
924 if (session) {
925 title.append(session->name());
926 if (doc) title.append(": ");
929 if (doc) {
930 if (!doc->filePath().isEmpty()) {
931 QFileInfo info = QFileInfo(doc->filePath());
932 QString pathString = info.dir().path();
934 QString homePath = QDir::homePath();
935 if (pathString.startsWith(homePath))
936 pathString.replace(0, homePath.size(), QString("~"));
938 QString titleString = QString("%1 (%2)").arg(info.fileName(), pathString);
940 title.append( titleString );
941 } else
942 title.append( "Untitled" );
945 if (!title.isEmpty())
946 title.append(" - ");
948 title.append("SuperCollider IDE");
950 setWindowTitle(title);
953 void MainWindow::toggleFullScreen()
955 if (isFullScreen()) {
956 setWindowState(windowState() & ~Qt::WindowFullScreen);
958 updateClockWidget(false);
959 } else {
960 setWindowState(windowState() | Qt::WindowFullScreen);
962 updateClockWidget(true);
966 void MainWindow::updateClockWidget(bool isFullScreen)
968 if (!isFullScreen) {
969 if (mClockLabel) {
970 delete mClockLabel;
971 mClockLabel = NULL;
973 } else {
974 if (mClockLabel == NULL) {
975 mClockLabel = new StatusClockLabel(this);
976 statusBar()->insertWidget(0, mClockLabel);
981 void MainWindow::openSession(const QString &sessionName)
983 if (promptSaveDocs())
984 mMain->sessionManager()->openSession( sessionName );
987 void MainWindow::openDefinition()
989 QWidget * focussedWidget = QApplication::focusWidget();
991 int indexOfMethod = focussedWidget->metaObject()->indexOfMethod("openDefinition()");
992 if (indexOfMethod != -1)
993 QMetaObject::invokeMethod( focussedWidget, "openDefinition", Qt::DirectConnection );
996 void MainWindow::lookupDefinition()
998 LookupDialog dialog(mEditors);
999 dialog.exec();
1002 void MainWindow::lookupDocumentation()
1004 PopupTextInput * dialog = new PopupTextInput(tr("Lookup Documentation For"), this);
1006 bool success = dialog->exec();
1007 if (success)
1008 Main::openDocumentation(dialog->textValue());
1010 delete dialog;
1013 void MainWindow::findReferences()
1015 QWidget * focussedWidget = QApplication::focusWidget();
1017 int indexOfMethod = focussedWidget->metaObject()->indexOfMethod("findReferences()");
1018 if (indexOfMethod != -1)
1019 QMetaObject::invokeMethod( focussedWidget, "findReferences", Qt::DirectConnection );
1022 void MainWindow::lookupReferences()
1024 ReferencesDialog dialog(parentWidget());
1025 dialog.exec();
1029 void MainWindow::showStatusMessage( QString const & string )
1031 mStatusBar->showMessage(string, 3000);
1034 void MainWindow::applySettings( Settings::Manager * settings )
1036 mEditors->applySettings(settings);
1037 mPostDock->mPostWindow->applySettings(settings);
1038 mCmdLine->applySettings(settings);
1042 void MainWindow::updateSessionsMenu()
1044 mSessionsMenu->clear();
1045 QStringList sessions = mMain->sessionManager()->availableSessions();
1046 foreach (const QString & session, sessions)
1047 mSessionsMenu->addAction( session );
1050 void MainWindow::showSwitchSessionDialog()
1052 SessionSwitchDialog * dialog = new SessionSwitchDialog(this);
1053 int result = dialog->exec();
1055 if (result == QDialog::Accepted)
1056 openSession(dialog->activeElement());
1058 delete dialog;
1061 void MainWindow::showCmdLine()
1063 mToolBox->setCurrentWidget( mCmdLine );
1064 mToolBox->show();
1066 mCmdLine->setFocus(Qt::OtherFocusReason);
1069 void MainWindow::showGoToLineTool()
1071 CodeEditor *editor = mEditors->currentEditor();
1072 mGoToLineTool->setValue( editor ? editor->textCursor().blockNumber() + 1 : 0 );
1074 mToolBox->setCurrentWidget( mGoToLineTool );
1075 mToolBox->show();
1077 mGoToLineTool->setFocus();
1080 void MainWindow::showFindTool()
1082 mFindReplaceTool->setMode( TextFindReplacePanel::Find );
1083 mFindReplaceTool->initiate();
1085 mToolBox->setCurrentWidget( mFindReplaceTool );
1086 mToolBox->show();
1088 mFindReplaceTool->setFocus(Qt::OtherFocusReason);
1091 void MainWindow::showReplaceTool()
1093 mFindReplaceTool->setMode( TextFindReplacePanel::Replace );
1094 mFindReplaceTool->initiate();
1096 mToolBox->setCurrentWidget( mFindReplaceTool );
1097 mToolBox->show();
1099 mFindReplaceTool->setFocus(Qt::OtherFocusReason);
1102 void MainWindow::hideToolBox()
1104 mToolBox->hide();
1105 CodeEditor *editor = mEditors->currentEditor();
1106 if (editor) {
1107 // This slot is mapped to Escape, so also clear highlighting
1108 // whenever invoked:
1109 editor->clearSearchHighlighting();
1110 if (!editor->hasFocus())
1111 editor->setFocus(Qt::OtherFocusReason);
1115 void MainWindow::showSettings()
1117 Settings::Dialog dialog(mMain->settings());
1118 dialog.resize(700,400);
1119 int result = dialog.exec();
1120 if( result == QDialog::Accepted )
1121 mMain->applySettings();
1124 void MainWindow::openDocumentation()
1126 QWidget * focussedWidget = QApplication::focusWidget();
1128 bool documentationOpened = false;
1130 int indexOfMethod = focussedWidget->metaObject()->indexOfMethod("openDocumentation()");
1131 if (indexOfMethod != -1)
1132 QMetaObject::invokeMethod( focussedWidget, "openDocumentation", Qt::DirectConnection,
1133 Q_RETURN_ARG(bool, documentationOpened) );
1135 if (!documentationOpened)
1136 openHelp();
1139 void MainWindow::openHelp()
1141 QString code = QString("Help.gui");
1142 Main::scProcess()->evaluateCode(code, true);
1145 void MainWindow::toggleServerRunning()
1147 ScServer *scServer = Main::scServer();
1149 if (scServer->isRunning())
1150 scServer->quit();
1151 else
1152 scServer->boot();
1155 void MainWindow::dragEnterEvent( QDragEnterEvent * event )
1157 if (event->mimeData()->hasUrls()) {
1158 foreach (QUrl url, event->mimeData()->urls()) {
1159 if (url.scheme() == QString("file")) { // LATER: use isLocalFile
1160 // LATER: check mime type ?
1161 event->acceptProposedAction();
1162 return;
1168 void MainWindow::dropEvent( QDropEvent * event )
1170 const QMimeData * data = event->mimeData();
1171 if (data->hasUrls()) {
1172 foreach (QUrl url, data->urls()) {
1173 if (url.scheme() == QString("file")) // LATER: use isLocalFile
1174 Main::documentManager()->open(url.toLocalFile());
1179 //////////////////////////// StatusLabel /////////////////////////////////
1181 StatusLabel::StatusLabel(QWidget *parent) : QLabel(parent)
1183 setAutoFillBackground(true);
1184 setMargin(3);
1185 setAlignment(Qt::AlignCenter);
1186 setBackground(Qt::black);
1187 setTextColor(Qt::white);
1189 QFont font("Monospace");
1190 font.setStyleHint(QFont::Monospace);
1191 font.setBold(true);
1192 setFont(font);
1195 void StatusLabel::setBackground(const QBrush & brush)
1197 QPalette plt(palette());
1198 plt.setBrush(QPalette::Window, brush);
1199 setPalette(plt);
1202 void StatusLabel::setTextColor(const QColor & color)
1204 QPalette plt(palette());
1205 plt.setColor(QPalette::WindowText, color);
1206 setPalette(plt);
1209 //////////////////////////// StatusClockLabel ////////////////////////////
1211 StatusClockLabel::StatusClockLabel(QWidget * parent):
1212 StatusLabel(parent)
1214 setTextColor(Qt::green);
1215 mTimerId = startTimer(1000);
1216 updateTime();
1219 StatusClockLabel::~StatusClockLabel()
1221 killTimer(mTimerId);
1224 void StatusClockLabel::timerEvent(QTimerEvent *e)
1226 if (e->timerId() == mTimerId)
1227 updateTime();
1230 void StatusClockLabel::updateTime()
1232 setText(QTime::currentTime().toString());
1235 } // namespace ScIDE