vlp-27 Removed some unused code. Added undo&redo to menu. Removed maximum window...
[vlp.git] / src / edit / editor.cpp
1 #include <unistd.h>
2 #include <QtCore/QTextStream>
3 #include <QtGui/QApplication>
4 #include <QtGui/QMenuBar>
5 #include <QtGui/QFileDialog>
6 #include <QtGui/QColor>
7 #include <QtGui/QPalette>
8 #include <QtGui/QCloseEvent>
9 #include <QtGui/QTextDocument>
10 #include <QtGui/QMainWindow>
11 #include <QtGui/QStatusBar>
12 #include <QtGui/QCheckBox>
13 #include <QtGui/QVBoxLayout>
14
15 #include "editor.h"
16 #include "my_edit.h"
17
18 #define TYPENUM 5
19
20 /**
21  * @attention Currently not in use
22  */
23 char *UnitTypes[TYPENUM] = {
24         "CLASS",
25         "PROCEDURE",
26         "FUNCTION",
27         "PROCESS",
28         "COROUTINE"
29 };
30
31 /**
32  * My_Edit constructor. Initializes and sets variables of Multiline editor
33  * widget.
34  * @param parent Parent widget of this widget. If set, this widget becomes a 
35  *               child window inside parent. If not set this widget becomes a
36  *               top level window. Default: NULL
37  */
38 My_Edit::My_Edit(QWidget *parent = NULL)
39         : QTextEdit(parent)
40 {
41 }
42
43 /**
44  * @copydoc QWidget::keyPressEvent(QKeyEvent*)
45  */
46 void My_Edit::keyPressEvent(QKeyEvent *ev)
47 {
48         QTextEdit::keyPressEvent(ev);
49         emit cursorMove();
50 }
51
52 /**
53  * Event invoked on program close.
54  * @copydoc QWidget::closeEvent(QCloseEvent*)
55  */
56 void Editor::closeEvent(QCloseEvent * e) {
57         e->accept();
58 }
59
60 /**
61  * Editor constructor. Initializes and sets variables of Loglan Editor.
62  * @param hdir Home directory of program (specified in configuration file)
63  * @param parent Parent widget of this widget. If set, this widget becomes a 
64  *               child window inside parent. If not set this widget becomes a
65  *               top level window. Default: NULL
66  */
67 Editor::Editor(char *hdir, QWidget * parent)
68         : QMainWindow(parent)
69 {
70         setupUi(this);
71
72         strcpy(HomeDir, hdir);
73         find_text = "";
74         sensitive = FALSE;
75
76         /*    m->insertItem( "&LOGLAN ", loglan );*/
77
78         connect(actionQuit, SIGNAL(triggered()), this, SLOT(close()));
79
80         /* comp->insertItem("Compile ", this, SLOT(cmp()), CTRL + Key_C);*/
81         /* comp->insertItem("Gen ", this, SLOT(gen()), CTRL + Key_G);*/
82         /* comp->insertItem("Compile & Gen ", this, SLOT(comp_all()));*/
83
84         /* loglan->insertItem( "Program structure", this, SLOT(log_prog()));*/
85         /* loglan->insertItem( "Unit structure", this, SLOT(log_unit()));*/
86         
87         connect(e, SIGNAL(cursorMove()), this, SLOT(updateline()));
88         connect(actionUndo, SIGNAL(triggered()), e, SLOT(undo()));
89         connect(actionRedo, SIGNAL(triggered()), e, SLOT(redo()));
90         connect(actionCopy, SIGNAL(triggered()), e, SLOT(copy()));
91         connect(actionPaste, SIGNAL(triggered()), e, SLOT(paste()));
92         connect(actionCut, SIGNAL(triggered()), e, SLOT(cut()));
93         connect(actionClear_all, SIGNAL(triggered()), e, SLOT(clear()));
94
95         compiler_path.sprintf("%s/%s", HomeDir, "compile/logcomp");
96         gen_path.sprintf("%s/%s", HomeDir, "compile/gen");
97         file_path.sprintf("%s", HomeDir);
98
99         position = new QLabel();
100         statusBar()->addPermanentWidget(position);
101 }
102
103 /**
104  * Editor destructor
105  */
106 Editor::~Editor()
107 {
108 }
109
110 /**
111  * Displays line:column position of cursor
112  */
113 void Editor::updateline()
114 {
115         char pom[255];
116         int cx;
117         int cy;
118
119         cx = e->textCursor().blockNumber();
120         cy = e->textCursor().columnNumber();
121         sprintf(pom,"%d:%d ", cx, cy);
122         position->setText(pom);
123 }
124
125 /**
126  * Displays additional window 
127  */
128 void Editor::on_actionOpen_triggered()
129 {
130         QString fn = QFileDialog::getOpenFileName(this, "Load file", file_path, "*.log");
131         if (!fn.isEmpty())
132                 load(fn.toAscii().data());
133 }
134
135 /**
136  * Loads given file content to the editor.
137  * @param fileName Filename of file which will be read.
138  */
139 void Editor::load(const char *fileName)
140 {
141         fname.sprintf("%s", fileName);
142
143         QFile f(fileName);
144         if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
145                 return;
146
147 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
148         e->setAutoUpdate(FALSE);
149 */
150         e->clear();
151
152         QTextStream t(&f);
153         while (!t.atEnd()) {
154                 QString s = t.readLine();
155                 e->append(s);
156         }
157         f.close();
158
159 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
160         e->setAutoUpdate(TRUE);
161 */
162         e->repaint();
163         setWindowTitle(fileName);
164 }
165
166 /**
167  * Saves editor content to the file.
168  * If content has been read from file, it is written to this file. Otherwise
169  * dialog is shown to save content to the specified by user, file.
170  */
171 void Editor::on_actionSave_triggered()
172 {
173         if (fname.isEmpty()) {
174                 QString fn = QFileDialog::getSaveFileName(this, "Save file", 
175                                                         file_path, "*.log");
176                 if (!fn.isEmpty()) {
177                         fname.sprintf("%s", fn.toAscii().data());
178                         save(fn.toAscii().data());
179                 }
180         } else {
181                 save(fname.toAscii().data());
182         }
183         setWindowTitle(fname);
184 }
185
186 /**
187  * Saves editor content to the file.
188  * Forces saving editor content to the new file. Special dialog is shown for
189  * that purpose.
190  */
191 void Editor::on_actionSave_as_triggered()
192 {
193         QString fn = QFileDialog::getSaveFileName(this, "Save file as",
194                                                         file_path, "*.log");
195         if (!fn.isEmpty()) {
196                 fname.sprintf("%s", fn.toAscii().data());
197                 save(fn.toAscii().data());
198         }
199         setWindowTitle(fname);
200 }
201
202 /**
203  * Saves editor content to the given filename.
204  * @param fileName File name of the file where content should be saved.
205  */
206 void Editor::save(const char *fileName)
207 {
208         QFile f(fileName);
209         if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
210                 return;
211         f.reset();
212         f.write(e->toPlainText().toAscii().data(), e->toPlainText().length());
213         f.close();
214 }
215
216 /**
217  * Empties editor content.
218  */
219 void Editor::on_actionNew_triggered()
220 {
221         e->clear();
222         fname.sprintf("%s", "");
223 }
224
225 /**
226  * @attention Currently not in use
227  */
228 //void Editor::print()
229 //{
230 //}
231
232 /**
233  * @attention Currently not in use.
234  * 
235  * Saves and compiles code.
236  */
237 void Editor::on_actionCompile_triggered()
238 {
239         on_actionSave_triggered();
240         compile(COMP_MODE);
241 }
242
243 /**
244  * @attention Currently not in use.
245  * 
246  * Generates program.
247  */
248 void Editor::gen()
249 {
250         compile(GEN_MODE);
251 }
252
253 /**
254  * @attention Currently not in use.
255  * 
256  * Saves, compiles and generates code.
257  */
258 void Editor::comp_all()
259 {
260         on_actionSave_triggered();
261         compile(ALL_MODE);
262 }
263
264 /**
265  * Invokes compiler in the giving mode.
266  * @param mode Mode of compilation. Possible values:
267  *             - COMP_MODE - compilation mode
268  *             - GEN_MODE - program generation mode
269  *             - ALL_MODE - compilation & generation mode.
270  */
271 void Editor::compile(int mode)
272 {
273         char cmd[255];
274 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
275         msg->setAutoUpdate(FALSE);
276 */
277         msg->setReadOnly(FALSE);
278         msg->clear();
279         msg->repaint();
280
281         /*i = fname.find('.');*/
282         /* if (i>=0) {*/
283
284         /*  fn.truncate(i);*/
285         switch(mode) {
286         case COMP_MODE:
287                 sprintf(cmd, "%s %s > comp_data!", compiler_path.toAscii().data(),
288                                                         fname.toAscii().data());
289                 break;
290         case GEN_MODE:
291                 sprintf(cmd, "%s %s > comp_data!", gen_path.toAscii().data(),
292                                                         fname.toAscii().data());
293                 break;
294         case ALL_MODE:
295                 sprintf(cmd, "%s %s > comp_data!", compiler_path.toAscii().data(),
296                                                         fname.toAscii().data());
297                 system(cmd);
298                 sprintf(cmd, "%s %s >> comp_data!", gen_path.toAscii().data(),
299                                                         fname.toAscii().data());
300         break;
301         }
302
303         system(cmd);
304         QFile f("comp_data!");
305         if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
306                 return;
307
308         QTextStream t(&f);
309         while (!t.atEnd()) {
310                 QString s = t.readLine();
311                 msg->append(s);
312         }
313         f.close();
314
315         msg->setReadOnly(TRUE);
316
317 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
318         msg->setAutoUpdate(TRUE);
319 */
320         msg->repaint();
321         unlink("comp_data!");
322         /*}*/
323 }
324
325 /**
326  * Displays window with editor properties
327  */
328 void Editor::on_actionProperties_triggered()
329 {
330         QDialog dlg(this, Qt::Dialog);
331
332         QLineEdit *files;
333         files = new QLineEdit(&dlg);
334         files->setGeometry(130, 20, 250, 30);
335         files->setText(file_path);
336         files->setMaxLength(32767);
337         files->setEchoMode(QLineEdit::Normal);
338         files->setFrame(TRUE);
339
340         QLabel *tmpQLabel;
341         tmpQLabel = new QLabel("Path to files:", &dlg);
342         tmpQLabel->setGeometry(10, 20, 100, 30);
343         tmpQLabel->setAlignment(Qt::AlignLeft);
344         tmpQLabel->setMargin(-1);
345
346         tmpQLabel = new QLabel("Path to compiler:", &dlg);
347         tmpQLabel->setGeometry(10, 60, 100, 30);
348         tmpQLabel->setAlignment(Qt::AlignLeft);
349         tmpQLabel->setMargin(-1);
350
351         /*
352         tmpQLabel = new QLabel(&dlg, "Label_3");
353         tmpQLabel->setGeometry(10, 100, 100, 30);
354         tmpQLabel->setText("Path to gen:");
355         tmpQLabel->setAlignment(289);
356         tmpQLabel->setMargin(-1);
357         */
358
359         QLineEdit *compp;
360         compp = new QLineEdit(compiler_path, &dlg);
361         compp->setGeometry(130, 60, 250, 30);
362         compp->setMaxLength(32767);
363         compp->setEchoMode(QLineEdit::Normal);
364         compp->setFrame(TRUE);
365
366         /*
367         QLineEdit* genp;
368         genp = new QLineEdit(&dlg, "g_path");
369         genp->setGeometry(130, 100, 250, 30);
370         genp->setText(gen_path.data());
371         genp->setMaxLength(32767);
372         genp->setEchoMode(QLineEdit::Normal);
373         genp->setFrame(TRUE);
374         */
375
376         QPushButton* tmpQPushButton;
377         tmpQPushButton = new QPushButton("Ok", &dlg);
378         tmpQPushButton->setGeometry(90, 100, 70, 30);
379         tmpQPushButton->setAutoRepeat(FALSE);
380 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
381         tmpQPushButton->setAutoResize(FALSE);
382 */
383         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
384
385         tmpQPushButton = new QPushButton("Cancel", &dlg);
386         tmpQPushButton->setGeometry(180, 100, 70, 30);
387         tmpQPushButton->setAutoRepeat(FALSE);
388 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
389         tmpQPushButton->setAutoResize(FALSE);
390 */
391         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
392         dlg.resize(400, 140);
393
394         if (dlg.exec()) {
395                 compiler_path.sprintf("%s", compp->text().toAscii().data());
396                 /* gen_path.sprintf("%s",genp->text()); */
397                 file_path.sprintf("%s", files->text().toAscii().data());
398         };
399 }
400
401 /**
402  * @attention Currently not in use
403  */
404 void Editor::log_unit()
405 {
406         /*
407         Code commented during Qt4 migration.
408         Code is not used, so there is no rush with this...
409         */
410         /*
411         QString txt;
412         QDialog dlg(this, Qt::Dialog);
413         int cx, cy, i;
414         char uname[255];
415
416         QLineEdit* files;
417         files = new QLineEdit(&dlg, "f_path");
418         files->setGeometry(130, 20, 250, 30);
419         files->setText("");
420         files->setMaxLength(32767);
421         files->setEchoMode(QLineEdit::Normal);
422         files->setFrame(TRUE);
423
424         QLabel* tmpQLabel;
425         tmpQLabel = new QLabel(&dlg, "Label_1");
426         tmpQLabel->setGeometry(10, 20, 100, 30);
427         tmpQLabel->setText("Unit name:");
428         tmpQLabel->setAlignment(289);
429         tmpQLabel->setMargin(-1);
430
431         QPushButton* tmpQPushButton;
432         tmpQPushButton = new QPushButton(&dlg, "OkBtn");
433         tmpQPushButton->setGeometry(40, 170, 70, 30);
434         tmpQPushButton->setText("Ok");
435         tmpQPushButton->setAutoRepeat(FALSE);
436         tmpQPushButton->setAutoResize(FALSE);
437         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
438
439         tmpQPushButton = new QPushButton(&dlg, "CancelBtn");
440         tmpQPushButton->setGeometry(130, 170, 100, 30);
441         tmpQPushButton->setText("Cancel");
442         tmpQPushButton->setAutoRepeat(FALSE);
443         tmpQPushButton->setAutoResize(FALSE);
444         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
445
446         tmpQLabel = new QLabel(&dlg, "Label_1");
447         tmpQLabel->setGeometry(10, 50, 100, 60);
448         tmpQLabel->setText("Unit type:");
449
450         QListBox lst(&dlg, "type");
451         for(i = 0; i < TYPENUM; i++) {
452                 lst.insertItem(UnitTypes[i]);
453         }
454         lst.setGeometry(130, 60, 180, 80);
455         lst.setCurrentItem(0);
456
457         if (dlg.exec()) {
458                 strcpy(uname, files->text());
459                 e->getCursorPosition(&cx, &cy);
460
461                 txt.sprintf("UNIT %s : %s( <params> );\nBEGIN\n\nEND %s;",
462                         uname, lst.text(lst.currentItem()).ascii(), uname);
463                 e->insertAt(txt, cx, cy);
464         }
465         */
466 }
467
468 /**
469  * @attention Currently not in use
470  */
471 void Editor::log_prog()
472 {
473         /*
474         Code commented during Qt4 migration.
475         Code is not used, so there is no rush with this...
476         */
477         /*
478         QString txt;
479         QDialog dlg(this, "unit", TRUE);
480         int cx, cy;
481         char uname[255];
482
483         QLineEdit *files;
484         files = new QLineEdit(&dlg, "f_path");
485         files->setGeometry(130, 20, 250, 30);
486         files->setText("");
487         files->setMaxLength(32767);
488         files->setEchoMode(QLineEdit::Normal);
489         files->setFrame(TRUE);
490
491         QLabel *tmpQLabel;
492         tmpQLabel = new QLabel(&dlg, "Label_1");
493         tmpQLabel->setGeometry(10, 20, 100, 30);
494         tmpQLabel->setText("Program name:");
495
496         QPushButton* tmpQPushButton;
497         tmpQPushButton = new QPushButton(&dlg, "OkBtn");
498         tmpQPushButton->setGeometry(40, 70, 70, 30);
499         tmpQPushButton->setText("Ok");
500         tmpQPushButton->setAutoRepeat(FALSE);
501         tmpQPushButton->setAutoResize(FALSE);
502         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
503
504         tmpQPushButton = new QPushButton(&dlg, "CancelBtn");
505         tmpQPushButton->setGeometry(130, 70, 100, 30);
506         tmpQPushButton->setText("Cancel");
507         tmpQPushButton->setAutoRepeat(FALSE);
508         tmpQPushButton->setAutoResize(FALSE);
509         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
510
511         if (dlg.exec()) {
512                 strcpy(uname, files->text());
513                 e->getCursorPosition(&cx, &cy);
514
515                 txt.sprintf("PROGRAM %s\n\nBEGIN\n\nEND ", uname);
516                 e->insertAt(txt, cx, cy);
517         }
518         */
519 }
520
521 /**
522  * Searches for given text in editor content.
523  * Displays window to set search parameters. If text is found sets cursor
524  * position on it.
525  */
526 void Editor::on_actionFind_triggered()
527 {
528         QDialog dlg(this, Qt::Dialog);
529         QString *txt;
530         int res, line, pom;
531
532         QLineEdit *tmpQLineEdit;
533         tmpQLineEdit = new QLineEdit("", &dlg);
534         tmpQLineEdit->setGeometry(60, 10, 180, 30);
535
536         QLabel *tmpQLabel;
537         tmpQLabel = new QLabel(&dlg);
538         tmpQLabel->setGeometry(10, 10, 50, 30);
539
540         tmpQLabel->setText("Text:");
541
542         QCheckBox *tmpQRadioButton;
543         tmpQRadioButton = new QCheckBox("Case sensitive", &dlg);
544         tmpQRadioButton->setGeometry(70, 50, 150, 30);
545         tmpQRadioButton->setAutoRepeat(FALSE);
546
547 /*TODO: Does not exists in Qt4. Use layout and set the size policy (https://qt-project.org/forums/viewthread/2112)
548         tmpQRadioButton->setAutoResize(FALSE);
549 */
550
551         QPushButton *okbtn, *cbtn;
552         okbtn = new QPushButton("Find", &dlg);
553         okbtn->setGeometry(260, 10, 100, 30);
554         okbtn->setDefault(TRUE);
555         connect(okbtn,SIGNAL(clicked()), &dlg, SLOT(accept()));
556
557         cbtn = new QPushButton("Close", &dlg);
558         cbtn->setGeometry(260, 50, 100, 30);
559         connect(cbtn, SIGNAL(clicked()), &dlg, SLOT(reject()));
560         dlg.resize(380, 90);
561
562         if (dlg.exec()) {
563                 sensitive = tmpQRadioButton->isChecked();
564                 find_text = tmpQLineEdit->text();
565                 
566                 QTextDocument::FindFlags flags = 0;
567                 
568                 if (sensitive) {
569                         flags |= QTextDocument::FindCaseSensitively;
570                 }
571                 e->find(find_text, flags);
572         }
573 }
574
575 /**
576  * Searches for next occurence of given text in editor content.
577  * Displays window to set search parameters. If text is found sets cursor
578  * position on it.
579  */
580 void Editor::on_actionFind_next_triggered()
581 {
582         if (!find_text.isEmpty()) {
583                 QTextDocument::FindFlags flags = 0;
584                 
585                 if (sensitive) {
586                         flags |= QTextDocument::FindCaseSensitively;
587                 }
588                 e->find(find_text, flags);
589         }
590 }
591
592 /**
593  * Program main function.
594  * argv[1] is mandatory and should be a path to the home directory of
595  * application (same as in configuration file).
596  * @param argc Number of program arguments
597  * @param argv Program arguments
598  */
599 int main(int argc, char **argv)
600 {
601         QApplication app(argc, argv);
602
603         Editor editor(argv[1], NULL);
604         editor.show();
605
606         return app.exec();
607 }
608