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