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"
42 #include <QApplication>
43 #include <QFileDialog>
45 #include <QGridLayout>
46 #include <QInputDialog>
49 #include <QMessageBox>
53 #include <QVBoxLayout>
57 MainWindow
* MainWindow::mInstance
= 0;
59 MainWindow::MainWindow(Main
* main
) :
67 setCorner( Qt::BottomLeftCorner
, Qt::LeftDockWidgetArea
);
69 // Construct status bar:
71 mLangStatus
= new StatusLabel();
72 mLangStatus
->setText("Inactive");
73 mServerStatus
= new StatusLabel();
74 onServerStatusReply(0, 0, 0, 0, 0, 0);
76 mStatusBar
= statusBar();
77 mStatusBar
->addPermanentWidget( new QLabel("Interpreter:") );
78 mStatusBar
->addPermanentWidget( mLangStatus
);
79 mStatusBar
->addPermanentWidget( new QLabel("Server:") );
80 mStatusBar
->addPermanentWidget( mServerStatus
);
83 mEditors
= new MultiEditor(main
);
87 mCmdLine
= new CmdLine("Command Line:");
88 connect(mCmdLine
, SIGNAL(invoked(QString
, bool)),
89 main
->scProcess(), SLOT(evaluateCode(QString
, bool)));
91 mFindReplaceTool
= new TextFindReplacePanel
;
93 mGoToLineTool
= new GoToLineTool();
94 connect(mGoToLineTool
, SIGNAL(activated(int)), this, SLOT(hideToolBox()));
96 mToolBox
= new ToolBox
;
97 mToolBox
->addWidget(mCmdLine
);
98 mToolBox
->addWidget(mFindReplaceTool
);
99 mToolBox
->addWidget(mGoToLineTool
);
103 mDocListDock
= new DocumentsDock(main
->documentManager(), this);
104 mDocListDock
->setObjectName("documents-dock");
105 addDockWidget(Qt::RightDockWidgetArea
, mDocListDock
);
106 mDocListDock
->hide();
109 mPostDock
= new PostDock(this);
110 mPostDock
->setObjectName("post-dock");
111 addDockWidget(Qt::LeftDockWidgetArea
, mPostDock
);
115 QVBoxLayout
*center_box
= new QVBoxLayout
;
116 center_box
->setContentsMargins(0,0,0,0);
117 center_box
->setSpacing(0);
118 center_box
->addWidget(mEditors
);
119 center_box
->addWidget(mToolBox
);
121 QWidget
*central
= new QWidget
;
122 central
->setLayout(center_box
);
123 setCentralWidget(central
);
125 // Session management
126 connect(main
->sessionManager(), SIGNAL(saveSessionRequest(Session
*)),
127 this, SLOT(saveSession(Session
*)));
128 connect(main
->sessionManager(), SIGNAL(switchSessionRequest(Session
*)),
129 this, SLOT(switchSession(Session
*)));
130 connect(main
->sessionManager(), SIGNAL(currentSessionNameChanged()),
131 this, SLOT(updateWindowTitle()));
132 // A system for easy evaluation of pre-defined code:
133 connect(&mCodeEvalMapper
, SIGNAL(mapped(QString
)),
134 this, SIGNAL(evaluateCode(QString
)));
135 connect(this, SIGNAL(evaluateCode(QString
,bool)),
136 main
->scProcess(), SLOT(evaluateCode(QString
,bool)));
137 // Interpreter: post output
138 connect(main
->scProcess(), SIGNAL( scPost(QString
) ),
139 mPostDock
->mPostWindow
, SLOT( post(QString
) ) );
140 // Interpreter: monitor running state
141 connect(main
->scProcess(), SIGNAL( stateChanged(QProcess::ProcessState
) ),
142 this, SLOT( onInterpreterStateChanged(QProcess::ProcessState
) ) );
143 // Interpreter: forward status messages
144 connect(main
->scProcess(), SIGNAL(statusMessage(const QString
&)),
145 this, SLOT(showMessage(const QString
&)));
147 // Document list interaction
148 connect(mDocListDock
->list(), SIGNAL(clicked(Document
*)),
149 mEditors
, SLOT(setCurrent(Document
*)));
150 connect(mEditors
, SIGNAL(currentDocumentChanged(Document
*)),
151 mDocListDock
->list(), SLOT(setCurrent(Document
*)),
152 Qt::QueuedConnection
);
154 // Update actions on document change
155 connect(mEditors
, SIGNAL(currentDocumentChanged(Document
*)),
156 this, SLOT(onCurrentDocumentChanged(Document
*)));
157 // Document management
158 DocumentManager
*docMng
= main
->documentManager();
159 connect(docMng
, SIGNAL(changedExternally(Document
*)),
160 this, SLOT(onDocumentChangedExternally(Document
*)));
161 connect(docMng
, SIGNAL(recentsChanged()),
162 this, SLOT(updateRecentDocsMenu()));
164 connect(main
, SIGNAL(applySettingsRequest(Settings::Manager
*)),
165 this, SLOT(applySettings(Settings::Manager
*)));
168 connect(mToolBox
->closeButton(), SIGNAL(clicked()), this, SLOT(hideToolBox()));
170 connect(main
->scResponder(), SIGNAL(serverRunningChanged(bool,QString
,int)), this, SLOT(onServerRunningChanged(bool,QString
,int)));
171 connect(main
->scServer(), SIGNAL(updateServerStatus(int,int,int,int,float,float)), this, SLOT(onServerStatusReply(int,int,int,int,float,float)));
176 // Must be called after createAtions(), because it accesses an action:
177 onServerRunningChanged(false, "", 0);
179 mServerStatus
->addAction( action(ToggleServerRunning
) );
180 mServerStatus
->setContextMenuPolicy(Qt::ActionsContextMenu
);
182 // Initialize recent documents menu
183 updateRecentDocsMenu();
186 icon
.addFile(":/icons/sc-cube-128");
187 icon
.addFile(":/icons/sc-cube-48");
188 icon
.addFile(":/icons/sc-cube-32");
189 icon
.addFile(":/icons/sc-cube-16");
190 QApplication::setWindowIcon(icon
);
195 void MainWindow::createActions()
197 Settings::Manager
*settings
= mMain
->settings();
198 settings
->beginGroup("IDE/shortcuts");
203 mActions
[Quit
] = act
= new QAction(
204 QIcon::fromTheme("application-exit"), tr("&Quit..."), this);
205 act
->setShortcut(tr("Ctrl+Q", "Quit application"));
206 act
->setStatusTip(tr("Quit SuperCollider IDE"));
207 QObject::connect( act
, SIGNAL(triggered()), this, SLOT(onQuit()) );
209 mActions
[DocNew
] = act
= new QAction(
210 QIcon::fromTheme("document-new"), tr("&New"), this);
211 act
->setShortcut(tr("Ctrl+N", "New document"));
212 act
->setStatusTip(tr("Create a new document"));
213 connect(act
, SIGNAL(triggered()), this, SLOT(newDocument()));
215 mActions
[DocOpen
] = act
= new QAction(
216 QIcon::fromTheme("document-open"), tr("&Open..."), this);
217 act
->setShortcut(tr("Ctrl+O", "Open document"));
218 act
->setStatusTip(tr("Open an existing file"));
219 connect(act
, SIGNAL(triggered()), this, SLOT(openDocument()));
221 mActions
[DocSave
] = act
= new QAction(
222 QIcon::fromTheme("document-save"), tr("&Save"), this);
223 act
->setShortcut(tr("Ctrl+S", "Save document"));
224 act
->setStatusTip(tr("Save the current document"));
225 connect(act
, SIGNAL(triggered()), this, SLOT(saveDocument()));
227 mActions
[DocSaveAs
] = act
= new QAction(
228 QIcon::fromTheme("document-save-as"), tr("Save &As..."), this);
229 act
->setShortcut(tr("Ctrl+Shift+S", "Save &As..."));
230 act
->setStatusTip(tr("Save the current document into a different file"));
231 connect(act
, SIGNAL(triggered()), this, SLOT(saveDocumentAs()));
233 mActions
[DocSaveAll
] = act
= new QAction(
234 QIcon::fromTheme("document-save"), tr("Save All..."), this);
235 act
->setShortcut(tr("Ctrl+Alt+S", "Save all documents"));
236 act
->setStatusTip(tr("Save all open documents"));
237 connect(act
, SIGNAL(triggered()), this, SLOT(saveAllDocuments()));
239 mActions
[DocClose
] = act
= new QAction(
240 QIcon::fromTheme("window-close"), tr("&Close"), this);
241 act
->setShortcut(tr("Ctrl+W", "Close document"));
242 act
->setStatusTip(tr("Close the current document"));
243 connect(act
, SIGNAL(triggered()), this, SLOT(closeDocument()));
245 mActions
[DocCloseAll
] = act
= new QAction(
246 QIcon::fromTheme("window-close"), tr("Close All..."), this);
247 act
->setShortcut(tr("Ctrl+Shift+W", "Close all documents"));
248 act
->setStatusTip(tr("Close all documents"));
249 connect(act
, SIGNAL(triggered()), this, SLOT(closeAllDocuments()));
251 mActions
[DocReload
] = act
= new QAction(
252 QIcon::fromTheme("view-refresh"), tr("&Reload"), this);
253 act
->setShortcut(tr("F5", "Reload document"));
254 act
->setStatusTip(tr("Reload the current document"));
255 connect(act
, SIGNAL(triggered()), this, SLOT(reloadDocument()));
257 mActions
[ClearRecentDocs
] = act
= new QAction(tr("Clear", "Clear recent documents"), this);
258 connect(act
, SIGNAL(triggered()),
259 Main::instance()->documentManager(), SLOT(clearRecents()));
262 mActions
[NewSession
] = act
= new QAction(
263 QIcon::fromTheme("document-new"), tr("&New Session"), this);
264 act
->setStatusTip(tr("Open a new session"));
265 connect(act
, SIGNAL(triggered()), this, SLOT(newSession()));
267 mActions
[SaveSessionAs
] = act
= new QAction(
268 QIcon::fromTheme("document-save-as"), tr("Save Session &As..."), this);
269 act
->setStatusTip(tr("Save the current session with a different name"));
270 connect(act
, SIGNAL(triggered()), this, SLOT(saveCurrentSessionAs()));
272 mActions
[ManageSessions
] = act
= new QAction(
273 tr("&Manage Sessions..."), this);
274 connect(act
, SIGNAL(triggered()), this, SLOT(openSessionsDialog()));
276 mActions
[OpenSessionSwitchDialog
] = act
= new QAction(
277 tr("&Switch Session..."), this);
278 connect(act
, SIGNAL(triggered()), this, SLOT(showSwitchSessionDialog()));
279 act
->setShortcut(tr("Ctrl+Shift+Q", "Switch Session"));
282 mActions
[Find
] = act
= new QAction(
283 QIcon::fromTheme("edit-find"), tr("&Find..."), this);
284 act
->setShortcut(tr("Ctrl+F", "Find"));
285 act
->setStatusTip(tr("Find text in document"));
286 connect(act
, SIGNAL(triggered()), this, SLOT(showFindTool()));
288 mActions
[Replace
] = act
= new QAction(
289 QIcon::fromTheme("edit-replace"), tr("&Replace..."), this);
290 act
->setShortcut(tr("Ctrl+R", "Replace"));
291 act
->setStatusTip(tr("Find and replace text in document"));
292 connect(act
, SIGNAL(triggered()), this, SLOT(showReplaceTool()));
295 mActions
[ShowCmdLine
] = act
= new QAction(tr("&Command Line"), this);
296 act
->setStatusTip(tr("Command line for quick code evaluation"));
297 act
->setShortcut(tr("Ctrl+E", "Show command line"));
298 connect(act
, SIGNAL(triggered()), this, SLOT(showCmdLine()));
300 mActions
[ShowGoToLineTool
] = act
= new QAction(tr("&Go To Line"), this);
301 act
->setStatusTip(tr("Tool to jump to a line by number"));
302 act
->setShortcut(tr("Ctrl+G", "Show go-to-line tool"));
303 connect(act
, SIGNAL(triggered()), this, SLOT(showGoToLineTool()));
305 mActions
[CloseToolBox
] = act
= new QAction(
306 QIcon::fromTheme("window-close"), tr("&Close Tool Panel"), this);
307 act
->setStatusTip(tr("Close any open tool panel"));
308 act
->setShortcut(tr("Esc", "Close tool box"));
309 connect(act
, SIGNAL(triggered()), this, SLOT(hideToolBox()));
311 mActions
[ShowFullScreen
] = act
= new QAction(tr("&Full Screen"), this);
312 act
->setCheckable(false);
313 act
->setShortcut(tr("Ctrl+Shift+F", "Show ScIDE in Full Screen"));
314 connect(act
, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
316 mActions
[ClearPostWindow
] = act
= new QAction(
317 QIcon::fromTheme("window-clearpostwindow"), tr("Clear Post Window"), this);
318 act
->setStatusTip(tr("Clear Post Window"));
319 act
->setShortcut(tr("Ctrl+Shift+C", "Clear Post Window"));
320 connect(act
, SIGNAL(triggered()), mPostDock
->mPostWindow
, SLOT(clear()));
322 mActions
[LookupDefinition
] = act
= new QAction(
323 QIcon::fromTheme("window-lookupdefinition"), tr("Lookup Definition"), this);
324 act
->setShortcut(tr("Ctrl+Shift+I", "Lookup Definition"));
325 connect(act
, SIGNAL(triggered()), this, SLOT(lookupDefinition()));
327 mActions
[LookupDocumentation
] = act
= new QAction(
328 QIcon::fromTheme("window-lookupDocumentation"), tr("Lookup Documentation"), this);
329 act
->setShortcut(tr("Ctrl+Shift+D", "Lookup Documentation"));
330 connect(act
, SIGNAL(triggered()), this, SLOT(lookupDocumentation()));
333 mActions
[OpenDefinition
] = act
= new QAction(tr("Open Class/Method Definition"), this);
334 act
->setShortcut(tr("Ctrl+I", "Open definition of selected class or method"));
335 connect(act
, SIGNAL(triggered(bool)), this, SLOT(openDefinition()));
338 mActions
[ShowSettings
] = act
= new QAction(tr("&Configure IDE..."), this);
339 act
->setStatusTip(tr("Show configuration dialog"));
340 connect(act
, SIGNAL(triggered()), this, SLOT(showSettings()));
344 mActions
[Help
] = act
= new QAction(
345 QIcon::fromTheme("system-help"), tr("Open Help Browser"), this);
346 act
->setStatusTip(tr("Open help."));
347 connect(act
, SIGNAL(triggered()), this, SLOT(openHelp()));
349 mActions
[HelpForSelection
] = act
= new QAction(
350 QIcon::fromTheme("system-help"), tr("&Help for Selection"), this);
351 act
->setShortcut(tr("Ctrl+D", "Help for selection"));
352 act
->setStatusTip(tr("Find help for selected text"));
353 connect(act
, SIGNAL(triggered()), this, SLOT(openDocumentation()));
356 mActions
[ToggleServerRunning
] = act
= new QAction(this);
357 connect(act
, SIGNAL(triggered()), this, SLOT(toggleServerRunning()));
359 settings
->endGroup(); // IDE/shortcuts;
361 // Add actions to settings
362 for (int i
= 0; i
< ActionCount
; ++i
)
363 settings
->addAction( mActions
[i
] );
366 void MainWindow::createMenus()
371 menu
= new QMenu(tr("&File"), this);
372 menu
->addAction( mActions
[DocNew
] );
373 menu
->addAction( mActions
[DocOpen
] );
374 mRecentDocsMenu
= menu
->addMenu(tr("Open Recent", "Open a recent document"));
375 connect(mRecentDocsMenu
, SIGNAL(triggered(QAction
*)),
376 this, SLOT(onRecentDocAction(QAction
*)));
377 menu
->addAction( mActions
[DocSave
] );
378 menu
->addAction( mActions
[DocSaveAs
] );
379 menu
->addAction( mActions
[DocSaveAll
] );
380 menu
->addSeparator();
381 menu
->addAction( mActions
[DocReload
] );
382 menu
->addSeparator();
383 menu
->addAction( mActions
[DocClose
] );
384 menu
->addAction( mActions
[DocCloseAll
] );
385 menu
->addSeparator();
386 menu
->addAction( mActions
[Quit
] );
388 menuBar()->addMenu(menu
);
390 menu
= new QMenu(tr("&Session"), this);
391 menu
->addAction( mActions
[NewSession
] );
392 menu
->addAction( mActions
[SaveSessionAs
] );
393 submenu
= menu
->addMenu(tr("&Open Session"));
394 connect(submenu
, SIGNAL(triggered(QAction
*)),
395 this, SLOT(onOpenSessionAction(QAction
*)));
396 mSessionsMenu
= submenu
;
397 updateSessionsMenu();
398 menu
->addSeparator();
399 menu
->addAction( mActions
[ManageSessions
] );
400 menu
->addAction( mActions
[OpenSessionSwitchDialog
] );
402 menuBar()->addMenu(menu
);
404 menu
= new QMenu(tr("&Edit"), this);
405 menu
->addAction( mEditors
->action(MultiEditor::Undo
) );
406 menu
->addAction( mEditors
->action(MultiEditor::Redo
) );
407 menu
->addSeparator();
408 menu
->addAction( mEditors
->action(MultiEditor::Cut
) );
409 menu
->addAction( mEditors
->action(MultiEditor::Copy
) );
410 menu
->addAction( mEditors
->action(MultiEditor::Paste
) );
411 menu
->addSeparator();
412 menu
->addAction( mActions
[Find
] );
413 menu
->addAction( mActions
[Replace
] );
414 menu
->addSeparator();
415 menu
->addAction( mEditors
->action(MultiEditor::IndentLineOrRegion
) );
416 menu
->addAction( mEditors
->action(MultiEditor::ToggleComment
) );
417 menu
->addAction( mEditors
->action(MultiEditor::ToggleOverwriteMode
) );
418 menu
->addAction( mEditors
->action(MultiEditor::SelectRegion
) );
419 menu
->addSeparator();
420 menu
->addAction( mActions
[OpenDefinition
] );
422 menuBar()->addMenu(menu
);
424 menu
= new QMenu(tr("&View"), this);
425 submenu
= new QMenu(tr("&Docks"), this);
426 submenu
->addAction( mPostDock
->toggleViewAction() );
427 submenu
->addAction( mDocListDock
->toggleViewAction() );
428 menu
->addMenu(submenu
);
429 menu
->addSeparator();
430 submenu
= menu
->addMenu(tr("&Tool Panels"));
431 submenu
->addAction( mActions
[Find
] );
432 submenu
->addAction( mActions
[Replace
] );
433 submenu
->addAction( mActions
[ShowCmdLine
] );
434 submenu
->addAction( mActions
[ShowGoToLineTool
] );
435 submenu
->addSeparator();
436 submenu
->addAction( mActions
[CloseToolBox
] );
437 menu
->addSeparator();
438 menu
->addAction( mEditors
->action(MultiEditor::EnlargeFont
) );
439 menu
->addAction( mEditors
->action(MultiEditor::ShrinkFont
) );
440 menu
->addAction( mEditors
->action(MultiEditor::ResetFontSize
) );
441 menu
->addSeparator();
442 menu
->addAction( mEditors
->action(MultiEditor::ShowWhitespace
) );
443 menu
->addSeparator();
444 menu
->addAction( mEditors
->action(MultiEditor::NextDocument
) );
445 menu
->addAction( mEditors
->action(MultiEditor::PreviousDocument
) );
446 menu
->addSeparator();
447 menu
->addAction( mEditors
->action(MultiEditor::SplitHorizontally
) );
448 menu
->addAction( mEditors
->action(MultiEditor::SplitVertically
) );
449 menu
->addAction( mEditors
->action(MultiEditor::RemoveCurrentSplit
) );
450 menu
->addAction( mEditors
->action(MultiEditor::RemoveAllSplits
) );
451 menu
->addSeparator();
452 menu
->addAction( mActions
[ClearPostWindow
] );
453 menu
->addSeparator();
454 menu
->addAction( mActions
[ShowFullScreen
] );
455 menu
->addAction( mActions
[LookupDefinition
] );
456 menu
->addAction( mActions
[LookupDocumentation
] );
458 menuBar()->addMenu(menu
);
460 menu
= new QMenu(tr("&Language"), this);
461 menu
->addAction( mMain
->scProcess()->action(SCProcess::StartSCLang
) );
462 menu
->addAction( mMain
->scProcess()->action(SCProcess::StopSCLang
) );
463 menu
->addAction( mMain
->scProcess()->action(SCProcess::RestartSCLang
) );
464 menu
->addAction( mMain
->scProcess()->action(SCProcess::RecompileClassLibrary
) );
465 menu
->addSeparator();
466 menu
->addAction( mEditors
->action(MultiEditor::EvaluateCurrentDocument
) );
467 menu
->addAction( mEditors
->action(MultiEditor::EvaluateRegion
) );
468 menu
->addAction( mEditors
->action(MultiEditor::EvaluateLine
) );
469 menu
->addSeparator();
470 menu
->addAction( mMain
->scProcess()->action(ScIDE::SCProcess::RunMain
) );
471 menu
->addAction( mMain
->scProcess()->action(ScIDE::SCProcess::StopMain
) );
473 menuBar()->addMenu(menu
);
475 menu
= new QMenu(tr("&Settings"), this);
476 menu
->addAction( mActions
[ShowSettings
] );
478 menuBar()->addMenu(menu
);
480 menu
= new QMenu(tr("&Help"), this);
481 menu
->addAction( mActions
[Help
] );
482 menu
->addAction( mActions
[HelpForSelection
] );
484 menuBar()->addMenu(menu
);
487 void MainWindow::saveWindowState()
489 Settings::Manager
*settings
= Main::settings();
490 settings
->beginGroup("IDE/mainWindow");
491 settings
->setValue("geometry", this->saveGeometry().toBase64());
492 settings
->setValue("state", this->saveState().toBase64());
493 settings
->endGroup();
496 void MainWindow::restoreWindowState()
498 Settings::Manager
*settings
= Main::settings();
499 settings
->beginGroup("IDE/mainWindow");
501 QByteArray geom
= QByteArray::fromBase64( settings
->value("geometry").value
<QByteArray
>() );
503 restoreGeometry(geom
);
505 setWindowState( windowState() & ~Qt::WindowFullScreen
| Qt::WindowMaximized
);
507 QByteArray state
= QByteArray::fromBase64( settings
->value("state").value
<QByteArray
>() );
508 if (!state
.isEmpty())
511 settings
->endGroup();
514 void MainWindow::newSession()
516 if (promptSaveDocs())
517 mMain
->sessionManager()->newSession();
520 void MainWindow::saveCurrentSessionAs()
522 QString name
= QInputDialog::getText( this,
523 "Save Current Session",
524 "Enter a name for the session:" );
526 if (name
.isEmpty()) return;
528 mMain
->sessionManager()->saveSessionAs(name
);
530 updateSessionsMenu();
533 void MainWindow::onOpenSessionAction( QAction
* action
)
535 openSession(action
->text());
538 void MainWindow::switchSession( Session
*session
)
541 session
->beginGroup("mainWindow");
542 QByteArray geom
= QByteArray::fromBase64( session
->value("geometry").value
<QByteArray
>() );
543 QByteArray state
= QByteArray::fromBase64( session
->value("state").value
<QByteArray
>() );
546 // Workaround for Qt bug 4397:
547 setWindowState(Qt::WindowNoState
);
550 restoreGeometry(geom
);
551 if (!state
.isEmpty())
554 updateClockWidget(isFullScreen());
557 mEditors
->switchSession(session
);
562 void MainWindow::saveSession( Session
*session
)
564 session
->beginGroup("mainWindow");
565 session
->setValue("geometry", this->saveGeometry().toBase64());
566 session
->setValue("state", this->saveState().toBase64());
569 mEditors
->saveSession(session
);
572 void MainWindow::openSessionsDialog()
574 QPointer
<MainWindow
> mainwin(this);
575 SessionsDialog
dialog(mMain
->sessionManager(), this);
578 mainwin
->updateSessionsMenu();
581 QAction
*MainWindow::action( ActionRole role
)
583 Q_ASSERT( role
< ActionCount
);
584 return mActions
[role
];
587 bool MainWindow::quit()
589 if (!promptSaveDocs())
599 void MainWindow::onQuit()
604 void MainWindow::onCurrentDocumentChanged( Document
* doc
)
608 mActions
[DocSave
]->setEnabled(doc
);
609 mActions
[DocSaveAs
]->setEnabled(doc
);
610 mActions
[DocClose
]->setEnabled(doc
);
612 CodeEditor
*editor
= mEditors
->currentEditor();
613 mFindReplaceTool
->setEditor( editor
);
614 mGoToLineTool
->setEditor( editor
);
617 void MainWindow::onDocumentChangedExternally( Document
*doc
)
622 mDocDialog
= new DocumentsDialog(DocumentsDialog::ExternalChange
, this);
623 mDocDialog
->addDocument(doc
);
624 connect(mDocDialog
, SIGNAL(finished(int)), this, SLOT(onDocDialogFinished()));
628 void MainWindow::onDocDialogFinished()
630 mDocDialog
->deleteLater();
634 void MainWindow::updateRecentDocsMenu()
636 mRecentDocsMenu
->clear();
638 const QStringList
&recent
= mMain
->documentManager()->recents();
640 foreach( const QString
& path
, recent
)
641 mRecentDocsMenu
->addAction(path
);
643 if (!recent
.isEmpty()) {
644 mRecentDocsMenu
->addSeparator();
645 mRecentDocsMenu
->addAction(mActions
[ClearRecentDocs
]);
649 void MainWindow::onRecentDocAction( QAction
*action
)
651 mMain
->documentManager()->open(action
->text());
654 void MainWindow::onInterpreterStateChanged( QProcess::ProcessState state
)
660 case QProcess::NotRunning
:
664 case QProcess::Starting
:
666 color
= QColor(255,255,0);
668 case QProcess::Running
:
674 mLangStatus
->setText(text
);
675 mLangStatus
->setTextColor(color
);
679 void MainWindow::onServerStatusReply(int ugens
, int synths
, int groups
, int synthDefs
, float avgCPU
, float peakCPU
)
681 QString statusString
=
682 QString("%1% %2% %3u %4s %5g %6d")
683 .arg(avgCPU
, 5, 'f', 2)
684 .arg(peakCPU
, 5, 'f', 2)
690 mServerStatus
->setText(statusString
);
693 void MainWindow::onServerRunningChanged(bool running
, const QString
&, int)
695 QAction
*serverStatusAction
= mActions
[ToggleServerRunning
];
697 mServerStatus
->setTextColor( running
? Qt::green
: Qt::white
);
699 onServerStatusReply(0, 0, 0, 0, 0, 0);
701 serverStatusAction
->setText( tr("&Boot Server") );
702 serverStatusAction
->setStatusTip(tr("Boot sound synthesis server"));
704 serverStatusAction
->setText( tr("&Quit Server") );
705 serverStatusAction
->setStatusTip(tr("Quit sound synthesis server"));
709 void MainWindow::closeEvent(QCloseEvent
*event
)
711 if(!quit()) event
->ignore();
714 bool MainWindow::close( Document
*doc
)
716 if (doc
->textDocument()->isModified())
718 QMessageBox::StandardButton ret
;
719 ret
= QMessageBox::warning(
721 tr("SuperCollider IDE"),
722 tr("There are unsaved changes in document '%1'.\n\n"
723 "Do you want to save it?").arg(doc
->title()),
724 QMessageBox::Save
| QMessageBox::Discard
| QMessageBox::Cancel
,
725 QMessageBox::Save
// the default
729 case QMessageBox::Cancel
:
731 case QMessageBox::Save
:
732 if (!MainWindow::save(doc
))
738 Main::instance()->documentManager()->close(doc
);
742 bool MainWindow::reload( Document
*doc
)
744 if (doc
->filePath().isEmpty())
747 if (doc
->textDocument()->isModified())
749 QMessageBox::StandardButton ret
;
750 ret
= QMessageBox::warning(
752 tr("SuperCollider IDE"),
753 tr("There are unsaved changes in document '%1'.\n\n"
754 "Do you want to reload it?").arg(doc
->title()),
755 QMessageBox::Yes
| QMessageBox::No
,
756 QMessageBox::No
// the default
758 if (ret
== QMessageBox::No
)
762 return Main::instance()->documentManager()->reload(doc
);
765 bool MainWindow::save( Document
*doc
, bool forceChoose
)
767 DocumentManager
*mng
= Main::instance()->documentManager();
768 if (forceChoose
|| doc
->filePath().isEmpty()) {
769 QFileDialog
dialog(mInstance
);
770 dialog
.setAcceptMode( QFileDialog::AcceptSave
);
772 QStringList filters
= (QStringList()
773 << "SuperCollider Document(*.scd)"
774 << "SuperCollider Class file(*.sc)"
778 dialog
.setNameFilters(filters
);
779 dialog
.setDefaultSuffix("scd");
781 if (dialog
.exec() == QDialog::Accepted
)
782 return mng
->saveAs(doc
, dialog
.selectedFiles()[0]);
786 return mng
->save(doc
);
789 void MainWindow::newDocument()
791 mMain
->documentManager()->create();
794 void MainWindow::openDocument()
796 QFileDialog
dialog (this, Qt::Dialog
);
797 dialog
.setModal(true);
798 dialog
.setWindowModality(Qt::ApplicationModal
);
800 dialog
.setFileMode( QFileDialog::ExistingFiles
);
802 CodeEditor
* currentEditor
= mEditors
->currentEditor();
804 Document
* currentDocument
= currentEditor
->document();
805 QFileInfo
filePath (currentDocument
->filePath());
806 dialog
.setDirectory(filePath
.dir());
812 << "SuperCollider(*.scd *.sc)"
813 << "SCDoc(*.schelp)";
814 dialog
.setNameFilters(filters
);
818 QStringList filenames
= dialog
.selectedFiles();
819 foreach(QString filename
, filenames
)
820 mMain
->documentManager()->open(filename
);
824 void MainWindow::saveDocument()
826 CodeEditor
*editor
= mEditors
->currentEditor();
829 Document
*doc
= editor
->document();
832 MainWindow::save(doc
);
835 void MainWindow::saveDocumentAs()
837 CodeEditor
*editor
= mEditors
->currentEditor();
840 Document
*doc
= editor
->document();
843 MainWindow::save(doc
, true);
846 void MainWindow::saveAllDocuments()
848 QList
<Document
*> docs
= mMain
->documentManager()->documents();
849 foreach (Document
*doc
, docs
)
850 if (!MainWindow::save(doc
))
854 void MainWindow::reloadDocument()
856 CodeEditor
*editor
= mEditors
->currentEditor();
859 Q_ASSERT(editor
->document());
860 MainWindow::reload(editor
->document());
863 void MainWindow::closeDocument()
865 CodeEditor
*editor
= mEditors
->currentEditor();
868 Q_ASSERT(editor
->document());
869 MainWindow::close( editor
->document() );
872 void MainWindow::closeAllDocuments()
874 if (promptSaveDocs()) {
875 QList
<Document
*> docs
= mMain
->documentManager()->documents();
876 foreach (Document
*doc
, docs
)
877 mMain
->documentManager()->close(doc
);
881 bool MainWindow::promptSaveDocs()
883 QList
<Document
*> docs
= mMain
->documentManager()->documents();
884 QList
<Document
*> unsavedDocs
;
885 foreach(Document
* doc
, docs
)
886 if(doc
->textDocument()->isModified())
887 unsavedDocs
.append(doc
);
889 if (unsavedDocs
.count())
891 DocumentsDialog
dialog(unsavedDocs
, DocumentsDialog::Quit
, this);
900 void MainWindow::updateWindowTitle()
902 Session
*session
= mMain
->sessionManager()->currentSession();
903 CodeEditor
*editor
= mEditors
->currentEditor();
904 Document
*doc
= editor
? editor
->document() : 0;
909 title
.append(session
->name());
910 if (doc
) title
.append(": ");
914 if (!doc
->filePath().isEmpty()) {
915 QFileInfo info
= QFileInfo(doc
->filePath());
916 QString pathString
= info
.dir().path();
918 QString homePath
= QDir::homePath();
919 if (pathString
.startsWith(homePath
))
920 pathString
.replace(0, homePath
.size(), QString("~"));
922 QString titleString
= QString("%1 (%2)").arg(info
.fileName(), pathString
);
924 title
.append( titleString
);
926 title
.append( "Untitled" );
929 if (!title
.isEmpty())
932 title
.append("SuperCollider IDE");
934 setWindowTitle(title
);
937 void MainWindow::toggleFullScreen()
939 if (isFullScreen()) {
940 setWindowState(windowState() & ~Qt::WindowFullScreen
);
942 updateClockWidget(false);
944 setWindowState(windowState() | Qt::WindowFullScreen
);
946 updateClockWidget(true);
950 void MainWindow::updateClockWidget(bool isFullScreen
)
958 if (mClockLabel
== NULL
) {
959 mClockLabel
= new StatusClockLabel(this);
960 statusBar()->insertWidget(0, mClockLabel
);
965 void MainWindow::openSession(const QString
&sessionName
)
967 if (promptSaveDocs())
968 mMain
->sessionManager()->openSession( sessionName
);
971 void MainWindow::openDefinition()
973 QWidget
* focussedWidget
= QApplication::focusWidget();
975 int indexOfMethod
= focussedWidget
->metaObject()->indexOfMethod("openDefinition()");
976 if (indexOfMethod
!= -1)
977 QMetaObject::invokeMethod( focussedWidget
, "openDefinition", Qt::DirectConnection
);
980 void MainWindow::lookupDefinition()
982 LookupDialog
dialog(mEditors
);
986 void MainWindow::lookupDocumentation()
988 PopupTextInput
* dialog
= new PopupTextInput(tr("Lookup Documentation For"), this);
990 bool success
= dialog
->exec();
992 Main::openDocumentation(dialog
->textValue());
997 void MainWindow::showMessage( QString
const & string
)
999 mStatusBar
->showMessage(string
, 3000);
1002 void MainWindow::applySettings( Settings::Manager
* settings
)
1004 mEditors
->applySettings(settings
);
1005 mPostDock
->mPostWindow
->applySettings(settings
);
1006 mCmdLine
->applySettings(settings
);
1010 void MainWindow::updateSessionsMenu()
1012 mSessionsMenu
->clear();
1013 QStringList sessions
= mMain
->sessionManager()->availableSessions();
1014 foreach (const QString
& session
, sessions
)
1015 mSessionsMenu
->addAction( session
);
1018 void MainWindow::showSwitchSessionDialog()
1020 SessionSwitchDialog
* dialog
= new SessionSwitchDialog(this);
1021 int result
= dialog
->exec();
1023 if (result
== QDialog::Accepted
)
1024 openSession(dialog
->activeElement());
1029 void MainWindow::showCmdLine()
1031 mToolBox
->setCurrentWidget( mCmdLine
);
1034 mCmdLine
->setFocus(Qt::OtherFocusReason
);
1037 void MainWindow::showGoToLineTool()
1039 CodeEditor
*editor
= mEditors
->currentEditor();
1040 mGoToLineTool
->setValue( editor
? editor
->textCursor().blockNumber() + 1 : 0 );
1042 mToolBox
->setCurrentWidget( mGoToLineTool
);
1045 mGoToLineTool
->setFocus();
1048 void MainWindow::showFindTool()
1050 mFindReplaceTool
->setMode( TextFindReplacePanel::Find
);
1051 mFindReplaceTool
->initiate();
1053 mToolBox
->setCurrentWidget( mFindReplaceTool
);
1056 mFindReplaceTool
->setFocus(Qt::OtherFocusReason
);
1059 void MainWindow::showReplaceTool()
1061 mFindReplaceTool
->setMode( TextFindReplacePanel::Replace
);
1062 mFindReplaceTool
->initiate();
1064 mToolBox
->setCurrentWidget( mFindReplaceTool
);
1067 mFindReplaceTool
->setFocus(Qt::OtherFocusReason
);
1070 void MainWindow::hideToolBox()
1073 CodeEditor
*editor
= mEditors
->currentEditor();
1075 // This slot is mapped to Escape, so also clear highlighting
1076 // whenever invoked:
1077 editor
->clearSearchHighlighting();
1078 if (!editor
->hasFocus())
1079 editor
->setFocus(Qt::OtherFocusReason
);
1083 void MainWindow::showSettings()
1085 Settings::Dialog
dialog(mMain
->settings());
1086 dialog
.resize(700,400);
1087 int result
= dialog
.exec();
1088 if( result
== QDialog::Accepted
)
1089 mMain
->applySettings();
1092 void MainWindow::openDocumentation()
1094 QWidget
* focussedWidget
= QApplication::focusWidget();
1096 bool documentationOpened
= false;
1098 int indexOfMethod
= focussedWidget
->metaObject()->indexOfMethod("openDocumentation()");
1099 if (indexOfMethod
!= -1)
1100 QMetaObject::invokeMethod( focussedWidget
, "openDocumentation", Qt::DirectConnection
,
1101 Q_RETURN_ARG(bool, documentationOpened
) );
1103 if (!documentationOpened
)
1107 void MainWindow::openHelp()
1109 QString code
= QString("Help.gui");
1110 Main::scProcess()->evaluateCode(code
, true);
1113 void MainWindow::toggleServerRunning()
1115 ScServer
*scServer
= Main::scServer();
1117 if (scServer
->isRunning())
1123 //////////////////////////// StatusLabel /////////////////////////////////
1125 StatusLabel::StatusLabel(QWidget
*parent
) : QLabel(parent
)
1127 setAutoFillBackground(true);
1129 setAlignment(Qt::AlignCenter
);
1130 setBackground(Qt::black
);
1131 setTextColor(Qt::white
);
1133 QFont
font("Monospace");
1134 font
.setStyleHint(QFont::Monospace
);
1139 void StatusLabel::setBackground(const QBrush
& brush
)
1141 QPalette
plt(palette());
1142 plt
.setBrush(QPalette::Window
, brush
);
1146 void StatusLabel::setTextColor(const QColor
& color
)
1148 QPalette
plt(palette());
1149 plt
.setColor(QPalette::WindowText
, color
);
1153 //////////////////////////// StatusClockLabel ////////////////////////////
1155 StatusClockLabel::StatusClockLabel(QWidget
* parent
):
1158 setTextColor(Qt::green
);
1159 mTimerId
= startTimer(1000);
1163 StatusClockLabel::~StatusClockLabel()
1165 killTimer(mTimerId
);
1168 void StatusClockLabel::timerEvent(QTimerEvent
*e
)
1170 if (e
->timerId() == mTimerId
)
1174 void StatusClockLabel::updateTime()
1176 setText(QTime::currentTime().toString());
1179 } // namespace ScIDE