comparison gui/src/FileEditor.cpp @ 14599:97cb9286919c gui

Cleaned up code. * .hgsub: Removed IRC Widget. * gui.pro: Removed dependency on IRC Widget and removed files. * class FileEditorMdiSubWindow: Renamed to FileEditor. File editor windows are now independent windows, thus removed the extra close button. * MainWindow: Removed MDI Area and replaced it with the terminal instead. * BrowserWidget: Removed browser widget. * SettingsDialog: Rearranged settings for the editor, removed tab for shortcuts. * OctaveCallbackThread: Raised update intervals from 0,5s to 1s. * OctaveLink: Replaced signals names for triggering updates on the symbol table. * WorkspaceView: Adjusted connect statements to fit the new signal names.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 07 May 2012 00:53:54 +0200
parents gui/src/FileEditorMdiSubWindow.cpp@be3e1a14a6de
children c8453a013000
comparison
equal deleted inserted replaced
14588:fa52c6e84ae0 14599:97cb9286919c
1 /* OctaveGUI - A graphical user interface for Octave
2 * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "FileEditor.h"
19 #include <QVBoxLayout>
20 #include <QApplication>
21 #include <QFile>
22 #include <QFont>
23 #include <QFileDialog>
24 #include <QMessageBox>
25 #include <QStyle>
26 #include <QTextStream>
27
28 FileEditor::FileEditor (QWidget * parent)
29 : QWidget (parent)
30 {
31 construct ();
32 }
33
34 FileEditor::~FileEditor ()
35 {
36 }
37
38 void
39 FileEditor::closeEvent(QCloseEvent *event)
40 {
41 if ( m_mainWindow->isCloseApplication() )
42 {
43 // close wohle application: save file or not if modified
44 checkFileModified ("Close Octave GUI",0); // no cancel possible
45 }
46 else
47 {
48 // ignore close event if file is not saved and user cancels closing this window
49 if (checkFileModified ("Close File",QMessageBox::Cancel)==QMessageBox::Cancel)
50 event->ignore();
51 else
52 event->accept();
53 }
54 }
55
56 void
57 FileEditor::handleMarginClicked(int margin, int line, Qt::KeyboardModifiers state)
58 {
59 Q_UNUSED (state);
60 if ( margin == 1 ) // marker margin
61 {
62 unsigned int mask = m_editor->markersAtLine (line);
63 if (mask && (1 << MARKER_BOOKMARK))
64 m_editor->markerDelete(line,MARKER_BOOKMARK);
65 else
66 m_editor->markerAdd(line,MARKER_BOOKMARK);
67 }
68 }
69
70 void
71 FileEditor::newWindowTitle(bool modified)
72 {
73 QString title(m_fileName);
74 if ( !m_longTitle )
75 {
76 QFileInfo file(m_fileName);
77 title = file.fileName();
78 }
79 if ( modified )
80 {
81 setWindowTitle(title.prepend("* "));
82 }
83 else
84 setWindowTitle (title);
85 }
86
87 void
88 FileEditor::handleCopyAvailable(bool enableCopy)
89 {
90 m_copyAction->setEnabled(enableCopy);
91 m_cutAction->setEnabled(enableCopy);
92 }
93
94
95 void
96 FileEditor::openFile ()
97 {
98 if (checkFileModified ("Open File",QMessageBox::Cancel)==QMessageBox::Cancel)
99 {
100 return; // existing file not saved and opening another file canceled by user
101 }
102 QString openFileName;
103 QFileDialog dlg(this);
104 dlg.setNameFilter(SAVE_FILE_FILTER);
105 dlg.setAcceptMode(QFileDialog::AcceptOpen);
106 dlg.setViewMode(QFileDialog::Detail);
107 if ( dlg.exec() )
108 {
109 openFileName = dlg.selectedFiles().at(0);
110 if (openFileName.isEmpty ())
111 return;
112 loadFile(openFileName);
113 }
114 }
115
116 void
117 FileEditor::loadFile (QString fileName)
118 {
119 QFile file (fileName);
120 if (!file.open (QFile::ReadOnly))
121 {
122 QMessageBox::warning (this, tr ("File Editor"),
123 tr ("Cannot read file %1:\n%2.").arg (fileName).
124 arg (file.errorString ()));
125 return;
126 }
127
128 QTextStream in (&file);
129 QApplication::setOverrideCursor (Qt::WaitCursor);
130 m_editor->setText (in.readAll ());
131 QApplication::restoreOverrideCursor ();
132
133 m_fileName = fileName;
134 newWindowTitle (false); // window title (no modification)
135 m_statusBar->showMessage (tr ("File loaded."), 2000);
136 m_editor->setModified (false); // loaded file is not modified yet
137 }
138
139 void
140 FileEditor::newFile ()
141 {
142 if (checkFileModified ("Create New File",QMessageBox::Cancel)==QMessageBox::Cancel)
143 {
144 return; // existing file not saved and creating new file canceled by user
145 }
146
147 m_fileName = UNNAMED_FILE;
148 newWindowTitle (false); // window title (no modification)
149 m_editor->setText ("");
150 m_editor->setModified (false); // new file is not modified yet
151 }
152
153 int
154 FileEditor::checkFileModified (QString msg, int cancelButton)
155 {
156 int decision = QMessageBox::Yes;
157 if (m_editor->isModified ())
158 {
159 // file is modified but not saved, aks user what to do
160 decision = QMessageBox::warning (this,
161 msg,
162 tr ("The file %1\n"
163 "has been modified. Do you want to save the changes?").
164 arg (m_fileName),
165 QMessageBox::Save, QMessageBox::Discard, cancelButton );
166 if (decision == QMessageBox::Save)
167 {
168 saveFile ();
169 if (m_editor->isModified ())
170 {
171 // If the user attempted to save the file, but it's still
172 // modified, then probably something went wrong, so return cancel
173 // for cancel this operation or try to save files as if cancel not
174 // possible
175 if ( cancelButton )
176 return (QMessageBox::Cancel);
177 else
178 saveFileAs ();
179 }
180 }
181 }
182 return (decision);
183 }
184
185 void
186 FileEditor::saveFile ()
187 {
188 saveFile(m_fileName);
189 }
190
191 void
192 FileEditor::saveFile (QString saveFileName)
193 {
194 // it is a new file with the name "<unnamed>" -> call saveFielAs
195 if (saveFileName==UNNAMED_FILE || saveFileName.isEmpty ())
196 {
197 saveFileAs();
198 return;
199 }
200
201 // open the file for writing
202 QFile file (saveFileName);
203 if (!file.open (QFile::WriteOnly))
204 {
205 QMessageBox::warning (this, tr ("File Editor"),
206 tr ("Cannot write file %1:\n%2.").
207 arg (saveFileName).arg (file.errorString ()));
208 return;
209 }
210
211 // save the contents into the file
212 QTextStream out (&file);
213 QApplication::setOverrideCursor (Qt::WaitCursor);
214 out << m_editor->text ();
215 QApplication::restoreOverrideCursor ();
216 m_fileName = saveFileName; // save file name for later use
217 newWindowTitle(false); // set the window title to actual file name (not modified)
218 m_statusBar->showMessage (tr ("File %1 saved").arg(m_fileName), 2000);
219 m_editor->setModified (false); // files is save -> not modified
220 }
221
222 void
223 FileEditor::saveFileAs ()
224 {
225 QString saveFileName(m_fileName);
226 QFileDialog dlg(this);
227 if (saveFileName==UNNAMED_FILE || saveFileName.isEmpty ())
228 {
229 saveFileName = QDir::homePath();
230 dlg.setDirectory(saveFileName);
231 }
232 else
233 {
234 dlg.selectFile(saveFileName);
235 }
236 dlg.setNameFilter(SAVE_FILE_FILTER);
237 dlg.setDefaultSuffix("m");
238 dlg.setAcceptMode(QFileDialog::AcceptSave);
239 dlg.setViewMode(QFileDialog::Detail);
240 if ( dlg.exec() )
241 {
242 saveFileName = dlg.selectedFiles().at(0);
243 if (saveFileName.isEmpty ())
244 return;
245 saveFile(saveFileName);
246 }
247 }
248
249 // handle the run command
250 void
251 FileEditor::runFile ()
252 {
253 if (m_editor->isModified ())
254 saveFile(m_fileName);
255 m_terminalView->sendText (QString ("run \'%1\'\n").arg (m_fileName));
256 m_terminalView->setFocus ();
257 }
258
259
260 // (un)comment selected text
261 void
262 FileEditor::commentSelectedText ()
263 {
264 doCommentSelectedText (true);
265 }
266 void
267 FileEditor::uncommentSelectedText ()
268 {
269 doCommentSelectedText (false);
270 }
271 void
272 FileEditor::doCommentSelectedText (bool comment)
273 {
274 if ( m_editor->hasSelectedText() )
275 {
276 int lineFrom, lineTo, colFrom, colTo, i;
277 m_editor->getSelection (&lineFrom,&colFrom,&lineTo,&colTo);
278 if ( colTo == 0 ) // the beginning of last line is not selected
279 lineTo--; // stop at line above
280 m_editor->beginUndoAction ();
281 for ( i=lineFrom; i<=lineTo; i++ )
282 {
283 if ( comment )
284 m_editor->insertAt("%",i,0);
285 else
286 {
287 QString line(m_editor->text(i));
288 if ( line.startsWith("%") )
289 {
290 m_editor->setSelection(i,0,i,1);
291 m_editor->removeSelectedText();
292 }
293 }
294 }
295 m_editor->endUndoAction ();
296 }
297 }
298
299
300 // remove bookmarks
301 void
302 FileEditor::removeBookmark ()
303 {
304 m_editor->markerDeleteAll(MARKER_BOOKMARK);
305 }
306 // toggle bookmark
307 void
308 FileEditor::toggleBookmark ()
309 {
310 int line,cur;
311 m_editor->getCursorPosition(&line,&cur);
312 if ( m_editor->markersAtLine (line) && (1 << MARKER_BOOKMARK) )
313 m_editor->markerDelete(line,MARKER_BOOKMARK);
314 else
315 m_editor->markerAdd(line,MARKER_BOOKMARK);
316 }
317 // goto next bookmark
318 void
319 FileEditor::nextBookmark ()
320 {
321 int line,cur,nextline;
322 m_editor->getCursorPosition(&line,&cur);
323 if ( m_editor->markersAtLine(line) && (1 << MARKER_BOOKMARK) )
324 line++; // we have a bookmark here, so start search from next line
325 nextline = m_editor->markerFindNext(line,(1 << MARKER_BOOKMARK));
326 m_editor->setCursorPosition(nextline,0);
327 }
328 // goto previous bookmark
329 void
330 FileEditor::prevBookmark ()
331 {
332 int line,cur,prevline;
333 m_editor->getCursorPosition(&line,&cur);
334 if ( m_editor->markersAtLine(line) && (1 << MARKER_BOOKMARK) )
335 line--; // we have a bookmark here, so start search from prev line
336 prevline = m_editor->markerFindPrevious(line,(1 << MARKER_BOOKMARK));
337 m_editor->setCursorPosition(prevline,0);
338 }
339
340 // function for setting the already existing lexer from MainWindow
341 void
342 FileEditor::initEditor (QTerminal* terminalView,
343 LexerOctaveGui* lexer,
344 MainWindow* mainWindow)
345 {
346 m_editor->setLexer(lexer);
347 m_terminalView = terminalView; // for sending commands to octave
348 // TODO: make a global commandOctave function?
349 m_mainWindow = mainWindow; // get the MainWindow for chekcing state at subwindow close
350 }
351
352 void
353 FileEditor::setModified (bool modified)
354 {
355 m_modified = modified;
356 }
357
358 void
359 FileEditor::construct ()
360 {
361 QSettings *settings = ResourceManager::instance ()->settings ();
362 QStyle *style = QApplication::style ();
363
364 m_menuBar = new QMenuBar (this);
365 m_toolBar = new QToolBar (this);
366 m_statusBar = new QStatusBar (this);
367 m_editor = new QsciScintilla (this);
368
369 // markers
370 m_editor->setMarginType (1, QsciScintilla::SymbolMargin);
371 m_editor->setMarginSensitivity(1,true);
372 m_editor->markerDefine(QsciScintilla::RightTriangle,MARKER_BOOKMARK);
373 connect(m_editor,SIGNAL(marginClicked(int,int,Qt::KeyboardModifiers)),
374 this,SLOT(handleMarginClicked(int,int,Qt::KeyboardModifiers)));
375
376 // line numbers
377 m_editor->setMarginsForegroundColor(QColor(96,96,96));
378 m_editor->setMarginsBackgroundColor(QColor(232,232,220));
379 if ( settings->value ("editor/showLineNumbers",true).toBool () )
380 {
381 QFont marginFont( settings->value ("editor/fontName","Courier").toString () ,
382 settings->value ("editor/fontSize",10).toInt () );
383 m_editor->setMarginsFont( marginFont );
384 QFontMetrics metrics(marginFont);
385 m_editor->setMarginType (2, QsciScintilla::TextMargin);
386 m_editor->setMarginWidth(2, metrics.width("99999"));
387 m_editor->setMarginLineNumbers(2, true);
388 }
389 // code folding
390 m_editor->setMarginType (3, QsciScintilla::SymbolMargin);
391 m_editor->setFolding (QsciScintilla::BoxedTreeFoldStyle , 3);
392 // other features
393 if ( settings->value ("editor/highlightCurrentLine",true).toBool () )
394 {
395 m_editor->setCaretLineVisible(true);
396 m_editor->setCaretLineBackgroundColor(QColor(245,245,245));
397 }
398 m_editor->setBraceMatching (QsciScintilla::StrictBraceMatch);
399 m_editor->setAutoIndent (true);
400 m_editor->setIndentationWidth (2);
401 m_editor->setIndentationsUseTabs (false);
402 if ( settings->value ("editor/codeCompletion",true).toBool () )
403 {
404 m_editor->autoCompleteFromAll ();
405 m_editor->setAutoCompletionSource(QsciScintilla::AcsAll);
406 m_editor->setAutoCompletionThreshold (1);
407 }
408 m_editor->setUtf8 (true);
409 m_longTitle = settings->value ("editor/longWindowTitle",true).toBool ();
410
411 // The Actions
412
413 // Theme icons with QStyle icons as fallback
414 QAction *newAction = new QAction (
415 QIcon::fromTheme("document-new",style->standardIcon (QStyle::SP_FileIcon)),
416 tr("&New File"), m_toolBar);
417 QAction *openAction = new QAction (
418 QIcon::fromTheme("document-open",style->standardIcon (QStyle::SP_DirOpenIcon)),
419 tr("&Open File"), m_toolBar);
420 QAction *saveAction = new QAction (
421 QIcon::fromTheme("document-save",style->standardIcon (QStyle::SP_DriveHDIcon)),
422 tr("&Save File"), m_toolBar);
423 QAction *saveAsAction = new QAction (
424 QIcon::fromTheme("document-save-as",style->standardIcon (QStyle::SP_DriveFDIcon)),
425 tr("Save File &As"), m_toolBar);
426 QAction *undoAction = new QAction (
427 QIcon::fromTheme("edit-undo",style->standardIcon (QStyle::SP_ArrowLeft)),
428 tr("&Undo"), m_toolBar);
429 QAction *redoAction = new QAction (
430 QIcon::fromTheme("edit-redo",style->standardIcon (QStyle::SP_ArrowRight)),
431 tr("&Redo"), m_toolBar);
432 m_copyAction = new QAction (QIcon::fromTheme("edit-copy"),tr("&Copy"),m_toolBar);
433 m_cutAction = new QAction (QIcon::fromTheme("edit-cut"),tr("Cu&t"),m_toolBar);
434 QAction *pasteAction = new QAction (QIcon::fromTheme("edit-paste"),tr("&Paste"),m_toolBar);
435 QAction *nextBookmarkAction = new QAction (tr("&Next Bookmark"),m_toolBar);
436 QAction *prevBookmarkAction = new QAction (tr("Pre&vious Bookmark"),m_toolBar);
437 QAction *toggleBookmarkAction = new QAction (tr("Toggle &Bookmark"),m_toolBar);
438 QAction *removeBookmarkAction = new QAction (tr("&Remove All Bookmarks"),m_toolBar);
439 QAction *commentSelectedAction = new QAction (tr("&Comment Selected Text"),m_toolBar);
440 QAction *uncommentSelectedAction = new QAction (tr("&Uncomment Selected Text"),m_toolBar);
441 QAction *runAction = new QAction (
442 QIcon::fromTheme("media-play",style->standardIcon (QStyle::SP_MediaPlay)),
443 tr("&Run File"), m_toolBar);
444
445 // some actions are disabled from the beginning
446 m_copyAction->setEnabled(false);
447 m_cutAction->setEnabled(false);
448 connect(m_editor,SIGNAL(copyAvailable(bool)),this,SLOT(handleCopyAvailable(bool)));
449
450 // short cuts
451 newAction->setShortcut(QKeySequence::New);
452 openAction->setShortcut(QKeySequence::Open);
453 saveAction->setShortcut(QKeySequence::Save);
454 saveAsAction->setShortcut(QKeySequence::SaveAs);
455 undoAction->setShortcut(QKeySequence::Undo);
456 redoAction->setShortcut(QKeySequence::Redo);
457 m_copyAction->setShortcut(QKeySequence::Copy);
458 m_cutAction->setShortcut(QKeySequence::Cut);
459 pasteAction->setShortcut(QKeySequence::Paste);
460 runAction->setShortcut(Qt::Key_F5);
461 nextBookmarkAction->setShortcut(Qt::Key_F2);
462 prevBookmarkAction->setShortcut(Qt::SHIFT + Qt::Key_F2);
463 toggleBookmarkAction->setShortcut(Qt::Key_F7);
464 commentSelectedAction->setShortcut(Qt::CTRL + Qt::Key_R);
465 uncommentSelectedAction->setShortcut(Qt::CTRL + Qt::Key_T);
466
467 // toolbar
468 m_toolBar->addAction (newAction);
469 m_toolBar->addAction (openAction);
470 m_toolBar->addAction (saveAction);
471 m_toolBar->addAction (saveAsAction);
472 m_toolBar->addSeparator();
473 m_toolBar->addAction (undoAction);
474 m_toolBar->addAction (redoAction);
475 m_toolBar->addAction (m_copyAction);
476 m_toolBar->addAction (m_cutAction);
477 m_toolBar->addAction (pasteAction);
478 m_toolBar->addSeparator();
479 m_toolBar->addAction (runAction);
480
481 // menu bar
482 QMenu *fileMenu = new QMenu(tr("&File"),m_menuBar);
483 fileMenu->addAction(newAction);
484 fileMenu->addAction(openAction);
485 fileMenu->addAction(saveAction);
486 fileMenu->addAction(saveAsAction);
487 fileMenu->addSeparator();
488 m_menuBar->addMenu(fileMenu);
489 QMenu *editMenu = new QMenu(tr("&Edit"),m_menuBar);
490 editMenu->addAction(undoAction);
491 editMenu->addAction(redoAction);
492 editMenu->addSeparator();
493 editMenu->addAction(m_copyAction);
494 editMenu->addAction(m_cutAction);
495 editMenu->addAction(pasteAction);
496 editMenu->addSeparator();
497 editMenu->addAction(commentSelectedAction);
498 editMenu->addAction(uncommentSelectedAction);
499 editMenu->addSeparator();
500 editMenu->addAction(toggleBookmarkAction);
501 editMenu->addAction(nextBookmarkAction);
502 editMenu->addAction(prevBookmarkAction);
503 editMenu->addAction(removeBookmarkAction);
504 m_menuBar->addMenu(editMenu);
505 QMenu *runMenu = new QMenu(tr("&Run"),m_menuBar);
506 runMenu->addAction(runAction);
507 m_menuBar->addMenu(runMenu);
508
509
510 QVBoxLayout *layout = new QVBoxLayout ();
511 layout->addWidget (m_menuBar);
512 layout->addWidget (m_toolBar);
513 layout->addWidget (m_editor);
514 layout->addWidget (m_statusBar);
515 layout->setMargin (2);
516 setLayout (layout);
517
518 connect (newAction, SIGNAL (triggered ()), this, SLOT (newFile ()));
519 connect (openAction, SIGNAL (triggered ()), this, SLOT (openFile ()));
520 connect (undoAction, SIGNAL (triggered ()), m_editor, SLOT (undo ()));
521 connect (redoAction, SIGNAL (triggered ()), m_editor, SLOT (redo ()));
522 connect (m_copyAction, SIGNAL (triggered ()), m_editor, SLOT (copy ()));
523 connect (m_cutAction, SIGNAL (triggered ()), m_editor, SLOT (cut ()));
524 connect (pasteAction, SIGNAL (triggered ()), m_editor, SLOT (paste ()));
525 connect (saveAction, SIGNAL (triggered ()), this, SLOT (saveFile ()));
526 connect (saveAsAction, SIGNAL (triggered ()), this, SLOT (saveFileAs ()));
527 connect (runAction, SIGNAL (triggered ()), this, SLOT (runFile ()));
528 connect (toggleBookmarkAction, SIGNAL (triggered ()), this, SLOT (toggleBookmark ()));
529 connect (nextBookmarkAction, SIGNAL (triggered ()), this, SLOT (nextBookmark ()));
530 connect (prevBookmarkAction, SIGNAL (triggered ()), this, SLOT (prevBookmark ()));
531 connect (removeBookmarkAction, SIGNAL (triggered ()), this, SLOT (removeBookmark ()));
532 connect (commentSelectedAction, SIGNAL (triggered ()), this, SLOT (commentSelectedText ()));
533 connect (uncommentSelectedAction, SIGNAL (triggered ()), this, SLOT (uncommentSelectedText ()));
534
535
536 // connect modified signal
537 connect (m_editor, SIGNAL (modificationChanged(bool)), this, SLOT (newWindowTitle(bool)) );
538
539 m_fileName = "";
540 newWindowTitle (false);
541 setWindowIcon(QIcon::fromTheme("accessories-text-editor",style->standardIcon (QStyle::SP_FileIcon)));
542 show ();
543 }