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