Fix problems from porting Qt3->Qt4, which were caused by introducing takeFirst()...
[vlp.git] / src / help / help.cpp
1 #include <QtGui/QApplication>
2 #include <QtGui/QMainWindow>
3 #include <Qt3Support/q3multilineedit.h>
4 #include <QtGui/QMenuBar>
5 // #include <qpopmenu.h>
6 #include <QtGui/QDialog>
7 #include <QtGui/QButtonGroup>
8 #include <QtGui/QLabel>
9 #include <QtGui/QLineEdit>
10 #include <Qt3Support/Q3ListBox>
11 #include <QtGui/QPushButton>
12 #include <QtGui/QRadioButton>
13 #include <QtCore/QList>
14 #include <QtCore/qfile.h>
15 #include <QtGui/qcombobox.h>
16 #include <QtGui/QToolTip>
17 #include <QtGui/QFont>
18 #include <QtGui/QPixmap>
19 #include <QtGui/QMessageBox>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <QtCore/QTextStream>
24 #include <QtCore/qstring.h>
25 #include <QtGui/QFileDialog>
26 #include <QtGui/QFontMetrics>
27 #include <QtGui/QPainter>
28 #include <QtGui/QScrollBar>
29
30
31 #define TAG_TEXT        0
32 #define TAG_OTHER       1
33
34 #define TAG_LINK        2 
35 #define TAG_ANCHOR      3 
36 #define TAG_BOLD_ON     4 
37 #define TAG_BOLD_OFF    5 
38 #define TAG_ITALIC_ON   6 
39 #define TAG_ITALIC_OFF  7 
40 #define TAG_BREAK       8 
41 #define TAG_LINE        9 
42 #define TAG_LINK_END    10 
43 #define TAG_LIST_ON     11
44 #define TAG_LIST_OFF    12
45 #define TAG_LIST_ITEM   13
46
47 #define PIX_HEIGHT      2000
48
49 char names[14][40] = {
50         "text", "other", "link", "anchor", "bold on",
51         "bold off", "italic on", "italic off", "break",
52         "line", "end link", "list on", "list off", "list item"
53 };
54
55 class Tag {
56 public:
57         Tag() {
58                 tag_type=0;
59                 strcpy(tag_label, "");
60                 strcpy(tag_link, "");
61                 strcpy(tag_text, "");
62         };
63         int tag_type;
64         char tag_label[255];
65         char tag_link[255];
66         char tag_text[255]; 
67         int x;
68         int y;
69         int w;
70         int h;
71 };
72
73 class HTMLAnalyzer {
74 public:
75         QList<Tag*> tags;
76         bool verbatim;
77
78         HTMLAnalyzer();
79
80         bool LoadFile(char*);
81         void AnalyzeTag(QString*);
82         void PackLinks();
83         void DumpList();
84         Tag *CheckTag(int, int);
85         Tag *FindAnchor(char*);
86 };
87
88 HTMLAnalyzer::HTMLAnalyzer()
89 {
90         tags.clear();
91         verbatim = FALSE;
92 }
93
94 bool HTMLAnalyzer::LoadFile(char *fname)
95 {
96         QFile f(fname);
97         QString poms, poms1;
98         int i;
99         Tag *pomt;
100         bool not_ended;
101
102         tags.clear();
103         if (!f.open(IO_ReadOnly))
104                 return(FALSE);
105
106         QTextStream fs(&f);
107
108         while (!fs.atEnd()) {
109                 poms = fs.readLine();
110                 while (poms.length()>0) {
111                         i = poms.find('<');
112                         if (i != -1) {
113                                 if (i > 1) {
114                                         poms1 = poms.left(i);
115                                         pomt = new Tag;
116                                         pomt->tag_type = TAG_TEXT;
117                                         if (!verbatim) {
118                                                 poms1 = poms1.simplifyWhiteSpace();
119                                         }
120                                                 
121                                         sprintf(pomt->tag_text, " %s", poms1.toStdString().c_str());
122                                         tags.append(pomt);
123                                 }
124                                 poms = poms.right(poms.length() - i);
125
126                                 i = poms.find('>');
127                                 if (i != -1) {
128                                         poms1 = poms.mid(1, i - 1);
129                                         AnalyzeTag(&poms1);
130                                         poms = poms.right(poms.length() - i -1);
131                                 } else {
132                                         not_ended = TRUE;
133                                         break;
134                                 }
135                         } else {
136                                 pomt = new Tag;
137                                 pomt->tag_type = TAG_TEXT;
138                                 if (!verbatim) 
139                                         poms=poms.simplifyWhiteSpace();
140                                 
141                                 sprintf(pomt->tag_text, " %s", poms.toStdString().c_str());
142                                 tags.append(pomt);
143                                 break;
144                         }
145                 }
146                 if (verbatim) {
147                         pomt = new Tag;
148                         pomt->tag_type = TAG_BREAK;
149                         tags.append(pomt);
150                 }
151         }
152         f.close();
153         return TRUE;
154 }
155
156 void HTMLAnalyzer::AnalyzeTag(QString *t)
157 {
158         Tag *pom;
159         int i;
160         QString poms, poms1;
161
162         *t = t->simplifyWhiteSpace();
163         pom = new Tag;
164
165         if ((t->toStdString().c_str()[0] != 'A') && (t->toStdString().c_str()[0] != 'a')) {
166                 *t = t->upper();
167                 if (strcmp(t->toStdString().c_str(), "B") ==0 ) {
168                         pom->tag_type = TAG_BOLD_ON;
169                 }
170                 else if (strcmp(t->toStdString().c_str(), "/B") == 0) {
171                         pom->tag_type = TAG_BOLD_OFF;
172                 }
173                 else if (strcmp(t->toStdString().c_str(), "I") == 0) {
174                         pom->tag_type = TAG_ITALIC_ON;
175                 }
176                 else if (strcmp(t->toStdString().c_str(), "/I") == 0) {
177                         pom->tag_type = TAG_ITALIC_OFF;
178                 }
179                 else if (strcmp(t->toStdString().c_str(), "BR") == 0) {
180                         pom->tag_type = TAG_BREAK;
181                 }
182                 else if (strcmp(t->toStdString().c_str(), "HR") == 0) {
183                         pom->tag_type = TAG_LINE;
184                 }
185                 else if (strcmp(t->toStdString().c_str(), "/A") == 0) {
186                         pom->tag_type = TAG_LINK_END;
187                 }
188                 else if (strcmp(t->toStdString().c_str(), "UL") == 0) {
189                         pom->tag_type = TAG_LIST_ON;
190                 }
191                 else if (strcmp(t->toStdString().c_str(), "/UL") == 0) {
192                         pom->tag_type = TAG_LIST_OFF;
193                 }
194                 else if (strcmp(t->toStdString().c_str(), "LI") == 0) {
195                         pom->tag_type = TAG_LIST_ITEM;
196                 }
197                 else if (strcmp(t->toStdString().c_str(), "PRE") == 0) {
198                         verbatim=TRUE;
199                 }
200                 else if (strcmp(t->toStdString().c_str(),"/PRE") == 0) {
201                         verbatim=FALSE;
202                 }
203         } else {
204          /*
205         'a' or 'A'
206         links
207         */
208                 i = t->find('=');
209                 if (i != -1) {
210                         poms = t->mid(2, i - 2);
211                         poms = poms.simplifyWhiteSpace();
212                         poms = poms.upper();
213                         poms1 = t->right(t->length() - i - 1);
214                         poms1 = poms1.simplifyWhiteSpace();
215
216                         if (poms == "HREF") {
217                                 pom->tag_type = TAG_LINK;
218                                 strcpy(pom->tag_link,poms1.toStdString().c_str());
219                         }
220                         else if (poms == "NAME") {
221                                 pom->tag_type = TAG_ANCHOR;
222                                 if (poms1[0] == '"')
223                                         poms1=poms1.right(poms1.length() - 1);
224                                 if (poms1[poms1.length() - 1] == '"')
225                                         poms1=poms1.left(poms1.length() - 1);
226                                 strcpy(pom->tag_label, poms1.toStdString().c_str());
227                         }
228                 }
229         }
230         tags.append(pom);
231 }
232
233 void HTMLAnalyzer::DumpList()
234 {
235         Tag *pom;
236         QListIterator<Tag *> tagsIterator(tags);
237
238         while (tagsIterator.hasNext()) {
239                 pom = tagsIterator.next();
240                 fprintf(stderr, "%s:%s,%s,%s\n", names[pom->tag_type],
241                         pom->tag_text, pom->tag_link, pom->tag_label);
242         }
243 }
244
245 void HTMLAnalyzer::PackLinks()
246 {
247         Tag *pom,*pom1;
248         char s[255];
249         QListIterator<Tag *> tagsIterator(tags);
250
251         while (tagsIterator.hasNext()) {
252                 pom = tagsIterator.next();
253                 if ((pom->tag_type == TAG_LINK) ||
254                         (pom->tag_type == TAG_ANCHOR)) {
255                         pom1 = tagsIterator.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.removeOne(pom1);
262                                 pom1 = tags.current();
263                         }
264                         strcpy(pom->tag_text,s); 
265                         tags.removeOne(pom1);
266                         pom = tags.current();
267                 } else {
268                         pom = tagsIterator.next();
269                 }
270         }
271 }
272
273
274 Tag *HTMLAnalyzer::CheckTag(int x,int y)
275 {
276         Tag *pom;
277         QListIterator<Tag *> tagsIterator(tags);
278
279         while (tagsIterator.hasNext()) {
280                 pom = tagsIterator.next();
281                 if (pom->tag_type==TAG_LINK)
282                         if ((x >= pom->x) && (x <= pom->x + pom->w) &&
283                                 (y >= pom->y) && (y <= pom->y + pom->h)) {
284                                 return pom;
285                         }
286         }
287         return NULL;
288 }
289
290 Tag *HTMLAnalyzer::FindAnchor(char *name)
291 {
292         Tag *pom;
293         QListIterator<Tag *> tagsIterator(tags);
294
295         while (tagsIterator.hasNext()) {
296                 pom = tagsIterator.next();
297                 if ((pom->tag_type == TAG_ANCHOR) &&
298                         (strcmp(pom->tag_label, name) == 0)) {
299                                 return(pom);
300                         }
301         }
302         return pom;
303 }
304 /********************************/
305
306 class QHTML: public QMainWindow {
307         Q_OBJECT
308 public:
309         QScrollBar *vscroll;
310         QMenuBar *bar;  
311         HTMLAnalyzer *analyzer;
312         QPixmap *map;
313         int cx,cy,oy,lstep,pstep;
314         bool Bold,Italic;
315         QFont *normal,*bold,*italic,*bold_italic,*actual_font;
316         char homedir[255];
317
318         QHTML(char*);
319         void DrawList();
320         virtual void paintEvent(QPaintEvent *ev);
321         virtual void resizeEvent(QResizeEvent *ev);
322         virtual void mousePressEvent(QMouseEvent *ev);
323 public slots:
324         void load();
325         void back();
326         void vscrolled(int);
327         void contents();
328         void user_guide();
329         void lang_guide();
330 };
331
332
333 QApplication *app;
334
335 QHTML::QHTML(char *d)
336 {
337         char s[255];
338
339         QFont f("Helvetica", 12, QFont::Bold);
340         normal = new QFont("Helvetica", 12, QFont::Normal);
341         bold = new QFont("Helvetica", 12, QFont::Bold);
342         italic = new QFont("Helvetica", 12, QFont::Normal, TRUE);
343         bold_italic = new QFont("Helvetica", 12, QFont::Bold, TRUE);
344         strcpy(homedir, d);
345
346         actual_font = normal;
347         
348         setWindowTitle("LOGLAN Help");
349
350         QMenu * contentsMenu = NULL;
351         menuBar()->addAction("File", this, SLOT(load()));
352         contentsMenu = menuBar()->addMenu("&Contents");
353         contentsMenu->addAction("Index", this, SLOT(contents()));
354         contentsMenu->addAction("User Guide", this, SLOT(user_guide()));
355         contentsMenu->addAction("Language reference", this, SLOT(lang_guide()));
356
357         menuBar()->addAction("Quit", app, SLOT(quit()));
358
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, QScrollBar::Vertical, this);
368         vscroll->setTracking(TRUE);  
369         vscroll->setGeometry(width() - 16, bar->height(), 16, height()-bar->height());
370         connect(vscroll, SIGNAL(valueChanged(int)), this, SLOT(vscrolled(int)));
371         sprintf(s, "%s/index.html", homedir);
372         analyzer->LoadFile(s);
373         analyzer->PackLinks();
374         DrawList();
375 }
376
377 void QHTML::vscrolled(int v)
378 {
379         oy = v;
380         repaint();
381 }
382
383 void QHTML::load()
384 {
385         QString s(QFileDialog::getOpenFileName(homedir, "*", this));
386         if (!s.isNull()) {
387                 vscroll->setValue(0); 
388                 analyzer->LoadFile((char*)s.ascii());
389                 analyzer->PackLinks();
390                 DrawList();
391         }
392 }
393
394 void QHTML::contents()
395 {
396         char ss[255];
397         sprintf(ss, "%s/index.html", homedir);
398         analyzer->LoadFile(ss);
399         analyzer->PackLinks();
400         DrawList(); 
401 }
402
403 void QHTML::user_guide()
404 {
405         char ss[255];
406         sprintf(ss, "%s/userg.html", homedir);
407         analyzer->LoadFile(ss);
408         analyzer->PackLinks();
409         DrawList(); 
410 }
411
412 void QHTML::lang_guide()
413 {
414         char ss[255];
415         sprintf(ss, "%s/langg.html", homedir);
416         analyzer->LoadFile(ss);
417         analyzer->PackLinks();
418         DrawList();
419 }
420
421 void QHTML::paintEvent(QPaintEvent *ev)
422 {
423         if (map != NULL) {
424                 bitBlt(this, 0, bar->height(), map, 0, oy,
425                                                 width() - 16, height() - 16);
426         }
427 }
428
429 void QHTML::resizeEvent(QResizeEvent *ev)
430 {
431         DrawList();
432 }
433
434 void QHTML::mousePressEvent(QMouseEvent *ev)
435 {
436         Tag *pom, *pom1;
437         QString poms;
438         char ss[255];
439
440         pom = analyzer->CheckTag(ev->x(), ev->y() + oy);
441         if (pom != NULL) {
442                 poms.sprintf(pom->tag_link);
443                 if (poms[0] == '"') 
444                         poms = poms.right(poms.length() - 1);
445                 if (poms[poms.length() - 1] == '"')
446                         poms=poms.left(poms.length() - 1);
447                 if (poms[0] == '#') {
448                         poms = poms.right(poms.length() - 1);
449                         pom1 = analyzer->FindAnchor((char*)poms.ascii());
450                         if (pom1 != NULL) {
451                                 vscroll->setValue(pom1->y);
452                         }
453                 } else {
454                         sprintf(ss, "%s/%s", homedir, poms.toStdString().c_str());
455                         analyzer->LoadFile(ss);
456                         analyzer->PackLinks();
457                         DrawList();
458                 }
459         }
460 }
461
462 /**
463  * @attention Currently not in use
464  */
465 void QHTML::back()
466 {
467 }
468
469 void QHTML::DrawList()
470 {
471         Tag *pom;
472         QPainter p;
473
474         if (!analyzer->tags.isEmpty()) {
475                 cx = 5;
476                 cy = 15;
477                 map->fill(backgroundColor());
478                 p.begin(map);
479
480                 QListIterator<Tag *> tagsIterator(tags);
481
482                 while (tagsIterator.hasNext()) {
483                         pom = tagsIterator.next();
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                 }
586                 p.end();
587                 repaint();
588         }
589 }
590
591 #include "help.moc"
592
593 int main( int argc, char **argv )
594 {
595         QString ps;
596
597         app = new QApplication(argc, argv);
598         if (argc == 2)
599                 ps.sprintf(argv[1]);
600         else
601                 ps.sprintf(".");
602         QHTML cfg((char*)ps.ascii());
603         //app->setStyle(WindowsStyle);
604 //      app->setMainWidget(&cfg);
605         cfg.show();
606         return app->exec();
607 }