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