moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kturtle / src / kturtle.cpp
blobb7f70705e6bc511fa99c9c20f90061e2cd845ced
1 /*
2 * KTurtle, Copyright (C) 2003-04 Cies Breijs <cies # kde ! nl>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of version 2 of the GNU General Public
6 License as published by the Free Software Foundation.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 // BEGIN includes and defines
21 #include <stdlib.h>
23 #include <qbutton.h>
24 #include <qregexp.h>
25 #include <qpainter.h>
26 #include <qtooltip.h>
27 #include <qtimer.h>
28 #include <qwhatsthis.h>
30 #include <kapplication.h>
31 #include <kconfigdialog.h>
32 #include <kdebug.h>
33 #include <kedittoolbar.h>
34 #include <kfiledialog.h>
35 #include <kimageio.h>
36 #include <kinputdialog.h>
37 #include <klocale.h>
38 #include <kmessagebox.h>
39 #include <kmenubar.h>
40 #include <kprinter.h>
41 #include <ksavefile.h>
42 #include <kstatusbar.h>
44 #include <ktexteditor/clipboardinterface.h>
45 #include <ktexteditor/cursorinterface.h>
46 #include <ktexteditor/editorchooser.h>
47 #include <ktexteditor/editinterface.h>
48 #include <ktexteditor/highlightinginterface.h>
49 #include <ktexteditor/printinterface.h>
50 #include <ktexteditor/selectioninterface.h>
51 #include <ktexteditor/undointerface.h>
52 #include <ktexteditor/viewcursorinterface.h>
54 #include "lexer.h"
55 #include "settings.h"
56 #include "translate.h"
58 #include "kturtle.h"
60 // StatusBar field IDs
61 #define IDS_STATUS 0
62 #define IDS_LINECOLUMN 2
63 #define IDS_INS 3
64 #define IDS_LANG 4
66 // END
70 // BEGIN constructor and destructor
72 MainWindow::MainWindow(KTextEditor::Document *document) : editor(0)
74 // the initial values
75 CurrentFile = KURL(); // fill with empty URL
76 setCaption( i18n("Untitled") );
77 picker = 0; // for the colorpickerdialog
78 executing = false;
79 b_fullscreen = false;
81 // set the shell's ui resource file
82 if (!document)
84 if ( !(document = KTextEditor::EditorChooser::createDocument(0,"KTextEditor::Document") ) )
86 KMessageBox::error( this, i18n("A KDE text-editor component could not be found;\n"
87 "please check your KDE installation.") );
88 kapp->exit(1);
90 // docList.append(doc);
92 doc = document;
94 setupCanvas();
95 setupEditor();
97 setupStatusBar();
98 setupActions();
99 createShellGUI(true);
100 setMinimumSize(200,200);
102 // init with more usefull size, stolen from kwite (they stole it from konq)
103 if ( !initialGeometrySet() && !kapp->config()->hasGroup("MainWindow Settings") ) resize(640, 480);
105 KConfig *config = kapp->config();
106 readConfig(config);
109 MainWindow::~MainWindow()
111 delete editor->document();
114 // END
118 // BEGIN setup's (actions, editor, statusbar, canvas)
120 void MainWindow::setupActions()
122 KActionCollection *ac = actionCollection(); // abbreviation
124 // File actions
125 KStdAction::openNew(this, SLOT(slotNewFile()), ac);
126 openExAction = new KAction(i18n("Open Exa&mples..."), "bookmark_folder", CTRL+Key_E, this, SLOT(slotOpenExample()), ac, "open_examples");
127 KStdAction::open(this, SLOT(slotOpenFile()), ac);
128 m_recentFiles = KStdAction::openRecent(this, SLOT(slotOpenFile(const KURL&)), ac);
129 KStdAction::save(this, SLOT(slotSaveFile()), ac);
130 KStdAction::saveAs(this, SLOT(slotSaveAs()), ac);
131 new KAction(i18n("Save &Canvas..."), 0, 0, this, SLOT(slotSaveCanvas()), ac, "save_canvas");
132 speed = new KSelectAction(i18n("Execution Speed"), 0, ALT+Key_S, this, SLOT( slotChangeSpeed() ), ac, "speed");
133 QStringList speeds; speeds << i18n("Full Speed") << i18n("Slow") << i18n("Slower") << i18n("Slowest");
134 speed->setItems(speeds);
135 speed->setCurrentItem(0);
136 run = new KAction(i18n("&Execute Commands"), "gear", ALT+Key_Return, this, SLOT( slotExecute() ), ac, "run");
137 pause = new KToggleAction(i18n("Pause E&xecution"), "player_pause", Key_Pause, this, SLOT( slotPauseExecution() ), ac, "pause");
138 pause->setChecked(false);
139 pause->setEnabled(false);
140 stop = new KAction(i18n("Stop E&xecution"), "stop", Key_Escape, this, SLOT( slotAbortExecution() ), ac, "stop");
141 stop->setEnabled(false);
142 KStdAction::print(this, SLOT(slotPrint()), ac);
143 KStdAction::quit(this, SLOT(close()), ac);
145 // Edit actions
146 KStdAction::undo(this, SLOT(slotUndo()), ac);
147 KStdAction::redo(this, SLOT(slotRedo()), ac);
148 KStdAction::cut(this, SLOT(slotCut()), ac);
149 KStdAction::copy(this, SLOT(slotCopy()), ac);
150 KStdAction::paste(this, SLOT(slotPaste()), ac);
151 KStdAction::selectAll(this, SLOT(slotSelectAll()), ac);
152 KStdAction::deselect(this, SLOT(slotClearSelection()), ac);
153 new KToggleAction(i18n("Toggle Insert"), Key_Insert, this, SLOT(slotToggleInsert()), ac, "set_insert");
154 KStdAction::find(this, SLOT(slotFind()), ac);
155 KStdAction::findNext(this, SLOT(slotFindNext()), ac);
156 KStdAction::findPrev(this, SLOT(slotFindPrevious()), ac);
157 KStdAction::replace(this, SLOT(slotReplace()), ac);
159 // View actions
160 new KToggleAction(i18n("Show &Line Numbers"), 0, Key_F11, this, SLOT(slotToggleLineNumbers()), ac, "line_numbers");
161 m_fullscreen = KStdAction::fullScreen(this, SLOT(slotToggleFullscreen()), ac, this, "full_screen");
162 m_fullscreen->setChecked(b_fullscreen);
164 // Tools actions
165 colorpicker = new KToggleAction(i18n("&Color Picker"), "colorize", ALT+Key_C, this, SLOT(slotColorPicker()), ac, "color_picker");
166 new KAction(i18n("&Indent"), "indent", CTRL+Key_I, this, SLOT(slotIndent()), ac, "edit_indent");
167 new KAction(i18n("&Unindent"), "unindent", CTRL+SHIFT+Key_I, this, SLOT(slotUnIndent()), ac, "edit_unindent");
168 new KAction(i18n("Cl&ean Indentation"), 0, 0, this, SLOT(slotCleanIndent()), ac, "edit_cleanIndent");
169 new KAction(i18n("Co&mment"), 0, CTRL+Key_D, this, SLOT(slotComment()), ac, "edit_comment");
170 new KAction(i18n("Unc&omment"), 0, CTRL+SHIFT+Key_D, this, SLOT(slotUnComment()), ac, "edit_uncomment");
172 // Settings actions
173 KStdAction::preferences( this, SLOT(slotSettings()), ac );
174 new KAction(i18n("&Configure Editor..."), "configure", 0, this, SLOT(slotEditor()), ac, "set_confdlg");
176 // Help actions
177 ContextHelp = new KAction(0, 0, Key_F2, this, SLOT(slotContextHelp()), ac, "context_help");
178 slotContextHelpUpdate(); // this sets the label of this action
180 // other
181 setXMLFile("kturtleui.rc");
182 setupGUI();
185 void MainWindow::setupEditor()
187 editorDock = new QDockWindow(this);
188 editorDock->setNewLine(true);
189 editorDock->setFixedExtentWidth(250);
190 editorDock->setFixedExtentHeight(150);
191 editorDock->setResizeEnabled(true);
192 editorDock->setFrameShape(QFrame::ToolBarPanel);
193 QWhatsThis::add( editorDock, i18n( "This is the code editor, here you type the Logo commands to instruct the turtle. You can also open an existing Logo program with File->Open Examples... or File->Open." ) );
194 moveDockWindow(editorDock, Qt::DockLeft);
195 editor = doc->createView (editorDock, 0L);
196 // editorInterface is the editor interface which allows us to access the text in the part
197 editorInterface = dynamic_cast<KTextEditor::EditInterface*>(doc);
198 editorDock->setWidget(editor);
200 // default the highlightstyle to "logo" using the needed i18n
201 kdDebug(0)<<"The HighlightStyle for the Code Editor: "<<Settings::logoLanguage()<<endl;
202 slotSetHighlightstyle( Settings::logoLanguage() );
204 // allow the cursor position to be indicated in the statusbar
205 connect( editor, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorStatusBar()) );
206 // and update the context help menu item
207 connect( editor, SIGNAL(cursorPositionChanged()), this, SLOT(slotContextHelpUpdate()) );
209 translate = new Translate();
212 void MainWindow::setupStatusBar()
214 statusBar()->insertItem("", IDS_STATUS, 1, false);
215 statusBar()->setItemAlignment(IDS_STATUS, AlignLeft);
216 statusBar()->insertItem("", IDS_LANG, 0, true);
217 statusBar()->insertItem("", IDS_LINECOLUMN, 0, true);
218 statusBar()->insertItem("", IDS_INS, 0, true);
220 // fill the statusbar
221 slotStatusBar(i18n("Welcome to KTurtle..."), IDS_STATUS); // the message part
222 slotStatusBar(i18n("Line: %1 Column: %2").arg(1).arg(1), IDS_LINECOLUMN);
223 slotStatusBar(i18n("INS"), IDS_INS);
226 void MainWindow::setupCanvas()
228 baseWidget = new QWidget(this);
229 setCentralWidget(baseWidget);
230 baseLayout = new QGridLayout(baseWidget, 0, 0);
231 canvasView = new Canvas(baseWidget);
232 baseLayout->addWidget(canvasView, 0, 0, AlignCenter);
233 baseLayout->setRowStretch(0, 1); // this apperntly fixes a pre-usefull scrollbars bug
234 baseLayout->setColStretch(0, 1);
235 QWhatsThis::add( canvasView, i18n("This is the canvas, here the turtle draws a picture.") );
236 canvasView->show();
237 connect( canvasView, SIGNAL( CanvasResized() ), this, SLOT( slotUpdateCanvas() ) );
240 // END
244 // BEGIN staturbar related functions
246 void MainWindow::slotStatusBar(QString text, int id)
248 text = " " + text + " "; // help the layout
249 statusBar()->changeItem(text, id);
252 void MainWindow::slotCursorStatusBar()
254 uint cursorLine;
255 uint cursorCol;
256 dynamic_cast<KTextEditor::ViewCursorInterface*>(editor)->cursorPositionReal(&cursorLine, &cursorCol);
257 QString linenumber = i18n(" Line: %1 Column: %2 ").arg(cursorLine + 1).arg(cursorCol + 1);
258 statusBar()->changeItem(linenumber, IDS_LINECOLUMN);
261 // END
265 // BEGIN file menu related fuctions (new, open, save()as, image, print, quit)
267 void MainWindow::slotNewFile()
269 if ( !editor->document()->isModified() && CurrentFile.isEmpty() ) return; // do nothing when nothing can be done
270 if ( editor->document()->isModified() )
272 int result = KMessageBox::warningContinueCancel( this,
273 i18n("The program you are currently working on is not saved. "
274 "By continuing you may lose the changes you have made."),
275 i18n("Unsaved File"), i18n("&Discard Changes") );
276 if (result != KMessageBox::Continue) return;
278 editorInterface->clear(); // clear the editor
279 canvasView->slotClear(); // clear the view
280 editor->document()->setModified(false);
281 CurrentFile = KURL();
282 setCaption( i18n("Untitled") );
283 slotStatusBar(i18n("New file... Happy coding!"), IDS_STATUS);
288 void MainWindow::slotOpenFile(const KURL &urlRef)
290 KURL url = urlRef;
291 if ( url.isEmpty() )
293 url = KFileDialog::getOpenURL( QString(":logo_dir"), QString("*.logo|") + i18n("Logo Files"), this, i18n("Open Logo File") );
295 loadFile(url);
298 void MainWindow::slotOpenExample()
300 KURL url;
301 url.setPath( locate("data", "kturtle/examples/" + Settings::logoLanguage() + "/") );
302 url = KFileDialog::getOpenURL( url.path(), QString("*.logo|") + i18n("Logo Examples Files"), this, i18n("Open Logo Example File") );
303 loadFile(url);
306 void MainWindow::loadFile(const KURL &url)
308 if ( !url.isEmpty() )
310 QFile file( url.path() );
311 if ( file.open(IO_ReadOnly) )
313 if ( editor->document()->isModified() )
315 int result = KMessageBox::warningContinueCancel( this,
316 i18n("The program you are currently working on is not saved. "
317 "By continuing you may lose the changes you have made."),
318 i18n("Unsaved File"), i18n("&Discard Changes") );
319 if (result != KMessageBox::Continue)
321 slotStatusBar(i18n("Opening aborted, nothing opened."), IDS_STATUS);
322 return;
325 QTextStream stream(&file);
326 stream.setEncoding(QTextStream::UnicodeUTF8);
327 editorInterface->setText( stream.read() );
328 file.close();
329 m_recentFiles->addURL(url);
330 setCaption( url.fileName() );
331 slotStatusBar(i18n("Opened file: %1").arg( url.fileName() ), IDS_STATUS);
332 editor->document()->setModified(false);
333 CurrentFile = url;
334 return;
336 else
338 KMessageBox::error( this,
339 i18n("KTurtle was unable to open: \n%1.").arg( url.prettyURL() ),
340 i18n("Open Error") );
341 slotStatusBar(i18n("Opening aborted because of error."), IDS_STATUS);
342 return;
345 slotStatusBar(i18n("Opening aborted."), IDS_STATUS); // fallback
348 void MainWindow::slotSaveFile()
350 writeFile(CurrentFile);
353 void MainWindow::slotSaveAs()
355 KURL url;
356 while (true)
358 url = KFileDialog::getSaveURL( QString(":logo_dir"), QString("*.logo|") + i18n("Logo Files"), this, i18n("Save As") );
359 if ( url.isEmpty() ) // cancelled the save dialog
361 slotStatusBar(i18n("Saving aborted."), IDS_STATUS);
362 return;
364 if ( QFile( url.path() ).exists() )
366 int result = KMessageBox::warningContinueCancel ( this,
367 i18n("A program named \"%1\" already exists in this folder. "
368 "Do you want to overwrite it?").arg( url.fileName() ),
369 i18n("Overwrite?"), i18n("&Overwrite") );
370 if (result != KMessageBox::Continue) return;
372 break;
374 writeFile(url);
377 void MainWindow::writeFile(const KURL &url)
379 if ( url.isEmpty() ) slotSaveAs();
380 else
382 QString mString = editorInterface->text(); // get the text
383 editorInterface->setText( mString.utf8() ); // convert it to utf8
384 editor->document()->saveAs(url); // use the KateParts method for saving
385 loadFile(url); // reload the file as utf8 otherwise display weird chars
386 setCaption( url.fileName() );
387 slotStatusBar(i18n("Saved to: %1").arg( url.fileName() ), IDS_STATUS);
388 m_recentFiles->addURL(url);
389 editor->document()->setModified(false);
390 CurrentFile = url;
396 void MainWindow::slotSaveCanvas()
398 KURL url;
399 while (true)
401 url = KFileDialog::getSaveURL( QString(":logo_dir"), QString("*.png|") +
402 i18n("Pictures"), this, i18n("Save Canvas as Picture") );
403 if ( url.isEmpty() ) return; // when cancelled the KFiledialog?
404 if ( QFile( url.path() ).exists() )
406 int result = KMessageBox::warningContinueCancel( this,
407 i18n("A picture named \"%1\" already in this folder. "
408 "Do you want to overwrite it?").arg( url.fileName() ),
409 i18n("Overwrite?"), i18n("&Overwrite") );
410 if (result != KMessageBox::Continue) return;
412 break;
415 QString type( KImageIO::type( url.path() ) );
416 if ( type.isNull() ) type = "PNG";
417 bool ok = false;
418 QPixmap* pixmap = canvasView->canvas2Pixmap();
419 if ( url.isLocalFile() )
421 KSaveFile saveFile( url.path() );
422 if ( saveFile.status() == 0 )
424 if ( pixmap->save( saveFile.file(), type.latin1() ) ) ok = saveFile.close();
427 if (!ok)
429 kdWarning() << "KTurtle was unable to save the canvas drawing" << endl;
430 KMessageBox::error(this,
431 i18n("KTurtle was unable to save the image to: \n%1.").arg( url.prettyURL() ),
432 i18n("Unable to Save Image") );
433 slotStatusBar(i18n("Could not save image."), IDS_STATUS);
434 return;
436 slotStatusBar(i18n("Saved canvas to: %1").arg( url.fileName() ), IDS_STATUS);
441 void MainWindow::slotPrint()
443 int result = KMessageBox::questionYesNoCancel( this,
444 i18n("Do you want to print the Logo code or the canvas?"),
445 i18n("What to Print?"), i18n("Print &Logo Code"), i18n("Print &Canvas") );
446 if (result == KMessageBox::Yes)
448 dynamic_cast<KTextEditor::PrintInterface*>(doc)->printDialog();
449 return;
451 if (result == KMessageBox::No)
453 KPrinter printer;
454 if ( printer.setup(this) )
456 QPainter painter(&printer);
457 QPixmap *CanvasPic = canvasView->canvas2Pixmap();
458 painter.drawPixmap(0, 0, *CanvasPic);
460 return;
462 slotStatusBar(i18n("Printing aborted."), IDS_STATUS);
467 bool MainWindow::queryClose()
469 if ( editor->document()->isModified() )
471 slotStatusBar(i18n("Quitting KTurtle..."), IDS_STATUS);
472 // make sure the dialog looks good with new -- unnamed -- files.
473 int result = KMessageBox::warningYesNoCancel( this,
474 i18n("The program you are currently working on is not saved. "
475 "By quitting KTurtle you may lose the changes you have made."),
476 i18n("Unsaved File"), i18n("&Save"), i18n("Discard Changes && &Quit") );
477 if (result == KMessageBox::Cancel)
479 slotStatusBar(i18n("Quitting aborted."), IDS_STATUS);
480 return false;
482 else if (result == KMessageBox::Yes)
484 slotSaveFile();
485 if ( CurrentFile.isEmpty() )
487 // when saveAs get cancelled or X-ed it should not quit
488 slotStatusBar(i18n("Quitting aborted."), IDS_STATUS);
489 return false;
493 KConfig *config = kapp->config();
494 config->setGroup("General Options");
495 m_recentFiles->saveEntries(config, "Recent Files");
496 config->sync();
497 return true;
500 // END
504 // BEGIN run related functions
506 void MainWindow::slotExecute()
508 if (b_fullscreen) // check if execution should be execution in 'fullscreen' mode
510 editorDock->hide();
511 statusBar()->hide();
512 menuBar()->hide();
513 toolBar()->hide();
516 run->setEnabled(false); // set action indications
517 pause->setEnabled(true);
518 stop->setEnabled(true);
520 // start paring
521 slotStatusBar(i18n("Parsing commands..."), IDS_STATUS);
522 kdDebug(0)<<"############## PARSING STARTED ##############"<<endl;
523 kapp->processEvents();
524 errMsg = new ErrorMessage(this); // create an empty errorDialog
525 QString txt = editorInterface->text() + "\x0a\x0a"; // parser expects input to have 2 delimiting newlines
526 QTextIStream in(&txt); // create the stream
527 Parser parser(in); // pass the reference to the stream to the parse object
528 connect(&parser, SIGNAL( ErrorMsg(Token&, const QString&, uint) ),
529 errMsg, SLOT( slotAddError(Token&, const QString&, uint) ) );
530 connect( errMsg, SIGNAL(setSelection(uint, uint, uint, uint) ),
531 this, SLOT(slotSetSelection(uint, uint, uint, uint) ) );
532 parser.parse(); // and GO!
533 TreeNode* root = parser.getTree(); // when finished parsing get the nodeTree
534 kdDebug(0)<<"############## PARSING FINISHED ##############"<<endl;
536 kdDebug(0)<<"TreeNode::showTree():"<<endl;
537 root->showTree(root); // show nodeTree, this is a DEBUG OPTION (but nice)
539 // start execution
540 slotStatusBar(i18n("Executing commands..."), IDS_STATUS);
541 kdDebug(0)<<"############## EXECUTION STARTED ##############"<<endl;
542 exe = new Executer(root); // make Executer object, 'exe', and pass it the nodeTree
544 connect(this, SIGNAL( changeSpeed(int) ), exe, SLOT(slotChangeSpeed(int) ) );
545 connect(this, SIGNAL( unpauseExecution() ), exe, SLOT( slotStopPausing() ) );
546 connect( exe, SIGNAL( setSelection(uint, uint, uint, uint) ),
547 this, SLOT ( slotSetSelection(uint, uint, uint, uint) ) );
548 connect( exe, SIGNAL( ErrorMsg(Token&, const QString&, uint) ),
549 errMsg, SLOT ( slotAddError(Token&, const QString&, uint) ) );
550 connect( exe, SIGNAL( InputDialog(QString&) ), this, SLOT( slotInputDialog(QString&) ) );
551 connect( exe, SIGNAL( MessageDialog(QString) ), this, SLOT( slotMessageDialog(QString) ) );
553 // Connect the signals form Executer to the slots from Canvas:
554 connect( exe, SIGNAL( Clear() ), canvasView, SLOT( slotClear() ) );
555 connect( exe, SIGNAL( Go(double, double) ), canvasView, SLOT( slotGo(double, double) ) );
556 connect( exe, SIGNAL( GoX(double) ), canvasView, SLOT( slotGoX(double) ) );
557 connect( exe, SIGNAL( GoY(double) ), canvasView, SLOT( slotGoY(double) ) );
558 connect( exe, SIGNAL( Forward(double) ), canvasView, SLOT( slotForward(double) ) );
559 connect( exe, SIGNAL( Backward(double) ), canvasView, SLOT( slotBackward(double) ) );
560 connect( exe, SIGNAL( Direction(double) ), canvasView, SLOT( slotDirection(double) ) );
561 connect( exe, SIGNAL( TurnLeft(double) ), canvasView, SLOT( slotTurnLeft(double) ) );
562 connect( exe, SIGNAL( TurnRight(double) ), canvasView, SLOT( slotTurnRight(double) ) );
563 connect( exe, SIGNAL( Center() ), canvasView, SLOT( slotCenter() ) );
564 connect( exe, SIGNAL( SetPenWidth(int) ), canvasView, SLOT( slotSetPenWidth(int) ) );
565 connect( exe, SIGNAL( PenUp() ), canvasView, SLOT( slotPenUp() ) );
566 connect( exe, SIGNAL( PenDown() ), canvasView, SLOT( slotPenDown() ) );
567 connect( exe, SIGNAL( SetFgColor(int, int, int) ), canvasView, SLOT( slotSetFgColor(int, int, int) ) );
568 connect( exe, SIGNAL( SetBgColor(int, int, int) ), canvasView, SLOT( slotSetBgColor(int, int, int) ) );
569 connect( exe, SIGNAL( ResizeCanvas(int, int) ), canvasView, SLOT( slotResizeCanvas(int, int) ) );
570 connect( exe, SIGNAL( SpriteShow() ), canvasView, SLOT( slotSpriteShow() ) );
571 connect( exe, SIGNAL( SpriteHide() ), canvasView, SLOT( slotSpriteHide() ) );
572 connect( exe, SIGNAL( SpritePress() ), canvasView, SLOT( slotSpritePress() ) );
573 connect( exe, SIGNAL( SpriteChange(int) ), canvasView, SLOT( slotSpriteChange(int) ) );
574 connect( exe, SIGNAL( Print(QString) ), canvasView, SLOT( slotPrint(QString) ) );
575 connect( exe, SIGNAL( FontType(QString, QString) ), canvasView, SLOT( slotFontType(QString, QString) ) );
576 connect( exe, SIGNAL( FontSize(int) ), canvasView, SLOT( slotFontSize(int) ) );
577 connect( exe, SIGNAL( WrapOn() ), canvasView, SLOT( slotWrapOn() ) );
578 connect( exe, SIGNAL( WrapOff() ), canvasView, SLOT( slotWrapOff() ) );
579 connect( exe, SIGNAL( Reset() ), canvasView, SLOT( slotReset() ) );
581 // START EXECUTION on the selected speed, and use the feedbacked boolean value
582 slotChangeSpeed();
583 if ( exe->run() ) slotStatusBar(i18n("Done."), IDS_STATUS);
584 else slotStatusBar(i18n("Execution aborted."), IDS_STATUS);
585 finishExecution();
587 delete exe; // clean-up
589 if ( errMsg->containsErrors() ) errMsg->display(); // if errors show them
592 void MainWindow::slotPauseExecution()
594 if ( pause->isChecked() )
596 exe->pause();
597 slotStatusBar(i18n("Execution paused."), IDS_STATUS);
599 else
601 emit unpauseExecution();
602 slotStatusBar(i18n("Executing commands..."), IDS_STATUS);
606 void MainWindow::slotAbortExecution()
608 // To abort the executor, this can for instance be handy when the
609 // executer got stuck in a user made endless loops...
610 // to keep the program responding to interrupts like this, all the
611 // loops have possible breaks. This activates them breaks:
612 exe->abort();
615 void MainWindow::finishExecution()
617 kdDebug(0)<<"############## EXECUTION FINISHED ##############"<<endl;
618 executing = false;
619 pause->setEnabled(false);
620 pause->setChecked(false);
621 run->setEnabled(true);
622 stop->setEnabled(false);
624 // if execution finished on FullSpeed the selection does not match the last executed command -> clear-it
625 if (speed->currentItem() == 0) slotClearSelection();
627 // if coming from fullscreen-mode show the editor, menu- and statusbar
628 if (b_fullscreen) QTimer::singleShot( 1000, this, SLOT( slotFinishedFullScreenExecution() ) );
631 void MainWindow::slotChangeSpeed()
633 emit changeSpeed( speed->currentItem() );
637 // slots for logo functions that need to use the MainWindow class:
639 void MainWindow::slotInputDialog(QString& value)
641 value = KInputDialog::getText(i18n("Input"), value);
644 void MainWindow::slotMessageDialog(QString text)
646 KMessageBox::information( this, text, i18n("Message") );
649 // END
653 // BEGIN editor connections (undo, redo, cut, copy, paste, cursor, selections, find, replace, linenumbers etc.)
655 void MainWindow::slotEditor()
657 KAction *a = editor->actionCollection()->action("set_confdlg");
658 a->activate();
661 void MainWindow::slotSetHighlightstyle(QString langCode)
663 KTextEditor::HighlightingInterface *hli = dynamic_cast<KTextEditor::HighlightingInterface*>(doc);
664 for (uint i = 0; i < hli->hlModeCount(); i++)
666 if (hli->hlModeName(i) == langCode)
668 hli->setHlMode(i);
669 return;
672 // and the fallback:
673 for (uint i = 0; i < hli->hlModeCount(); i++)
675 if(hli->hlModeName(i) == "en_US") hli->setHlMode(i);
680 void MainWindow::slotUndo()
682 dynamic_cast<KTextEditor::UndoInterface*>(doc)->undo();
685 void MainWindow::slotRedo()
687 dynamic_cast<KTextEditor::UndoInterface*>(doc)->redo();
691 void MainWindow::slotCut()
693 dynamic_cast<KTextEditor::ClipboardInterface*>(editor)->cut();
696 void MainWindow::slotCopy()
698 dynamic_cast<KTextEditor::ClipboardInterface*>(editor)->copy();
701 void MainWindow::slotPaste()
703 dynamic_cast<KTextEditor::ClipboardInterface*>(editor)->paste();
707 void MainWindow::slotSelectAll()
709 dynamic_cast<KTextEditor::SelectionInterface*>(doc)->selectAll();
712 void MainWindow::slotClearSelection()
714 dynamic_cast<KTextEditor::SelectionInterface*>(doc)->clearSelection();
717 void MainWindow::slotFind()
719 KAction *a = editor->actionCollection()->action("edit_find");
720 a->activate();
723 void MainWindow::slotFindNext()
725 KAction *a = editor->actionCollection()->action("edit_find_next");
726 a->activate();
729 void MainWindow::slotFindPrevious()
731 KAction *a = editor->actionCollection()->action("edit_find_prev");
732 a->activate();
735 void MainWindow::slotReplace()
737 KAction* a = editor->actionCollection()->action("edit_replace");
738 a->activate();
741 void MainWindow::slotToggleInsert()
743 KToggleAction *a = dynamic_cast<KToggleAction*>(editor->actionCollection()->action("set_insert"));
744 a->activate();
745 if (a) statusBar()->changeItem(a->isChecked() ? i18n(" OVR ") : i18n(" INS "), IDS_INS);
748 void MainWindow::slotIndent()
750 KAction *a = editor->actionCollection()->action("tools_indent");
751 a->activate();
754 void MainWindow::slotUnIndent()
756 KAction *a = editor->actionCollection()->action("tools_unindent");
757 a->activate();
760 void MainWindow::slotCleanIndent()
762 KAction *a = editor->actionCollection()->action("tools_cleanIndent");
763 a->activate();
766 void MainWindow::slotComment()
768 KAction *a = editor->actionCollection()->action("tools_comment");
769 a->activate();
772 void MainWindow::slotUnComment()
774 KAction *a = editor->actionCollection()->action("tools_uncomment");
775 a->activate();
778 void MainWindow::slotToggleLineNumbers()
780 KToggleAction *a = dynamic_cast<KToggleAction*>( editor->actionCollection()->action("view_line_numbers") );
781 a->activate();
784 void MainWindow::slotInsertText(QString str)
786 uint StartLine, StartCol, EndLine, EndCol;
787 dynamic_cast<KTextEditor::ViewCursorInterface*>(editor)->cursorPositionReal(&StartLine, &StartCol);
788 dynamic_cast<KTextEditor::EditInterface*>(doc)->insertText(StartLine, StartCol, str);
789 dynamic_cast<KTextEditor::ViewCursorInterface*>(editor)->cursorPositionReal(&EndLine, &EndCol);
790 dynamic_cast<KTextEditor::SelectionInterface*>(doc)->setSelection(StartLine, StartCol, EndLine, EndCol);
793 void MainWindow::slotSetCursorPos(uint row, uint col)
795 dynamic_cast<KTextEditor::ViewCursorInterface*>(editor)->setCursorPositionReal(row - 1, col);
796 // kdDebug(0)<<"Cursor set to: ("<<row-1<<", "<<col<<")"<<endl;
799 void MainWindow::slotSetSelection(uint StartLine, uint StartCol, uint EndLine, uint EndCol)
801 dynamic_cast<KTextEditor::SelectionInterface*>(doc)->setSelection(StartLine - 1, StartCol - 1, EndLine - 1, EndCol - 1);
802 // kdDebug(0)<<"Selection set to: ("<<StartLine<<", "<<StartCol<<", "<<EndLine<<", "<<EndCol<<")"<<endl;
804 // END
808 // BEGIN fullscreen functions
810 void MainWindow::slotToggleFullscreen()
812 if (!b_fullscreen) showFullScreen(); // both calls will generate event triggering updateFullScreen()
813 else if ( isFullScreen() ) showNormal();
816 bool MainWindow::event(QEvent* e)
818 // executes updateFullScreen() after a ShowFullScreen or ShowNormal event got triggered
819 if (e->type() == QEvent::ShowFullScreen || e->type() == QEvent::ShowNormal) updateFullScreen();
820 return KMainWindow::event(e);
823 void MainWindow::updateFullScreen()
825 if (isFullScreen() == b_fullscreen) return;
826 b_fullscreen = isFullScreen();
827 if (m_fullscreen) m_fullscreen->setChecked(b_fullscreen);
830 void MainWindow::slotFinishedFullScreenExecution()
832 restartOrBackDialog = new RestartOrBack(this); // we have to make some to delete some
833 if ( errMsg->containsErrors() ) slotBackToFullScreen(); // straight back to edit if there where errors
834 else
836 connect( restartOrBackDialog, SIGNAL( user1Clicked() ), this, SLOT( slotRestartFullScreen() ) );
837 connect( restartOrBackDialog, SIGNAL( user2Clicked() ), this, SLOT( slotBackToFullScreen() ) );
838 connect( restartOrBackDialog, SIGNAL( finished() ), this, SLOT( slotBackToFullScreen() ) );
839 restartOrBackDialog->show();
840 restartOrBackDialog->move(50, 50);
844 void MainWindow::slotBackToFullScreen()
846 delete restartOrBackDialog;
847 editorDock->show();
848 statusBar()->show();
849 menuBar()->show();
850 toolBar()->show();
853 void MainWindow::slotRestartFullScreen()
855 delete restartOrBackDialog;
856 slotExecute();
859 // END
863 // BEGIN configuration related functions
865 void MainWindow::slotSettings()
867 // Check if there is already a dialog, if so bring it to the foreground.
868 if ( KConfigDialog::showDialog("settings") ) return;
870 // Create a new dialog with the same name as the above checking code.
871 KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self() );
872 // connect the help
873 connect( dialog, SIGNAL( helpClicked() ), this, SLOT( slotSettingsHelp() ) );
875 // making the filling for the 'General' settings dept.
876 general = new QWidget();
877 QGridLayout *generalLayout = new QGridLayout( general, 1, 1, 11, 6, "generalLayout");
878 WidthHeightBox = new QGroupBox( i18n("Initial Canvas Size"), general );
879 WidthHeightBox->setColumnLayout(0, Qt::Vertical );
880 WidthHeightBox->layout()->setSpacing( 6 );
881 WidthHeightBox->layout()->setMargin( 11 );
882 QVBoxLayout *WidthHeightBoxLayout = new QVBoxLayout( WidthHeightBox->layout() );
883 WidthHeightBoxLayout->setAlignment( Qt::AlignTop );
884 QHBoxLayout *layout3 = new QHBoxLayout( 0, 0, 6, "layout3");
885 QVBoxLayout *layout2 = new QVBoxLayout( 0, 0, 6, "layout2");
887 QVBoxLayout *layout1 = new QVBoxLayout( 0, 0, 6, "layout1");
889 kcfg_CanvasWidth = new KIntNumInput( WidthHeightBox, "kcfg_CanvasWidth" );
890 kcfg_CanvasWidth->setValue( 400 );
891 kcfg_CanvasWidth->setMinValue( 1 );
892 kcfg_CanvasWidth->setReferencePoint( 1 );
893 layout1->addWidget( kcfg_CanvasWidth );
895 kcfg_CanvasHeight = new KIntNumInput( WidthHeightBox, "kcfg_CanvasHeight" );
896 kcfg_CanvasHeight->setValue( 300 );
897 kcfg_CanvasHeight->setMinValue( 1 );
898 kcfg_CanvasHeight->setReferencePoint( 1 );
899 layout1->addWidget( kcfg_CanvasHeight );
901 WidthLabel = new QLabel( kcfg_CanvasWidth, i18n("Canvas &width:"), WidthHeightBox );
902 layout2->addWidget( WidthLabel );
903 HeightLabel = new QLabel( kcfg_CanvasHeight, i18n("Ca&nvas height:"), WidthHeightBox );
904 layout2->addWidget( HeightLabel );
905 layout3->addLayout( layout2 );
907 layout3->addLayout( layout1 );
908 WidthHeightBoxLayout->addLayout( layout3 );
909 QLabel* WidthHeightLabel = new QLabel(i18n("You need to restart before these settings have effect"), WidthHeightBox);
910 WidthHeightBoxLayout->addWidget( WidthHeightLabel );
911 generalLayout->addWidget( WidthHeightBox, 0, 0 );
912 general->resize( QSize(234, 109).expandedTo(minimumSizeHint()) );
914 dialog->addPage( general, i18n("General"), "package_settings", i18n("General Settings") );
916 // making the filling for the 'Language' settings dept.
917 QWidget *language = new QWidget();
918 QGridLayout *languageLayout = new QGridLayout( language, 1, 1, 11, 6, "Form1Layout");
919 QGroupBox *groupBox1 = new QGroupBox( language, "groupBox1" );
920 groupBox1->setColumnLayout(0, Qt::Vertical );
921 groupBox1->layout()->setSpacing( 6 );
922 groupBox1->layout()->setMargin( 11 );
923 QGridLayout *groupBox1Layout = new QGridLayout( groupBox1->layout() );
924 groupBox1Layout->setAlignment( Qt::AlignTop );
926 QVBoxLayout *layout4 = new QVBoxLayout( 0, 0, 6, "layout4");
928 kcfg_LanguageComboBox = new KComboBox(groupBox1, "kcfg_LanguageComboBox");
929 kcfg_LanguageComboBox->setEditable(false);
930 QStringList LogoLanguageList = Settings::logoLanguageList();
931 // Add the full language names to the items
932 for ( QStringList::Iterator it = LogoLanguageList.begin(); it != LogoLanguageList.end(); ++it ) {
933 *it = KGlobal::locale()->twoAlphaToLanguageName( (*it).left(2) ) + " (" + *it + ")";
935 kcfg_LanguageComboBox->insertStringList(LogoLanguageList);
937 LanguageLabel = new QLabel(kcfg_LanguageComboBox, i18n("&Select the language for the Logo commands:"), groupBox1);
938 layout4->addWidget( LanguageLabel );
939 layout4->addWidget( kcfg_LanguageComboBox );
940 LanguageLabel->setBuddy( kcfg_LanguageComboBox );
942 groupBox1Layout->addLayout( layout4, 0, 0 );
943 languageLayout->addWidget( groupBox1, 0, 0 );
944 language->resize( QSize(373, 80).expandedTo(minimumSizeHint()) );
946 dialog->addPage( language, i18n("Language"), "locale", i18n("Language Settings") );
948 // When the user clicks OK or Apply we want to update our settings.
949 connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotUpdateSettings() ) );
951 // Display the dialog is there where errors.
952 dialog->setInitialSize( QSize(550, 300) );
953 dialog->show();
956 void MainWindow::slotUpdateSettings()
958 // get the selected language as a language code
959 QString selectedLogoLanguage = kcfg_LanguageComboBox->currentText().section( "(", -1, -1 ).remove(")");
960 // update the settings
961 Settings::setLogoLanguage( selectedLogoLanguage );
962 Settings::setLanguageComboBox( kcfg_LanguageComboBox->currentItem() );
963 Settings::writeConfig();
964 // set the HLstyle
965 slotSetHighlightstyle( selectedLogoLanguage );
966 // set the statusbar to display the language as just updated
967 // TODO maybe this language name can be more pretty by not using ".left(2)", ie "American English" would than be possible... [if this is possible this should be fixed at more places.]
968 KConfig entry(locate("locale", "all_languages"));
969 entry.setGroup(Settings::logoLanguage().left(2));
970 slotStatusBar(i18n("Command language: %1").arg( entry.readEntry("Name") ), IDS_LANG);
972 delete translate; // to update the currently used language
973 translate = new Translate();
976 void MainWindow::readConfig(KConfig *config)
978 config->setGroup("General Options");
979 m_recentFiles->loadEntries(config, "Recent Files");
980 KConfig entry(locate("locale", "all_languages"));
981 entry.setGroup(Settings::logoLanguage().left(2));
982 slotStatusBar(i18n("Command language: %1").arg( entry.readEntry("Name") ), IDS_LANG);
985 void MainWindow::slotSettingsHelp()
987 kapp->invokeHelp("settings-configure", "", "");
990 // END
994 // BEGIN help related functions
996 void MainWindow::slotContextHelp()
998 // somehow the 'anchor' parameter of invokeHelp is not working correcctly (yet)
1000 // this is/was appearently a bug in KHTML that Waldo Bastian kindly and quikly fixed.
1002 // Ooh... and we also want a DCOPmethod to close the sidebar since it over-informs...
1003 // Ooh3... we want fancy help (using KHTML) @ errormessage dialog
1004 // Ooh4... And we might also have to keep track of the KHelpCenter instance we open so
1005 // we will not end up with loads of them
1008 // IDEA!!: put all the keyword in a i18n("...") this will make translating them a lot easier!!!
1009 // MAYBE THIS IS ALSO POSSIBLE FOR THE INTERPRETER!!!!
1010 // this should be discussed with translators (and please think of the highlight-themes too (since
1011 // right now thay can probably be translated with a simple perl script
1013 kdDebug(0)<<"help requested on this text: "<<helpKeyword<<endl;
1015 QString helpWord;
1016 if ( helpKeyword == i18n("<no keyword>") )
1018 KMessageBox::information( this, i18n("There is currently no text under the cursor to get help on."), i18n("Nothing Under Cursor") );
1019 return;
1021 else if ( helpKeyword == i18n("<number>") ) helpWord = "number";
1022 else if ( helpKeyword == i18n("<string>") ) helpWord = "string";
1023 else if ( helpKeyword == i18n("<assignment>") ) helpWord = "assignment";
1024 else if ( helpKeyword == i18n("<question>") ) helpWord = "questions";
1025 else if ( helpKeyword == i18n("<name>") ) helpWord = "name";
1026 else if ( helpKeyword == i18n("<comment>") ) helpWord = "comment";
1027 else
1029 // make lowercase
1030 helpWord = helpKeyword.lower();
1031 // if the key is an alias translate that alias to a key
1032 if ( !translate->alias2key(helpKeyword).isEmpty() ) helpWord = translate->alias2key(helpKeyword);
1033 else if ( !translate->name2key (helpKeyword).isEmpty() ) helpWord = translate->name2key (helpKeyword);
1035 // at this point helpKeyword should contain a valid
1036 // section/anchor-id that can be used found in the doc
1037 // if not... who cares :)... well let's put an debugMsg for that occasion:
1038 else kdDebug(0)<<"Error in MainWindow::slotContextHelp: could not translate \""<<helpKeyword<<"\""<<endl;
1041 kdDebug(0)<<"trying to open a help page using this keyword: "<<helpWord<<endl;
1043 kapp->invokeHelp(helpWord, "", "");
1045 QString help2statusBar;
1046 if ( helpKeyword.startsWith("<") ) help2statusBar = helpKeyword;
1047 else help2statusBar = i18n("\"%1\"").arg(helpKeyword);
1048 slotStatusBar(i18n("Displaying help on %1").arg(help2statusBar), IDS_STATUS);
1051 void MainWindow::slotContextHelpUpdate()
1053 uint row, col;
1054 dynamic_cast<KTextEditor::ViewCursorInterface*>(editor)->cursorPositionReal(&row, &col);
1055 QString line = dynamic_cast<KTextEditor::EditInterface*>(doc)->textLine(row);
1057 // two shortcuts so we dont do all the CPU intensive regexp stuff when it not needed
1058 if ( line.stripWhiteSpace().startsWith("#") )
1060 helpKeyword = i18n("<comment>");
1061 ContextHelp->setText( i18n("Help on: %1").arg(helpKeyword) );
1062 return;
1064 if ( line.stripWhiteSpace().isEmpty() || line.mid(col-1,2).stripWhiteSpace().isEmpty() )
1066 helpKeyword = i18n("<no keyword>");
1067 ContextHelp->setText( i18n("Help on: %1").arg(helpKeyword) );
1068 return;
1071 int start, length, pos;
1073 pos = 0;
1074 if ( line.contains('"') )
1076 QRegExp delimitedStrings("(\"[^\"\\\\\\r\\n]*(\\\\.[^\"\\\\\\r\\n]*)*\")");
1077 while ( delimitedStrings.search(line, pos) != -1 )
1079 // kdDebug(0)<<"stringsearch: >>"<<pos<<"<<"<<endl;
1080 start = delimitedStrings.search(line, pos);
1081 length = delimitedStrings.matchedLength(); // the length of the last matched string, or -1 if there was no match
1082 if ( col >= (uint)start && col < (uint)(start+length) )
1084 helpKeyword = i18n("<string>");
1085 ContextHelp->setText( i18n("Help on: %1").arg(helpKeyword) );
1086 return;
1088 pos += (length <= 0 ? 1 : length);
1093 // except for "strings" this regexp effectively separates logo code in 'words' (in a very broad meaning)
1094 QRegExp splitter("(([^ ,+\\-*/()=<>[!]|(?!==|<=|>=|!=))*)|(([ ,+\\-*/()=<>[!]|==|<=|>=|!=))");
1096 pos = 0;
1097 while (splitter.search(line, pos) != -1)
1099 start = splitter.search(line, pos);
1100 length = splitter.matchedLength();
1101 if ( col < (uint)start ) break;
1102 if ( col >= (uint)start && col < (uint)(start+length) )
1104 QString cursorWord = line.mid( (uint)start, (uint)length );
1105 // kdDebug(0)<<"splitsearch: >>"<<cursorWord<<"<<"<<endl;
1107 if ( cursorWord.stripWhiteSpace().isEmpty() ) helpKeyword = i18n("<no keyword>");
1109 else if ( !translate->name2key( cursorWord.lower() ).isEmpty() ||
1110 !translate->alias2key( cursorWord.lower() ).isEmpty() ) helpKeyword = cursorWord;
1112 else if ( cursorWord.find( QRegExp("[\\d.]+") ) == 0 ) helpKeyword = i18n("<number>");
1114 else if ( cursorWord.find( QRegExp("[+\\-*/\\(\\)]") ) == 0 ) helpKeyword = i18n("<math>");
1116 else if ( cursorWord == QString("=") ) helpKeyword = i18n("<assignment>");
1118 else if ( cursorWord.find( QRegExp("==|<|>|<=|>=|!=") ) == 0 ) helpKeyword = i18n("<question>");
1120 // if we come here we either have an ID of some sort or an error
1121 // all we can do is try to catch some errors (TODO) and then...
1123 else helpKeyword = i18n("<name>");
1125 ContextHelp->setText( i18n("Help on: %1").arg(helpKeyword) );
1126 return;
1128 pos += (length <= 0 ? 1 : length); // the pos had to be increased with at least one
1131 // we allready cached some in the beginning of this method; yet its still needed as fall-through
1132 helpKeyword = i18n("<no keyword>");
1133 ContextHelp->setText( i18n("Help on: %1").arg(helpKeyword) );
1136 // END
1140 // BEGIN misc. functions
1142 void MainWindow::slotColorPicker()
1144 // in the constructor picker is initialised as 0
1145 // if picker is 0 when this funktion is called a colorpickerdialog is created and connected
1146 if (picker == 0)
1148 picker = new ColorPicker(this);
1149 if(picker == 0) return; // safety
1150 connect( picker, SIGNAL( visible(bool) ), colorpicker, SLOT( setChecked(bool) ) );
1151 connect( picker, SIGNAL( ColorCode(QString) ), this, SLOT( slotInsertText(QString) ) );
1153 // if picker is not 0, there is a colorpickerdialog which only needs to be shown OR hidden
1154 if ( picker->isHidden() )
1156 picker->show();
1157 colorpicker->setChecked(true);
1159 else
1161 picker->hide();
1162 colorpicker->setChecked(false);
1166 void MainWindow::slotUpdateCanvas()
1168 // fixes a non updateing bug
1169 // I tried doing this by connecting Canvas's resized to baseWidget's update...
1170 // but i had no luck :( ... this worked though :)
1171 canvasView->hide();
1172 canvasView->show();
1175 // END
1178 #include "kturtle.moc"