Restore functionality of loglan helpers
[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 #include <QtGui/QListWidget>
15 #include <QtGui/QListWidgetItem>
16
17 #include "editor.h"
18
19 #define TYPENUM 5
20
21 /**
22  * @attention Currently not in use
23  */
24 char *UnitTypes[TYPENUM] = {
25         "CLASS",
26         "PROCEDURE",
27         "FUNCTION",
28         "PROCESS",
29         "COROUTINE"
30 };
31
32 /**
33  * Editor constructor. Initializes and sets variables of Loglan Editor.
34  *
35  * @param argc command line argc parameter
36  * @param argv command line argv parameter
37  */
38 Editor::Editor(int argc, char **argv)
39 {
40         setupUi(this);
41
42         if (argc > 1) {
43                 strcpy(HomeDir, argv[1]);
44         }
45
46         find_text = "";
47         sensitive = FALSE;
48
49         compiler_path.sprintf("%s/%s", HomeDir, "compile/logcomp");
50         gen_path.sprintf("%s/%s", HomeDir, "compile/gen");
51         file_path.sprintf("%s", HomeDir);
52         
53         
54         connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(on_editor_cursorPositionChanged()));
55 }
56
57 /**
58  * Editor destructor
59  */
60 Editor::~Editor()
61 {
62 }
63
64 /**
65  * Displays line:column position of cursor
66  */
67 void Editor::on_editor_cursorPositionChanged()
68 {
69         QString position;
70         int cx;
71         int cy;
72
73         cx = editor->textCursor().blockNumber();
74         cy = editor->textCursor().columnNumber();
75         position.sprintf("%d:%d", cx, cy);
76
77         statusBar()->showMessage(position);
78 }
79
80 /**
81  * Loads given file content to the editor.
82  *
83  * @param fileName Filename of file which will be read.
84  */
85 void Editor::load(const char *fileName)
86 {
87         fname.sprintf("%s", fileName);
88
89         QFile file(fileName);
90         if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
91                 return;
92
93         editor->clear();
94
95         QTextStream textStream(&file);
96         while (!file.atEnd()) {
97                 editor->append(textStream.readLine());
98         }
99
100         file.close();
101
102         editor->repaint();
103         setWindowTitle(fileName);
104 }
105
106 /**
107  * Saves editor content to the given filename.
108  * @param fileName File name of the file where content should be saved.
109  */
110 void Editor::save(const char *fileName)
111 {
112         QFile file(fileName);
113         if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
114                 return;
115
116         file.reset();
117         file.write(editor->toPlainText().toAscii().data(), editor->toPlainText().length());
118         file.close();
119 }
120
121 /**
122  * Invokes compiler in the giving mode.
123  * @param mode Mode of compilation. Possible values:
124  *             - COMP_MODE - compilation mode
125  *             - GEN_MODE - program generation mode
126  *             - ALL_MODE - compilation & generation mode.
127  */
128 void Editor::compile(int mode)
129 {
130         char cmd[255];
131         messages->setReadOnly(FALSE);
132         messages->clear();
133         messages->repaint();
134
135         /*i = fname.find('.');*/
136         /* if (i>=0) {*/
137
138         /*  fn.truncate(i);*/
139         switch(mode) {
140         case COMP_MODE:
141                 sprintf(cmd, "%s %s > comp_data!", compiler_path.toAscii().data(),
142                                                         fname.toAscii().data());
143                 break;
144         case GEN_MODE:
145                 sprintf(cmd, "%s %s > comp_data!", gen_path.toAscii().data(),
146                                                         fname.toAscii().data());
147                 break;
148         case ALL_MODE:
149                 sprintf(cmd, "%s %s > comp_data!", compiler_path.toAscii().data(),
150                                                         fname.toAscii().data());
151                 system(cmd);
152                 sprintf(cmd, "%s %s >> comp_data!", gen_path.toAscii().data(),
153                                                         fname.toAscii().data());
154         break;
155         }
156
157         system(cmd);
158         QFile f("comp_data!");
159         if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
160                 return;
161
162         QTextStream t(&f);
163         while (!t.atEnd()) {
164                 QString s = t.readLine();
165                 messages->append(s);
166         }
167         f.close();
168
169         messages->setReadOnly(TRUE);
170
171         messages->repaint();
172         unlink("comp_data!");
173         /*}*/
174 }
175
176 /**
177  * Empties editor content.
178  */
179 void Editor::on_actionNew_triggered()
180 {
181         editor->clear();
182         fname.sprintf("%s", "");}
183
184 /**
185  * Displays additional window 
186  */
187 void Editor::on_actionOpen_triggered()
188 {
189         QString fn = QFileDialog::getOpenFileName(this, "Load file", file_path, "*.log");
190         if (!fn.isEmpty())
191                 load(fn.toAscii().data());
192 }
193
194 /**
195  * Saves editor content to the file.
196  * If content has been read from file, it is written to this file. Otherwise
197  * dialog is shown to save content to the specified by user, file.
198  */
199 void Editor::on_actionSave_triggered()
200 {
201         if (fname.isEmpty()) {
202                 QString fn = QFileDialog::getSaveFileName(this, "Save file", 
203                                                         file_path, "*.log");
204                 if (!fn.isEmpty()) {
205                         fname.sprintf("%s", fn.toAscii().data());
206                         save(fn.toAscii().data());
207                 }
208         } else {
209                 save(fname.toAscii().data());
210         }
211         setWindowTitle(fname);
212 }
213
214 /**
215  * Saves editor content to the file.
216  * Forces saving editor content to the new file. Special dialog is shown for
217  * that purpose.
218  */
219 void Editor::on_actionSave_as_triggered()
220 {
221         QString fn = QFileDialog::getSaveFileName(this, "Save file as",
222                                                         file_path, "*.log");
223         if (!fn.isEmpty()) {
224                 fname.sprintf("%s", fn.toAscii().data());
225                 save(fn.toAscii().data());
226         }
227         setWindowTitle(fname);
228 }
229 void Editor::on_actionQuit_triggered()
230 {
231         QApplication::instance()->quit();
232 }
233 void Editor::on_actionCopy_triggered()
234 {
235 }
236 void Editor::on_actionPaste_triggered()
237 {
238 }
239 void Editor::on_actionCut_triggered()
240 {
241 }
242 void Editor::on_actionClear_all_triggered()
243 {
244 }
245
246 /**
247  * Searches for given text in editor content.
248  * Displays window to set search parameters. If text is found sets cursor
249  * position on it.
250  */
251 void Editor::on_actionFind_triggered()
252 {
253         QDialog dlg(this, Qt::Dialog);
254
255         QLineEdit *tmpQLineEdit;
256         tmpQLineEdit = new QLineEdit("", &dlg);
257         tmpQLineEdit->setGeometry(60, 10, 180, 30);
258
259         QLabel *tmpQLabel;
260         tmpQLabel = new QLabel(&dlg);
261         tmpQLabel->setGeometry(10, 10, 50, 30);
262
263         tmpQLabel->setText("Text:");
264
265         QCheckBox *tmpQRadioButton;
266         tmpQRadioButton = new QCheckBox("Case sensitive", &dlg);
267         tmpQRadioButton->setGeometry(70, 50, 150, 30);
268         tmpQRadioButton->setAutoRepeat(FALSE);
269
270         QPushButton *okbtn, *cbtn;
271         okbtn = new QPushButton("Find", &dlg);
272         okbtn->setGeometry(260, 10, 100, 30);
273         okbtn->setDefault(TRUE);
274         connect(okbtn,SIGNAL(clicked()), &dlg, SLOT(accept()));
275
276         cbtn = new QPushButton("Close", &dlg);
277         cbtn->setGeometry(260, 50, 100, 30);
278         connect(cbtn, SIGNAL(clicked()), &dlg, SLOT(reject()));
279
280         dlg.resize(380, 90);
281
282         if (dlg.exec()) {
283                 sensitive = tmpQRadioButton->isChecked();
284                 find_text = tmpQLineEdit->text();
285                 
286                 QTextDocument::FindFlags flags = 0;
287                 
288                 if (sensitive) {
289                         flags |= QTextDocument::FindCaseSensitively;
290                 }
291                 editor->find(find_text, flags);
292         }
293 }
294
295 /**
296  * Searches for next occurence of given text in editor content.
297  * Displays window to set search parameters. If text is found sets cursor
298  * position on it.
299  */
300 void Editor::on_actionFind_Next_triggered()
301 {
302         if (!find_text.isEmpty()) {
303                 QTextDocument::FindFlags flags = 0;
304                 
305                 if (sensitive) {
306                         flags |= QTextDocument::FindCaseSensitively;
307                 }
308                 editor->find(find_text, flags);
309         }
310 }
311
312 /**
313  * Displays window with editor properties
314  */
315 void Editor::on_actionPreferences_triggered()
316 {
317         QDialog dlg(this, Qt::Dialog);
318
319         QLineEdit *files;
320         files = new QLineEdit(&dlg);
321         files->setGeometry(130, 20, 250, 30);
322         files->setText(file_path);
323         files->setMaxLength(32767);
324         files->setEchoMode(QLineEdit::Normal);
325         files->setFrame(TRUE);
326
327         QLabel *tmpQLabel;
328         tmpQLabel = new QLabel("Path to files:", &dlg);
329         tmpQLabel->setGeometry(10, 20, 100, 30);
330         tmpQLabel->setAlignment(Qt::AlignLeft);
331         tmpQLabel->setMargin(-1);
332
333         tmpQLabel = new QLabel("Path to compiler:", &dlg);
334         tmpQLabel->setGeometry(10, 60, 100, 30);
335         tmpQLabel->setAlignment(Qt::AlignLeft);
336         tmpQLabel->setMargin(-1);
337
338         /*
339         tmpQLabel = new QLabel(&dlg, "Label_3");
340         tmpQLabel->setGeometry(10, 100, 100, 30);
341         tmpQLabel->setText("Path to gen:");
342         tmpQLabel->setAlignment(289);
343         tmpQLabel->setMargin(-1);
344         */
345
346         QLineEdit *compp;
347         compp = new QLineEdit(compiler_path, &dlg);
348         compp->setGeometry(130, 60, 250, 30);
349         compp->setMaxLength(32767);
350         compp->setEchoMode(QLineEdit::Normal);
351         compp->setFrame(TRUE);
352
353         /*
354         QLineEdit* genp;
355         genp = new QLineEdit(&dlg, "g_path");
356         genp->setGeometry(130, 100, 250, 30);
357         genp->setText(gen_path.data());
358         genp->setMaxLength(32767);
359         genp->setEchoMode(QLineEdit::Normal);
360         genp->setFrame(TRUE);
361         */
362
363         QPushButton* tmpQPushButton;
364         tmpQPushButton = new QPushButton("Ok", &dlg);
365         tmpQPushButton->setGeometry(90, 100, 70, 30);
366         tmpQPushButton->setAutoRepeat(FALSE);
367         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
368
369         tmpQPushButton = new QPushButton("Cancel", &dlg);
370         tmpQPushButton->setGeometry(180, 100, 70, 30);
371         tmpQPushButton->setAutoRepeat(FALSE);
372         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
373
374         dlg.resize(400, 140);
375
376         if (dlg.exec()) {
377                 compiler_path.sprintf("%s", compp->text().toAscii().data());
378                 /* gen_path.sprintf("%s",genp->text()); */
379                 file_path.sprintf("%s", files->text().toAscii().data());
380         };
381 }
382
383 /**
384  * Saves and compiles code.
385  */
386 void Editor::on_actionCompile_triggered()
387 {
388         on_actionSave_triggered();
389         compile(COMP_MODE);
390 }
391
392 /**
393  * Generates program.
394  */
395 void Editor::on_actionGen_triggered()
396 {
397         compile(GEN_MODE);
398 }
399
400 /**
401  * Saves, compiles and generates code.
402  */
403 void Editor::on_actionCompile_Gen_triggered()
404 {
405         on_actionSave_triggered();
406         compile(ALL_MODE);
407 }
408
409 void Editor::on_actionProgram_structure_triggered()
410 {
411         QDialog dlg(this, "unit", TRUE);
412         char uname[255];
413
414         QLineEdit *files;
415         files = new QLineEdit(&dlg, "f_path");
416         files->setGeometry(130, 20, 250, 30);
417         files->setText("");
418         files->setMaxLength(32767);
419         files->setEchoMode(QLineEdit::Normal);
420         files->setFrame(TRUE);
421
422         QLabel *tmpQLabel;
423         tmpQLabel = new QLabel(&dlg);
424         tmpQLabel->setGeometry(10, 20, 100, 30);
425         tmpQLabel->setText("Program name:");
426
427         QPushButton* tmpQPushButton;
428         tmpQPushButton = new QPushButton(&dlg);
429         tmpQPushButton->setGeometry(40, 70, 70, 30);
430         tmpQPushButton->setText("Ok");
431         tmpQPushButton->setAutoRepeat(FALSE);
432         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
433
434         tmpQPushButton = new QPushButton(&dlg);
435         tmpQPushButton->setGeometry(130, 70, 100, 30);
436         tmpQPushButton->setText("Cancel");
437         tmpQPushButton->setAutoRepeat(FALSE);
438         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
439
440         if (dlg.exec()) {
441                 strcpy(uname, files->text());
442
443                 QString txt;
444                 txt.sprintf("PROGRAM %s\n\nBEGIN\n\nEND", uname);
445
446                 editor->textCursor().insertText(txt);
447         }
448 }
449
450 void Editor::on_actionUnit_structure_triggered()
451 {
452         QDialog dlg(this, Qt::Dialog);
453         int i;
454         char uname[255];
455
456         QLineEdit* files;
457         files = new QLineEdit(&dlg, "f_path");
458         files->setGeometry(130, 20, 250, 30);
459         files->setText("");
460         files->setMaxLength(32767);
461         files->setEchoMode(QLineEdit::Normal);
462         files->setFrame(TRUE);
463
464         QLabel* tmpQLabel;
465         tmpQLabel = new QLabel(&dlg);
466         tmpQLabel->setGeometry(10, 20, 100, 30);
467         tmpQLabel->setText("Unit name:");
468         tmpQLabel->setAlignment(289);
469         tmpQLabel->setMargin(-1);
470
471         QPushButton* tmpQPushButton;
472         tmpQPushButton = new QPushButton(&dlg);
473         tmpQPushButton->setGeometry(40, 170, 70, 30);
474         tmpQPushButton->setText("Ok");
475         tmpQPushButton->setAutoRepeat(FALSE);
476         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(accept()));
477
478         tmpQPushButton = new QPushButton(&dlg);
479         tmpQPushButton->setGeometry(130, 170, 100, 30);
480         tmpQPushButton->setText("Cancel");
481         tmpQPushButton->setAutoRepeat(FALSE);
482         connect(tmpQPushButton,SIGNAL(clicked()), &dlg, SLOT(reject()));
483
484         tmpQLabel = new QLabel(&dlg);
485         tmpQLabel->setGeometry(10, 50, 100, 60);
486         tmpQLabel->setText("Unit type:");
487
488         QListWidget *listWidget = new QListWidget(&dlg);
489         for(i = 0; i < TYPENUM; i++) {
490                 QListWidgetItem *newItem = new QListWidgetItem;
491                 newItem->setText(UnitTypes[i]);
492                 listWidget->insertItem(i, newItem);
493         }
494         listWidget->setCurrentItem(0);
495
496         if (dlg.exec()) {
497                 strcpy(uname, files->text());
498
499                 QString txt;
500                 txt.sprintf("UNIT %s : %s( <params> );\nBEGIN\n\nEND %s;",
501                         uname,
502                         listWidget->currentItem()->text().toStdString().c_str(),
503                         uname
504                 );
505
506                 editor->textCursor().insertText(txt);
507         }
508 }
509
510 /**
511  * Program main function.
512  * argv[1] is mandatory and should be a path to the home directory of
513  * application (same as in configuration file).
514  * @param argc Number of program arguments
515  * @param argv Program arguments
516  */
517 int main(int argc, char **argv)
518 {
519         QApplication app(argc, argv);
520         Editor * editor = new Editor(argc, argv);
521         editor->show();
522         return app.exec();
523 }
524