vlp-7 More documentation in code.
[vlp.git] / src / help / help.cpp
1 #include <qapp.h>
2 #include <qframe.h>
3 #include <qmlined.h>
4 #include <qmenubar.h>
5 #include <qpopmenu.h>
6 #include <qdialog.h>
7 #include <qbttngrp.h>
8 #include <qlabel.h>
9 #include <qlined.h>
10 #include <qlistbox.h>
11 #include <qpushbt.h>
12 #include <qradiobt.h>
13 #include <qlist.h>
14 #include <qfile.h>
15 #include <qcombo.h>
16 #include <qtooltip.h>
17 #include <qfont.h>
18 #include <qpixmap.h>
19 #include <qmsgbox.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <qfile.h>
24 #include <qtstream.h>
25 #include <qstring.h>
26 #include <qfiledlg.h>
27 #include <qfontmet.h>
28 #include <qpainter.h>
29 #include <qscrbar.h>
30
31
32 #define TAG_TEXT        0
33 #define TAG_OTHER       1
34
35 #define TAG_LINK        2 
36 #define TAG_ANCHOR      3 
37 #define TAG_BOLD_ON     4 
38 #define TAG_BOLD_OFF    5 
39 #define TAG_ITALIC_ON   6 
40 #define TAG_ITALIC_OFF  7 
41 #define TAG_BREAK       8 
42 #define TAG_LINE        9 
43 #define TAG_LINK_END    10 
44 #define TAG_LIST_ON     11
45 #define TAG_LIST_OFF    12
46 #define TAG_LIST_ITEM   13
47
48 #define PIX_HEIGHT      2000
49
50 char names[14][40] = {
51         "text", "other", "link", "anchor", "bold on",
52         "bold off", "italic on", "italic off", "break",
53         "line", "end link", "list on", "list off", "list item"
54 };
55
56 class Tag {
57 public:
58         Tag() {
59                 tag_type=0;
60                 strcpy(tag_label, "");
61                 strcpy(tag_link, "");
62                 strcpy(tag_text, "");
63         };
64         int tag_type;
65         char tag_label[255];
66         char tag_link[255];
67         char tag_text[255]; 
68         int x;
69         int y;
70         int w;
71         int h;
72 };
73
74 class HTMLAnalyzer {
75 public:
76         QList<Tag> tags;
77         bool verbatim;
78
79         HTMLAnalyzer();
80
81         bool LoadFile(char*);
82         void AnalyzeTag(QString*);
83         void PackLinks();
84         void DumpList();
85         Tag *CheckTag(int, int);
86         Tag *FindAnchor(char*);
87 };
88
89 HTMLAnalyzer::HTMLAnalyzer()
90 {
91         tags.clear();
92         verbatim = FALSE;
93 }
94
95 bool HTMLAnalyzer::LoadFile(char *fname)
96 {
97         QFile f(fname);
98         QString poms, poms1;
99         int i;
100         Tag *pomt;
101         bool not_ended;
102
103         tags.clear();
104         if (!f.open(IO_ReadOnly))
105                 return(FALSE);
106
107         QTextStream fs(&f);
108
109         while (!fs.eof()) {
110                 poms = fs.readLine();
111                 while (poms.length()>0) {
112                         i = poms.find('<');
113                         if (i != -1) {
114                                 if (i > 1) {
115                                         poms1 = poms.left(i);
116                                         pomt = new Tag;
117                                         pomt->tag_type = TAG_TEXT;
118                                         if (!verbatim) {
119                                                 poms1 = poms1.simplifyWhiteSpace();
120                                         }
121                                                 
122                                         sprintf(pomt->tag_text, " %s",
123                                                                 poms1.data());
124                                         tags.append(pomt);
125                                 }
126                                 poms = poms.right(poms.length() - i);
127
128                                 i = poms.find('>');
129                                 if (i != -1) {
130                                         poms1 = poms.mid(1, i - 1);
131                                         AnalyzeTag(&poms1);
132                                         poms = poms.right(poms.length() - i -1);
133                                 } else {
134                                         not_ended = TRUE;
135                                         break;
136                                 }
137                         } else {
138                                 pomt = new Tag;
139                                 pomt->tag_type = TAG_TEXT;
140                                 if (!verbatim) 
141                                         poms=poms.simplifyWhiteSpace();
142                                 
143                                 sprintf(pomt->tag_text, " %s", poms.data());
144                                 tags.append(pomt);
145                                 break;
146                         }
147                 }
148                 if (verbatim) {
149                         pomt = new Tag;
150                         pomt->tag_type = TAG_BREAK;
151                         tags.append(pomt);
152                 }
153         }
154         f.close();
155         return TRUE;
156 }
157
158 void HTMLAnalyzer::AnalyzeTag(QString *t)
159 {
160         Tag *pom;
161         int i;
162         QString poms, poms1;
163
164         *t = t->simplifyWhiteSpace();
165         pom = new Tag;
166
167         if ((t->data()[0] != 'A') && (t->data()[0] != 'a')) {
168                 *t = t->upper();
169                 if (strcmp(t->data(), "B") ==0 ) {
170                         pom->tag_type = TAG_BOLD_ON;
171                 }
172                 else if (strcmp(t->data(), "/B") == 0) {
173                         pom->tag_type = TAG_BOLD_OFF;
174                 }
175                 else if (strcmp(t->data(), "I") == 0) {
176                         pom->tag_type = TAG_ITALIC_ON;
177                 }
178                 else if (strcmp(t->data(), "/I") == 0) {
179                         pom->tag_type = TAG_ITALIC_OFF;
180                 }
181                 else if (strcmp(t->data(), "BR") == 0) {
182                         pom->tag_type = TAG_BREAK;
183                 }
184                 else if (strcmp(t->data(), "HR") == 0) {
185                         pom->tag_type = TAG_LINE;
186                 }
187                 else if (strcmp(t->data(), "/A") == 0) {
188                         pom->tag_type = TAG_LINK_END;
189                 }
190                 else if (strcmp(t->data(), "UL") == 0) {
191                         pom->tag_type = TAG_LIST_ON;
192                 }
193                 else if (strcmp(t->data(), "/UL") == 0) {
194                         pom->tag_type = TAG_LIST_OFF;
195                 }
196                 else if (strcmp(t->data(), "LI") == 0) {
197                         pom->tag_type = TAG_LIST_ITEM;
198                 }
199                 else if (strcmp(t->data(), "PRE") == 0) {
200                         verbatim=TRUE;
201                 }
202                 else if (strcmp(t->data(),"/PRE") == 0) {
203                         verbatim=FALSE;
204                 }
205         } else {
206          /*
207         'a' or 'A'
208         links
209         */
210                 i = t->find('=');
211                 if (i != -1) {
212                         poms = t->mid(2, i - 2);
213                         poms = poms.simplifyWhiteSpace();
214                         poms = poms.upper();
215                         poms1 = t->right(t->length() - i - 1);
216                         poms1 = poms1.simplifyWhiteSpace();
217
218                         if (strcmp(poms.data(),"HREF") == 0) {
219                                 pom->tag_type = TAG_LINK;
220                                 strcpy(pom->tag_link,poms1.data());
221                         }
222                         else if (strcmp(poms.data(), "NAME") == 0) {
223                                 pom->tag_type = TAG_ANCHOR;
224                                 if (poms1.data()[0] == '"')
225                                         poms1=poms1.right(poms1.length() - 1);
226                                 if (poms1.data()[poms1.length() - 1] == '"')
227                                         poms1=poms1.left(poms1.length() - 1);
228                                 strcpy(pom->tag_label, poms1.data());
229                         }
230                 }
231         }
232         tags.append(pom);
233 }
234
235 void HTMLAnalyzer::DumpList()
236 {
237         Tag *pom;
238         pom = tags.first();
239         while (pom != NULL) {
240                 fprintf(stderr, "%s:%s,%s,%s\n", names[pom->tag_type],
241                         pom->tag_text, pom->tag_link, pom->tag_label);
242                 pom=tags.next();
243         }
244 }
245
246 void HTMLAnalyzer::PackLinks()
247 {
248         Tag *pom,*pom1;
249         char s[255];
250
251         pom = tags.first();
252         while (pom!=NULL) {
253                 if ((pom->tag_type == TAG_LINK) ||
254                         (pom->tag_type == TAG_ANCHOR)) {
255                         pom1 = tags.next();
256                         strcpy(s, "");
257                         while ((pom1 != NULL) &&
258                                 (pom1->tag_type != TAG_LINK_END)) {
259                                 if (pom1->tag_type == TAG_TEXT)
260                                         strcat(s,pom1->tag_text);
261                                 tags.remove(pom1);
262                                 pom1 = tags.current();
263                         }
264                         strcpy(pom->tag_text,s); 
265                         tags.remove(pom1);
266                         pom = tags.current();
267                 } else {
268                         pom = tags.next();
269                 }
270         }
271 }
272
273
274 Tag *HTMLAnalyzer::CheckTag(int x,int y)
275 {
276         Tag *pom;
277         pom=tags.first();
278         while (pom != NULL) {
279                 if (pom->tag_type==TAG_LINK)
280                         if ((x >= pom->x) && (x <= pom->x + pom->w) &&
281                                 (y >= pom->y) && (y <= pom->y + pom->h)) {
282                                 return pom;
283                         }
284                 pom=tags.next();
285         }
286         return NULL;
287 }
288
289 Tag *HTMLAnalyzer::FindAnchor(char *name)
290 {
291         Tag *pom;
292         pom = tags.first();
293         while (pom != NULL) {
294                 if ((pom->tag_type == TAG_ANCHOR) &&
295                         (strcmp(pom->tag_label, name) == 0)) {
296                                 return(pom);
297                         }
298                 pom=tags.next();
299         }
300         return pom;
301 }
302 /********************************/
303
304 class QHTML: public QFrame {
305         Q_OBJECT
306 public:
307         QScrollBar *vscroll;
308         QMenuBar *bar;  
309         HTMLAnalyzer *analyzer;
310         QPixmap *map;
311         int cx,cy,oy,lstep,pstep;
312         bool Bold,Italic;
313         QFont *normal,*bold,*italic,*bold_italic,*actual_font;
314         char homedir[255];
315
316         QHTML(char*);
317         void DrawList();
318         virtual void paintEvent(QPaintEvent *ev);
319         virtual void resizeEvent(QResizeEvent *ev);
320         virtual void mousePressEvent(QMouseEvent *ev);
321 public slots:
322         void load();
323         void back();
324         void vscrolled(int);
325         void contents();
326         void user_guide();
327         void lang_guide();
328 };
329
330
331 QApplication *app;
332
333 QHTML::QHTML(char *d)
334 {
335         QPopupMenu *pp;
336         char s[255];
337
338         QFont f("Helvetica", 12, QFont::Bold);
339         normal = new QFont("Helvetica", 12, QFont::Normal);
340         bold = new QFont("Helvetica", 12, QFont::Bold);
341         italic = new QFont("Helvetica", 12, QFont::Normal, TRUE);
342         bold_italic = new QFont("Helvetica", 12, QFont::Bold, TRUE);
343         strcpy(homedir, d);
344
345         actual_font = normal;
346         bar = new QMenuBar(this);
347         pp = new QPopupMenu;
348         pp->insertItem("Index", this, SLOT(contents()));
349         pp->insertItem("User Guide", this, SLOT(user_guide()));
350         pp->insertItem("Language reference", this, SLOT(lang_guide()));
351         pp->setFont(f);
352         /*pp->setStyle(WindowsStyle);*/
353         bar->insertItem("File", this, SLOT(load()));
354         bar->insertItem("Contents", pp);
355         bar->insertItem("Quit", app, SLOT(quit()));
356         bar->setFont(f);
357         setCaption("LOGLAN Help");
358         setBackgroundColor(gray);
359         analyzer = new HTMLAnalyzer;
360         map = new QPixmap(500, PIX_HEIGHT);
361         map->fill(backgroundColor());
362         resize(500, height());
363         setFixedSize(width(), height());
364         oy = 0;
365         lstep = 10;
366         pstep = height() - bar->height();
367         vscroll = new QScrollBar(0, PIX_HEIGHT, lstep, pstep, 0, 
368                                                 QScrollBar::Vertical, this);
369         vscroll->setTracking(TRUE);  
370         vscroll->setGeometry(width() - 16, bar->height(), 16, 
371                                                         height()-bar->height());
372         connect(vscroll, SIGNAL(valueChanged(int)), this, SLOT(vscrolled(int)));  
373         sprintf(s, "%s/index.html", homedir);
374         analyzer->LoadFile(s);
375         analyzer->PackLinks();
376         DrawList();
377 }
378
379 void QHTML::vscrolled(int v)
380 {
381         oy = v;
382         repaint();
383 }
384
385 void QHTML::load()
386 {
387         QString s(QFileDialog::getOpenFileName(homedir, "*", this));
388         if (!s.isNull()) {
389                 vscroll->setValue(0); 
390                 analyzer->LoadFile((char*)s.ascii());
391                 analyzer->PackLinks();
392                 DrawList();
393         }
394 }
395
396 void QHTML::contents()
397 {
398         char ss[255];
399         sprintf(ss, "%s/index.html", homedir);
400         analyzer->LoadFile(ss);
401         analyzer->PackLinks();
402         DrawList(); 
403 }
404
405 void QHTML::user_guide()
406 {
407         char ss[255];
408         sprintf(ss, "%s/userg.html", homedir);
409         analyzer->LoadFile(ss);
410         analyzer->PackLinks();
411         DrawList(); 
412 }
413
414 void QHTML::lang_guide()
415 {
416         char ss[255];
417         sprintf(ss, "%s/langg.html", homedir);
418         analyzer->LoadFile(ss);
419         analyzer->PackLinks();
420         DrawList();
421 }
422
423 void QHTML::paintEvent(QPaintEvent *ev)
424 {
425         if (map != NULL) {
426                 bitBlt(this, 0, bar->height(), map, 0, oy,
427                                                 width() - 16, height() - 16);
428         }
429 }
430
431 void QHTML::resizeEvent(QResizeEvent *ev)
432 {
433         DrawList();
434 }
435
436 void QHTML::mousePressEvent(QMouseEvent *ev)
437 {
438         Tag *pom, *pom1;
439         QString poms;
440         char ss[255];
441
442         pom = analyzer->CheckTag(ev->x(), ev->y() + oy);
443         if (pom != NULL) {
444                 poms.sprintf(pom->tag_link);
445                 if (poms.data()[0] == '"') 
446                         poms = poms.right(poms.length() - 1);
447                 if (poms.data()[poms.length() - 1] == '"')
448                         poms=poms.left(poms.length() - 1);
449                 if (poms.data()[0] == '#') {
450                         poms = poms.right(poms.length() - 1);
451                         pom1 = analyzer->FindAnchor((char*)poms.ascii());
452                         if (pom1 != NULL) {
453                                 vscroll->setValue(pom1->y);
454                         }
455                 } else {
456                         sprintf(ss, "%s/%s", homedir, poms.data());
457                         analyzer->LoadFile(ss);
458                         analyzer->PackLinks();
459                         DrawList();
460                 }
461         }
462 }
463
464 /**
465  * @attention Currently not in use
466  */
467 void QHTML::back()
468 {
469 }
470
471 void QHTML::DrawList()
472 {
473         Tag *pom;
474         QPainter p;
475
476         if (!analyzer->tags.isEmpty()) {
477                 cx = 5;
478                 cy = 15;
479                 map->fill(backgroundColor());
480                 p.begin(map);
481
482                 pom = analyzer->tags.first();
483                 while (pom != NULL) {
484                         switch(pom->tag_type) {
485                         case TAG_TEXT:
486                                 p.setFont(*actual_font);
487                                 if (cx + p.fontMetrics().width(pom->tag_text) > 
488                                                                 width() - 16) {
489                                         cx = 5;
490                                         cy = cy + p.fontMetrics().height();
491                                 }
492                                 p.drawText(cx, cy, pom->tag_text);
493                                 cx = cx + p.fontMetrics().width(pom->tag_text);
494                                 break;
495                         case TAG_BREAK:
496                                 p.setFont(*actual_font);
497                                 cy = cy + p.fontMetrics().height();
498                                 cx = 5;
499                                 break;
500                         case TAG_ITALIC_ON:
501                                 if (actual_font == bold)
502                                         actual_font = bold_italic;
503                                 else 
504                                         actual_font = italic;
505
506                                 break;
507                         case TAG_ITALIC_OFF:
508                                 if (actual_font == bold_italic)
509                                         actual_font = bold;
510                                 else
511                                         actual_font = normal;
512
513                                 break;
514                         case TAG_BOLD_ON:
515                                 if (actual_font == italic)
516                                         actual_font = bold_italic;
517                                 else 
518                                         actual_font = bold;
519                                         
520                                 break;
521                         case TAG_BOLD_OFF:
522                                 if (actual_font == bold_italic)
523                                         actual_font = italic;
524                                 else 
525                                         actual_font = normal;
526                                         
527                                 break;
528                         case TAG_LINK:
529                                 p.setFont(*actual_font);
530                                 if (cx + p.fontMetrics().width(pom->tag_text) >
531                                                                 width() - 16) {
532                                         cx = 5;
533                                         cy = cy + p.fontMetrics().height();
534                                 }
535                                 p.setPen(QColor(255, 0, 0));
536                                 p.drawText(cx, cy, pom->tag_text);
537                                 pom->x = cx;
538                                 pom->y = cy + p.fontMetrics().height();
539                                 pom->w = p.fontMetrics().width(pom->tag_text);
540                                 pom->h = p.fontMetrics().height();
541                                 p.setPen(QColor(0, 0, 0));
542                                 cx = cx + p.fontMetrics().width(pom->tag_text);
543                                 break;
544                         case TAG_ANCHOR:
545                                 p.setFont(*actual_font);
546                                 if (cx + p.fontMetrics().width(pom->tag_text) >
547                                                                 width() - 16) {
548                                         cx = 5;
549                                         cy = cy + p.fontMetrics().height();
550                                 }
551                                 //p.setPen(QColor(0,255,0));
552                                 p.drawText(cx, cy, pom->tag_text);
553                                 pom->x = cx;
554                                 pom->y = cy - p.fontMetrics().height();
555                                 pom->w = p.fontMetrics().width(pom->tag_text);
556                                 pom->h = p.fontMetrics().height();
557                                 p.setPen(QColor(0, 0, 0));
558                                 cx=cx + p.fontMetrics().width(pom->tag_text);
559                                 break;
560                         case TAG_LIST_OFF:
561                         case TAG_LIST_ON:
562                                 p.setFont(*actual_font);
563                                 cx = 5;
564                                 cy = cy + p.fontMetrics().height();
565                                 break;
566                         case TAG_LIST_ITEM:p.setFont(*actual_font);
567                                 p.setBrush(QBrush(QColor(0, 0, 255)));
568                                 cx = 5;
569                                 cy = cy + p.fontMetrics().height();
570                                 p.drawPie(cx, cy - 5, 5, 5, 0, 5760); 
571                                 cx = cx + 15;
572                                 break;
573                         case TAG_LINE:
574                                 p.setFont(*actual_font);
575                                 cx = 5;
576                                 cy = cy + p.fontMetrics().height();
577                                 p.drawLine(cx, cy - 
578                                         (int)(p.fontMetrics().height() / 2),
579                                         width() - 16 - 5, cy -
580                                         (int)(p.fontMetrics().height() / 2));
581                                 cx = 5;
582                                 cy = cy + p.fontMetrics().height();
583                                 break;
584                         }
585                         pom = analyzer->tags.next();
586                 }
587                 p.end();
588                 repaint();
589         }
590 }
591
592 #include "help.moc"
593
594 int main( int argc, char **argv )
595 {
596         QString ps;
597
598         app = new QApplication(argc, argv);
599         if (argc == 2)
600                 ps.sprintf(argv[1]);
601         else
602                 ps.sprintf(".");
603         QHTML cfg((char*)ps.ascii());
604         //app->setStyle(WindowsStyle);
605         app->setMainWidget(&cfg);
606         cfg.show();
607         return app->exec();
608 }