OSDN Git Service

Remove extra spaces
[kita/kita.git] / src / htmlpart.cpp
1 /***************************************************************************
2 *   Copyright (C) 2004 by Kita Developers                                 *
3 *   ikemo@users.sourceforge.jp                                            *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 ***************************************************************************/
10
11 #include "htmlpart.h"
12
13 #include <QtCore/QRegExp>
14 #include <QtGui/QApplication>
15 #include <QtGui/QClipboard>
16 #include <QtGui/QCursor>
17 #include <QtGui/QScrollBar>
18 #include <QtGui/QStyle>
19 #include <QtGui/QStyleOptionComplex>
20
21 #include <kaction.h>
22 #include <khtml_events.h>
23 #include <kmenu.h>
24 #include <kmessagebox.h>
25 #include <krun.h>
26
27 #include "const.h"
28 #include "domtree.h"
29 #include "respopup.h"
30 #include "viewmediator.h"
31 #include "kitaui/htmlview.h"
32 #include "libkita/abone.h"
33 #include "libkita/boarddatabase.h"
34 #include "libkita/colorconfig.h"
35 #include "libkita/datmanager.h"
36 #include "libkita/globalconfig.h"
37 #include "libkita/kita_misc.h"
38
39 using namespace Kita;
40 /*-------------------------------------------*/
41
42
43 /*-------------------------------------*/
44 /* Don't forget to call setup() later. */
45
46 HTMLPart::HTMLPart(QWidget* parent) : KHTMLPart(new HTMLView(this, parent))
47 {
48     m_mode = HTMLPART_MODE_MAINPART;
49     m_popup = 0;
50     m_domtree = 0;
51     m_datUrl.clear();
52     m_updatedKokoyon = false;
53
54     clearPart();
55     createHTMLDocument();
56     connectSignals();
57 }
58
59
60 HTMLPart::~HTMLPart()
61 {
62     clearPart();
63 }
64
65
66 /* private */
67 void HTMLPart::clearPart()
68 {
69     slotDeletePopup();
70
71     // delete DomTree
72     delete m_domtree;
73     m_domtree = 0;
74
75     DatManager datManager(m_datUrl);
76     // update ViewPos
77     if (m_mode == HTMLPART_MODE_MAINPART && !m_updatedKokoyon
78             && !m_datUrl.isEmpty()) {
79         int readNum = datManager.getReadNum();
80         if (readNum) {
81             datManager.setViewPos(readNum);
82         }
83     }
84     m_updatedKokoyon = false;
85
86     // clear variables
87     m_anchorStack.clear();
88     m_centerNum = 0;
89     m_jumpNumAfterLoading = 0;
90     findTextInit();
91
92     if (!m_datUrl.isEmpty()) {  // This part is opened.
93         // This part is on the main thread view.
94         if (m_mode == HTMLPART_MODE_MAINPART) {
95
96             // tell Thread class that "thread is closed"
97             datManager.setMainThreadOpened(false);
98
99             // emit "deactivated all thread view" SIGNAL
100             KUrl nullUrl("");
101             ViewMediator::getInstance()->changeWriteTab(nullUrl);
102
103             //  update subject tab.
104         }
105     }
106
107     m_datUrl.clear();
108     m_mode = HTMLPART_MODE_MAINPART;
109 }
110
111
112
113 /* public */
114 bool HTMLPart::setup(int mode, const KUrl& url)
115 {
116     Q_ASSERT(!url.isEmpty());
117
118     clearPart();
119
120     m_datUrl = getDatUrl(url);
121     m_mode = mode;
122
123     if (m_mode == HTMLPART_MODE_MAINPART) {
124         // This part is on the main thread view.
125         DatManager datManager(m_datUrl);
126         // create DatInfo explicitly to open new thread.
127         // Usually, DatInfo is NOT created if ReadNum == 0.
128         // See also DatManager::createDatInfo() and
129         //          DatManager::getDatInfo().
130         datManager.createDatInfo();
131
132         // tell Thread class that "thread is opened"
133         datManager.setMainThreadOpened(true);
134
135         // reset abone
136         datManager.resetAbone();
137     }
138
139     // create HTML Document
140     createHTMLDocument();
141
142     // create DOM manager
143     if (m_mode == HTMLPART_MODE_MAINPART) {
144         m_domtree = new DomTree(htmlDocument(), m_datUrl);
145     }
146
147     return true;
148 }
149
150
151 /* private */
152 void HTMLPart::connectSignals()
153 {
154     // popup
155     connect(this, SIGNAL(onURL(const QString&)), SLOT(slotOnUrl(const QString&)));
156
157     connect(view(), SIGNAL(leave()), SLOT(slotLeave()));
158     connect(view()->verticalScrollBar(), SIGNAL(sliderReleased()), SLOT(slotVSliderReleased()));
159     connect(view()->horizontalScrollBar(), SIGNAL(sliderReleased()), SLOT(slotHSliderReleased()));
160 }
161
162
163
164 /* private */
165 void HTMLPart::createHTMLDocument()
166 {
167     // style
168     QString style = QString("body { font-size: %1pt; font-family: \"%2\"; color: %3; background-color: %4; }")
169                     .arg(GlobalConfig::threadFont().pointSize())
170                     .arg(GlobalConfig::threadFont().family())
171                     .arg(ColorConfig::thread().name())
172                     .arg(ColorConfig::threadBackground().name());
173
174     QString text = "<html><head><style>";
175     text += DEFAULT_STYLESHEET;
176     text += style;
177     text += "</style></head><body></body></html>";
178
179     setJScriptEnabled(false);
180     setJavaEnabled(false);
181
182     // Use dummy URL here, and protocol should be "file:".
183     // If protocol is "http:", local image files are not shown
184     // (for security reasons?).
185     begin(KUrl("file:/dummy.htm"));
186     write(text);
187     end();
188 }
189
190 /*---------------------------------------------------------------*/
191 /*---------------------------------------------------------------*/
192 /* direct rendering functions */
193
194 /**
195  * show responses.
196  * @warning don't forget to call updateScreen() later.
197  */
198 void HTMLPart::showResponses(int startnum, int endnum)
199 {
200     if (!m_domtree) return ;
201
202     for (int i = startnum ; i <= endnum; i++) m_domtree->appendRes(i);
203 }
204
205
206 /* do parsing only.            */
207 /* call showResponses() later  */ /* public */
208 void HTMLPart::parseResponses(int startnum, int endnum)
209 {
210     if (!m_domtree) return ;
211
212     for (int i = startnum ; i <= endnum; i++) m_domtree->createResElement(i);
213 }
214
215
216 /*------------------------------------------------*/
217 /* Show all responses ,header, footer, and etc,
218    if these are not shown.                        */
219
220 /* note that updateScreen() is called internally. */
221 /* So, you need not call it later.                */  /* public slot */
222 void HTMLPart::showAll()
223 {
224     if (!m_domtree) return ;
225
226     int bottom = m_domtree->getBottomResNumber();
227     int readNum = DatManager(m_datUrl).getReadNum();
228     if (bottom != readNum) {
229
230         QCursor qc; qc.setShape(Qt::WaitCursor);
231         QApplication::setOverrideCursor(qc);
232
233         showResponses(1, readNum);
234         updateScreen(true, false);
235
236         QApplication::restoreOverrideCursor();
237     }
238 }
239
240 /*
241  * update screen
242  */
243 void HTMLPart::updateScreen(bool showHeaderEtc, bool clock)
244 {
245     if (!m_domtree) {
246         view()->setFocus();
247         return ;
248     }
249
250     // show clock cursor
251     if (clock) {
252         QCursor qc; qc.setShape(Qt::WaitCursor);
253         QApplication::setOverrideCursor(qc);
254     }
255
256     // show header, footer, and kokomadeyonda, etc.
257     if (showHeaderEtc) {
258         m_domtree->appendKokoyon();
259         m_domtree->appendFooterAndHeader();
260     }
261
262     // change color of number of the res which is responsed.
263     if (m_mode == HTMLPART_MODE_MAINPART) {
264
265         if (GlobalConfig::checkResponsed()) {
266             m_domtree->changeColorOfAllResponsedNumber();
267         }
268     }
269
270     // update display
271     htmlDocument().applyChanges();
272     view()->layout();
273     view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
274     view()->setFocus();
275
276     // restore cursor
277     if (clock) {
278         QApplication::restoreOverrideCursor();
279     }
280 }
281
282
283 /* public */
284 void HTMLPart::setInnerHTML(const QString& innerHTML)
285 {
286     createHTMLDocument();
287     htmlDocument().body().setInnerHTML(innerHTML);
288 }
289
290
291
292 /* redraw screen  */
293 void HTMLPart::redrawHTMLPart(const KUrl& datUrl, bool force)
294 {
295     if (m_domtree == 0) return ;
296     if (m_datUrl != datUrl) return ;
297
298     m_domtree->redraw(force);
299 }
300
301 /* public slot */
302 void HTMLPart::slotSetFaceOfHTMLPart()
303 {
304     QFont font = GlobalConfig::threadFont();
305
306     DOM::CSSStyleDeclaration style = htmlDocument().body().style();
307     style.setProperty("font-family", font.family(), "");
308     style.setProperty("font-size", QString("%1pt").arg(font.pointSize()), "");
309     style.setProperty("color", ColorConfig::thread().name(), "");
310     style.setProperty("background-color",
311             ColorConfig::threadBackground().name(), "");
312     htmlDocument().applyChanges();
313 }
314
315 /*---------------------------------------------------------------*/
316 /*---------------------------------------------------------------*/
317 /* cache functions */
318
319
320 /*----------------------------------*/
321 /* load thread from cache & show it */ /* public */
322
323 /*  top = centerNum - preShowNum
324     bottom = centerNum + afterShowNum
325     readNum = DatManager::getReadNum
326  
327     No.1 <- show -> No.20 <- not show -> No.(top) <- show -> No.(bottom) <- not show -> No.(readNum) */
328
329 bool HTMLPart::load(int centerNum)
330 {
331     m_centerNum = centerNum;
332     m_jumpNumAfterLoading = 0;
333
334     if (m_mode != HTMLPART_MODE_MAINPART)
335         return false;
336     if (!m_domtree)
337         return false;
338     DatManager datManager(m_datUrl);
339     if (datManager.getReadNum() == 0)
340         return false;
341
342     int endNum = datManager.getReadNum();
343     showResponses(1, endNum);
344     updateScreen(true , false);
345     gotoAnchor(QString::number(m_centerNum), false);
346     view() ->setFocus();
347
348     return true;
349 }
350
351
352
353 /*----------------------------*/
354 /* start reloading            */
355
356 /* see also slotReceiveData()
357    and slotFinishLoad().      */ /* public */
358 bool HTMLPart::reload(int jumpNum)
359 {
360     if (!m_domtree) return false;
361     if (m_mode != HTMLPART_MODE_MAINPART) {
362         // If this is not MainPart, then open MainPart.
363         ViewMediator::getInstance()->openUrl(m_datUrl);
364         return false;
365     }
366
367     m_firstReceive = true;
368     if (m_centerNum == 0) m_centerNum = m_domtree->getBottomResNumber();
369     m_jumpNumAfterLoading = jumpNum;
370
371     // DatManager will call back slotReceiveData and slotFinishLoad.
372     DatManager(m_datUrl).updateCache(this);
373     view() ->setFocus();
374
375     return true;
376 }
377
378
379
380 /*---------------------------------------------*/
381 /* This slot is called after DatManager
382    received new data, and emits receiveData()  */ /* !!! "public" slot !!! */
383 void HTMLPart::slotReceiveData()
384 {
385     const int delta = 20;
386
387     if (m_mode != HTMLPART_MODE_MAINPART) return ;
388     if (!m_domtree) return ;
389
390     int readNum = DatManager(m_datUrl).getReadNum();
391     int bottom = m_domtree->getBottomResNumber();
392
393     // parsing
394     parseResponses(bottom + 1, readNum);
395
396     // rendering
397     if (m_firstReceive || bottom + delta < readNum) {
398         showResponses(bottom + 1, readNum);
399         updateScreen(true, false);
400     }
401
402     if (m_firstReceive && m_centerNum < readNum) {
403         gotoAnchor(QString::number(m_centerNum), false);
404         m_firstReceive = false;
405     }
406
407     emit receiveData();
408 }
409
410
411 /*--------------------------------------------*/
412 /* This slot is called after DatManager
413    finished updating new data,
414    and emits finishReload()                   */ /* !!! "public" slot !!! */
415 void HTMLPart::slotFinishLoad()
416 {
417     if (m_mode != HTMLPART_MODE_MAINPART) return ;
418     if (!m_domtree) return ;
419
420     int bottom = m_domtree->getBottomResNumber();
421     int shownNum = m_centerNum + 5000;
422
423     showResponses(bottom + 1, shownNum);
424     updateScreen(true, false);
425     //    m_domtree->parseAllRes();
426     m_centerNum = 0;
427
428     if (m_jumpNumAfterLoading)
429         gotoAnchor(QString::number(m_jumpNumAfterLoading), false);
430     m_jumpNumAfterLoading = 0;
431
432     emit finishReload();
433 }
434
435
436
437
438 /*---------------------------------------------------------------*/
439 /*---------------------------------------------------------------*/
440 /* goto anchor */
441
442
443 /* public */
444 bool HTMLPart::gotoAnchor(const QString& anc, bool pushPosition)
445 {
446     if (anc.isEmpty()) return false;
447     if (!m_domtree || m_mode == HTMLPART_MODE_POPUP)
448         return KHTMLPart::gotoAnchor(anc);
449
450     hidePopup();
451
452     QString ancstr = anc;
453     int res = ancstr.toInt();
454
455     if (res > 1) {
456
457         // is target valid?
458         if (!DatManager(m_datUrl).isResValid(res))
459             return false;
460
461         ancstr = QString::number(res);
462     }
463
464     if (res == 1) ancstr = "header";
465     if (pushPosition) pushCurrentPosition();
466
467     // KHTMLPart::gotoAnchor() will fail if the thread is not shown.
468     // So KHTMLPart::gotoAnchor() should be called via custom event.
469     // See also HTMLPart::customEvent()
470     GotoAnchorEvent * e = new GotoAnchorEvent(ancstr);
471     QApplication::postEvent(this, e);  // Qt will delete it when done
472
473     return true;
474 }
475
476
477
478 /* jump to kokomade yonda */ /* public slot */
479 void HTMLPart::slotGotoKokoyon()
480 {
481     if (!m_domtree) return ;
482     if (m_mode != HTMLPART_MODE_MAINPART) return ;
483
484     int kokoyon = DatManager(m_datUrl).getViewPos();
485     gotoAnchor(QString::number(kokoyon), false);
486 }
487
488
489
490 /* public slot  */
491 void HTMLPart::slotGobackAnchor()
492 {
493     if (m_anchorStack.isEmpty()) return ;
494
495     QString anc = m_anchorStack.last();
496     m_anchorStack.pop_back();
497     gotoAnchor(anc , false);
498 }
499
500
501
502
503 /* private */
504 void HTMLPart::pushCurrentPosition()
505 {
506     m_anchorStack += getCurrentIdOfNode();
507 }
508
509
510 /* find the id of current node */ /* private */
511 QString HTMLPart::getCurrentIdOfNode()
512 {
513     DOM::Node node;
514     node = nodeUnderMouse();
515     while (node != 0 && node.nodeName().string() != "div") node = node.parentNode();
516     if (node == 0) return QString();
517
518     return static_cast<DOM::Element>(node).getAttribute("id").string();
519 }
520
521 /* public slot */
522 void HTMLPart::slotClickGotoFooter()
523 {
524     if (!m_domtree || m_mode != HTMLPART_MODE_MAINPART) {
525         gotoAnchor("footer", false);
526         return ;
527     }
528
529     int bottom = m_domtree->getBottomResNumber();
530     int readNum = DatManager(m_datUrl).getReadNum();
531
532     if (readNum != bottom) {
533         showResponses(bottom + 1, readNum);
534         updateScreen(true, true);
535     }
536
537     gotoAnchor("footer", false);
538 }
539
540
541 /*---------------------------------------------------------------*/
542 /*---------------------------------------------------------------*/
543 /* search */
544
545
546 /* private */
547 void HTMLPart::findTextInit()
548 {
549     m_findNode = 0;
550     m_findPos = -1;
551     m_find_y = 0;
552 }
553
554
555
556 /* public */
557 bool HTMLPart::findText(const QString &query, bool reverse)
558 {
559     if (m_mode != HTMLPART_MODE_MAINPART) return false;
560
561     QRegExp regexp(query);
562     regexp.setCaseSensitivity(Qt::CaseInsensitive);
563
564     // init
565     if (m_findNode.isNull()) {
566
567         m_findNode = htmlDocument().body();
568         m_find_y = 0;
569
570         // move to the last child node
571         if (reverse) {
572             while (!m_findNode.lastChild().isNull()) m_findNode = m_findNode.lastChild();
573             m_find_y = view() ->contentsHeight();
574         }
575     }
576
577     while (1) {
578
579         if (m_findNode.nodeType() == DOM::Node::TEXT_NODE
580                 || m_findNode.nodeType() == DOM::Node::CDATA_SECTION_NODE) {
581
582             // find the word in the current node
583             DOM::DOMString nodeText = m_findNode.nodeValue();
584             QString nodestr = nodeText.string();
585             if (reverse && m_findPos != -1) nodestr.resize(m_findPos);
586
587             if (reverse) m_findPos = nodestr.lastIndexOf(regexp, m_findPos);
588             else m_findPos = nodestr.indexOf(regexp, m_findPos + 1);
589
590             // scroll & select & return
591             if (m_findPos != -1) {
592                 int matchLen = regexp.matchedLength();
593
594                 QRect qr = m_findNode.getRect();
595                 view() ->setContentsPos(qr.left() - 50, m_find_y - 100);
596                 DOM::Range rg(m_findNode, m_findPos, m_findNode, m_findPos + matchLen);
597                 setSelection(rg);
598
599                 return true;
600             }
601
602         } else if (m_findNode.nodeName().string() == "table") {
603
604             QRect qr = m_findNode.getRect();
605
606             m_find_y = qr.bottom();
607
608         } else if (m_findNode.nodeName().string() == "div") {
609
610             QRect qr = m_findNode.getRect();
611
612             if (reverse) {
613                 m_find_y = qr.bottom();
614             } else {
615                 m_find_y = qr.top();
616             }
617
618         } else if (m_findNode.nodeName().string() == "br") {
619
620             DOM::Node tmpnode = m_findNode.previousSibling();
621
622             if (tmpnode != 0) {
623
624                 QRect qr = tmpnode.getRect();
625                 if (reverse) m_find_y -= qr.bottom() - qr.top();
626                 else m_find_y += qr.bottom() - qr.top();
627             }
628         }
629
630         //------------------------
631
632         m_findPos = -1;
633         DOM::Node next;
634
635         // move to the next node
636         if (!reverse) {
637
638             next = m_findNode.firstChild();
639             if (next.isNull()) next = m_findNode.nextSibling();
640
641             while (!m_findNode.isNull() && next.isNull()) {
642                 m_findNode = m_findNode.parentNode();
643                 if (!m_findNode.isNull()) {
644                     next = m_findNode.nextSibling();
645                 }
646             }
647         }
648         // revearse
649         else {
650
651             next = m_findNode.lastChild();
652             if (next.isNull()) next = m_findNode.previousSibling();
653
654             while (!m_findNode.isNull() && next.isNull()) {
655                 m_findNode = m_findNode.parentNode();
656                 if (!m_findNode.isNull()) {
657                     next = m_findNode.previousSibling();
658                 }
659             }
660         }
661
662         m_findNode = next;
663         if (m_findNode.isNull()) {
664             m_findNode = 0;
665             return false;
666         }
667     }
668
669     return false;
670 }
671
672
673
674
675
676
677 /*---------------------------------------------------------------*/
678 /*---------------------------------------------------------------*/
679 /* popup menu */
680
681
682 /* private */
683 void HTMLPart::showPopupMenu(const KUrl& kurl)
684 {
685     QString url = kurl.prettyUrl();
686     bool showppm = false;
687
688     QString str;
689
690     // If selected Text is composed of only digits, then show res popup.
691     if (!m_pushctrl && showSelectedDigitPopup()) return ;
692
693     //-----------------------------------
694     // create menu items                 
695
696     KMenu popupMenu(view());
697     KMenu* backSubMenu = 0;
698     KMenu* markSubMenu = 0;
699
700     //------
701     // jump
702     KAction* homeLinkAct = 0;
703     KAction* kokoLinkAct = 0;
704     KAction* endLinkAct = 0;
705     if (m_domtree &&
706             (m_mode == HTMLPART_MODE_MAINPART)) {
707
708         showppm = true;
709
710         DatManager datManager(m_datUrl);
711         // back
712         if (!m_anchorStack.isEmpty()) {
713             backSubMenu = new KMenu(view());
714
715             int i = m_anchorStack.size();
716             QStringList::iterator it;
717             for (it = m_anchorStack.begin(); it != m_anchorStack.end(); it++, i--) {
718                 str = (*it) + "   " + datManager.getPlainBody((*it).toInt()).left(10);
719                 KAction* backLink = new KAction(str, this);
720                 backSubMenu->addAction(backLink);
721             }
722             backSubMenu->setTitle(
723                     i18nc("@title:menu Go back to the responses", "Back"));
724             popupMenu.addMenu(backSubMenu);
725             popupMenu.addSeparator();
726         }
727
728         // mark
729         int readNum = datManager.getReadNum();
730         for (int i = 1; i <= readNum ; i++) {
731             if (datManager.isMarked(i)) {
732                 if (!markSubMenu) {
733                     markSubMenu = new KMenu(view());
734                     markSubMenu->setTitle(i18nc("@title:menu", "Mark"));
735                     popupMenu.addMenu(markSubMenu);
736                     popupMenu.addSeparator();
737                 }
738                 str = QString::number(i) + "   "
739                     + datManager.getPlainBody(i).left(10);
740                 KAction *gotoMarkAct = new KAction(str, this);
741                 markSubMenu->addAction(gotoMarkAct);
742             }
743         }
744
745         // home
746         homeLinkAct = new KAction(
747                 i18nc("@action:inmenu Go to the original post", "Start"), this);
748         popupMenu.addAction(homeLinkAct);
749
750         // template
751         if (m_mode == HTMLPART_MODE_MAINPART) {
752             int kokoyon = datManager.getViewPos();
753             if (kokoyon) {
754                 str = i18nc("@action:inmenu", "Kokomade Yonda (%1)", kokoyon);
755                 kokoLinkAct = new KAction(str, this);
756                 popupMenu.addAction(kokoLinkAct);
757             }
758         }
759         // end 
760         endLinkAct = new KAction(i18nc("@action:inmenu", "End"), this);
761         popupMenu.addAction(endLinkAct);
762     }
763
764     // copy & abone
765     KAction* copyStrAct = 0;
766     KAction* aboneWordAct = 0;
767     if (hasSelection()) {
768         if (showppm) popupMenu.addSeparator();
769         showppm = true;
770
771         copyStrAct = new KAction(i18nc("@action:inmenu", "Copy"), this);
772         popupMenu.addAction(copyStrAct);
773
774         // truncated
775         QString selectedStr = selectedText();
776         if (selectedStr.length() > 20) {
777             selectedStr.truncate(20);
778             selectedStr.append("...");
779         }
780
781         aboneWordAct = new KAction(i18nc("@action:inmenu",
782                     "Add '%1' to abone list", selectedStr), this);
783         popupMenu.addAction(aboneWordAct);
784     }
785
786
787     // copy link
788     KAction* openBrowserAct = 0;
789     KAction* copyLinkAct = 0;
790     if (!url.isEmpty()) {
791         if (showppm) popupMenu.addSeparator();
792         showppm = true;
793
794         openBrowserAct= new KAction(i18nc("@action:inmenu",
795                     "Open with Web Browser"), this);
796         popupMenu.addAction(openBrowserAct);
797         popupMenu.addSeparator();
798
799         copyLinkAct = new KAction(i18nc("@action:inmenu",
800                     "Copy Link Location"), this);
801         popupMenu.addAction(copyLinkAct);
802     }
803
804
805     // show menu
806     if (showppm) {
807
808         QClipboard * clipboard = QApplication::clipboard();
809
810         QAction* action = popupMenu.exec(QCursor::pos());
811         if (!action) {
812             delete backSubMenu;
813             delete markSubMenu;
814             return;
815         }
816         if (action == copyLinkAct) {
817             clipboard->setText(url , QClipboard::Clipboard);
818             clipboard->setText(url , QClipboard::Selection);
819         } else if (action == openBrowserAct) {
820             KRun::runUrl(kurl, "text/html", view());
821         } else if (action == homeLinkAct) {
822             gotoAnchor("header", false);
823         } else if (action == kokoLinkAct) {
824             slotGotoKokoyon();
825         } else if (action == endLinkAct) {
826             slotClickGotoFooter();
827         } else if (action == copyStrAct) {
828             clipboard->setText(selectedText(), QClipboard::Clipboard);
829         } else if (action == aboneWordAct) {
830             if (KMessageBox::warningYesNo(view(),
831                     i18n("Do you want to add '%1' to abone list?",
832                                selectedText())) == KMessageBox::Yes) {
833                 AboneConfig::aboneWordList().append(selectedText());
834                 redrawHTMLPart(m_datUrl, false);
835             }
836         } else {
837             QMenu* menu = action->menu();
838             if (!menu) {
839                 delete backSubMenu;
840                 delete markSubMenu;
841                 return;
842             }
843             if (menu == markSubMenu) {
844                 gotoAnchor(QString::number(menu->actions().indexOf(action)),
845                         false);
846             } else if (menu == backSubMenu) {
847                 for (int i = 0; i < menu->actions().indexOf(action); i++)
848                     m_anchorStack.pop_back();
849                 slotGobackAnchor();
850             }
851         }
852     }
853     delete backSubMenu;
854     delete markSubMenu;
855 }
856
857 /*---------------------------------------------------------------*/
858 /*---------------------------------------------------------------*/
859 /* user event */
860
861
862 /* protected */ /* virtual */
863 void HTMLPart::customEvent(QEvent * e)
864 {
865     if (e->type() == EVENT_GotoAnchor) {
866         KHTMLPart::gotoAnchor(static_cast< GotoAnchorEvent* >(e) ->getAnc());
867         return ;
868     }
869
870     KHTMLPart::customEvent(e);
871 }
872
873
874 /*---------------------------------------------------------------*/
875 /*---------------------------------------------------------------*/
876 /* mouse event */
877
878
879 /* protected */
880 void HTMLPart::khtmlMousePressEvent(khtml::MousePressEvent* e)
881 {
882     emit mousePressed(); // to ThreadView to focus this view.
883
884     KUrl kurl;
885     if (!e->url().string().isEmpty()) {
886         BoardDatabase db(m_datUrl);
887         kurl = KUrl(db.boardUrl(), e->url().string());
888     }
889
890     m_pushctrl = m_pushmidbt = m_pushrightbt = false;
891     if (e->qmouseEvent() ->button() & Qt::RightButton) m_pushrightbt = true;
892     if (e->qmouseEvent() ->modifiers() & Qt::ControlModifier) m_pushctrl = true;
893     if (e->qmouseEvent() ->button() & Qt::MidButton) m_pushmidbt = true;
894
895     if (e->url() != 0) {
896
897         if (e->url().string().at(0) == '#') { // anchor
898             kurl = m_datUrl;
899             kurl.setRef(e->url().string().mid(1)) ;
900         }
901
902         clickAnchor(kurl);
903         m_pushctrl = m_pushmidbt = m_pushrightbt = false;
904         return ;
905     }
906
907     // popup menu
908     if (m_pushrightbt) {
909         showPopupMenu(kurl);
910         m_pushctrl = m_pushmidbt = m_pushrightbt = false;
911         return ;
912     }
913
914     KHTMLPart::khtmlMousePressEvent(e);
915 }
916
917
918
919
920
921 /*-------------------------------------------------------*/
922 /*-------------------------------------------------------*/
923 /* click */
924
925
926
927 /* private slot */
928 void HTMLPart::slotOpenUrlRequest(const KUrl& urlin, const KParts::OpenUrlArguments&)
929 {
930     clickAnchor(urlin);
931 }
932
933
934 /*------------------------------------------------------*/
935 /* This function is called when user clicked res anchor */ /* private */
936 void HTMLPart::clickAnchor(const KUrl& urlin)
937 {
938     QString refstr;
939     KUrl datUrl = getDatUrl(urlin , refstr);
940
941     //--------------------
942     // Ctrl + right click
943     if (m_pushctrl && m_pushrightbt) {
944         showPopupMenu(urlin);
945         return ;
946     }
947
948     //--------------------------------
949     // If this is not anchor, then
950     // emit openURLRequest and return
951
952     if (datUrl.host() != m_datUrl.host() || datUrl.path() != m_datUrl.path()) {
953
954         // right click
955         if (m_pushrightbt) {
956
957             // start multi-popup mode or show popup menu
958             if (!startMultiPopup()) showPopupMenu(urlin);
959
960             return ;
961         }
962         // right click
963
964         ViewMediator::getInstance()->openUrl(urlin);
965         return ;
966     }
967
968     if (refstr.isEmpty()) return ;
969
970     //---------------------------
971     // show popupmenu for #write
972
973     if (refstr.left(5) == "write") {
974         showWritePopupMenu(refstr);
975         return ;
976     }
977
978     //----------------------------
979     // extract responses by ID
980
981     if (refstr.left(5) == "idpop") {
982         showIdPopup(refstr);
983         return ;
984     }
985
986     //---------------------------
987     // show popupmenu for #bepop
988
989     if (refstr.left(5) == "bepop") {
990         showBePopupMenu(refstr);
991         return ;
992     }
993
994     //-------------------------
995     // start multi-popup mdde
996     if (m_pushrightbt && startMultiPopup()) return ;
997
998
999     //----------------------------
1000     // next 100 ,before 100 ,etc.
1001     if (m_mode == HTMLPART_MODE_MAINPART) {
1002         if (refstr.left(7) == "tosaigo") {
1003             slotClickGotoFooter();
1004             return;
1005         }
1006     }
1007
1008     //-------------------------------
1009     // open Kita Navi or goto anchor
1010
1011     int refNum, refNum2;
1012
1013     int i = refstr.indexOf("-");
1014     if (i != -1) {
1015         refNum = refstr.left(i).toInt();
1016         refNum2 = refstr.mid(i + 1).toInt();
1017         if (refNum2 < refNum) {
1018             refNum2 = refNum;
1019         }
1020     } else {
1021         refNum = refNum2 = refstr.toInt();
1022     }
1023
1024     if (!refNum) return ;
1025
1026     if (m_mode == HTMLPART_MODE_POPUP) {
1027         ViewMediator::getInstance()->openUrl(urlin);
1028     } else {
1029         gotoAnchor(QString::number(refNum), true);
1030     }
1031 }
1032
1033
1034
1035 /*---------------------------------------------------------*/
1036 /* popup menu that is opened when user clicked res number. */
1037 /* This funtcion is called in only clickAnchor().          */ /* private */
1038 void HTMLPart::showWritePopupMenu(const QString& refstr)
1039 {
1040     QClipboard * clipboard = QApplication::clipboard();
1041     QString str, resstr;
1042     int resNum = refstr.mid(5).toInt();
1043     DatManager datManager(m_datUrl);
1044     QString namestr = datManager.getPlainName(resNum);
1045
1046     // show res tree
1047     if (m_pushrightbt) {
1048         int num;
1049         QString htmlstr = datManager.getTreeByRes(resNum, num);
1050         if (!num) return ;
1051         QString tmpstr = QString("<DIV>No.%1 : [%2]<BR>").arg(resNum).arg(num);
1052         tmpstr += htmlstr + "<BR><BR></DIV>";
1053         showPopup(m_datUrl, tmpstr);
1054         startMultiPopup();
1055         return ;
1056     }
1057
1058     //---------------------
1059     // create popup menu
1060     QString plainStr;
1061
1062     KMenu popupMenu(view());
1063
1064     KAction* resAct = 0;
1065     KAction* quoteAct = 0;
1066     if (m_mode == HTMLPART_MODE_MAINPART) {
1067         resAct = new KAction(i18nc("@action:inmenu", "Write Response"), this);
1068         popupMenu.addAction(resAct);
1069         
1070         quoteAct = new KAction(i18nc("@action:inmenu", "Quote This"), this);
1071         popupMenu.addAction(quoteAct);
1072
1073         popupMenu.addSeparator();
1074     }
1075
1076     // mark
1077     KAction* markAct = new KAction(i18nc("@action:inmenu", "Mark"), this);
1078     markAct->setCheckable(true);
1079     markAct->setChecked(datManager.isMarked(resNum));
1080     popupMenu.addAction(markAct);
1081
1082     popupMenu.addSeparator();
1083
1084     // open
1085     KAction* showBrowserAct
1086         = new KAction(i18nc("@action:inmenu", "Open with Web Browser"), this);
1087     popupMenu.addAction(showBrowserAct);
1088
1089     popupMenu.addSeparator();
1090
1091     // util
1092     KAction* resTreeAct
1093         = new KAction(i18nc("@action:inmenu", "Res Tree"), this);
1094     popupMenu.addAction(resTreeAct);
1095
1096     KAction* reverseResTreeAct
1097         = new KAction(i18nc("@action:inmenu", "Reverse Res Tree"), this);
1098     popupMenu.addAction(reverseResTreeAct);
1099
1100     KAction* extractNameAct
1101         = new KAction(i18nc("@action:inmenu", "Extract by Name"), this);
1102     popupMenu.addAction(extractNameAct);
1103
1104     popupMenu.addSeparator();
1105
1106     // copy
1107     KAction* copyUrlAct
1108         = new KAction(i18nc("@action:inmenu", "Copy URL"), this);
1109     popupMenu.addAction(copyUrlAct);
1110
1111     KAction* copyThreadNameAct
1112         = new KAction(i18nc("@action:inmenu", "Copy Title and URL"), this);
1113     popupMenu.addAction(copyThreadNameAct);
1114
1115     KAction* copyAct = new KAction(i18nc("@action:inmenu", "Copy"), this);
1116     popupMenu.addAction(copyAct);
1117
1118     // kokkoma de yonda
1119     KAction* setKokoYonAct = 0;
1120     if (m_domtree && m_mode == HTMLPART_MODE_MAINPART) {
1121         popupMenu.addSeparator();
1122
1123         setKokoYonAct
1124             = new KAction(i18nc("@action:inmenu", "Set Kokomade Yonda"), this);
1125         popupMenu.addAction(setKokoYonAct);
1126     }
1127
1128     // abone
1129     popupMenu.addSeparator();
1130
1131     KAction* aboneNameAct
1132         = new KAction(i18nc("@action:inmenu", "Add Name to Abone List"), this);
1133     popupMenu.addAction(aboneNameAct);
1134
1135
1136     // show popup menu
1137     QAction* action = popupMenu.exec(QCursor::pos());
1138     if (!action) {
1139         return;
1140     }
1141     if (action == resAct) {
1142         resstr = ">>" + QString::number(resNum) + '\n';
1143         ViewMediator::getInstance()->showWriteView(m_datUrl, resstr);
1144     } else if (action == quoteAct) {
1145         resstr = ">>" + QString::number(resNum) + '\n'
1146                  + "> " + datManager.getPlainTitle(resNum) + '\n'
1147                  + "> " + datManager.getPlainBody(resNum).replace('\n', "\n> ") + '\n';
1148         ViewMediator::getInstance()->showWriteView(m_datUrl, resstr);
1149     } else if (action == markAct) {
1150         datManager.setMark(resNum, !datManager.isMarked(resNum));
1151     } else if (action == copyAct || action == copyUrlAct || action == copyThreadNameAct) {
1152         str.clear();
1153
1154         // title 
1155         if (action == copyThreadNameAct || action == copyAct) {
1156             str = datManager.threadName();
1157         }
1158
1159         // url
1160         if (!str.isEmpty()) str += '\n';
1161         str += datManager.threadUrl() + '/' + QString::number(resNum)
1162             + '\n';
1163
1164         // body
1165         if (action == copyAct) {
1166             str += '\n'
1167                    + datManager.getPlainTitle(resNum) + '\n'
1168                    + datManager.getPlainBody(resNum) + '\n';
1169         }
1170
1171         // copy
1172         clipboard->setText(str , QClipboard::Clipboard);
1173         clipboard->setText(str , QClipboard::Selection);
1174
1175     } else if (action == setKokoYonAct) {
1176         datManager.setViewPos(resNum);
1177         ViewMediator::getInstance()->updateBoardView(m_datUrl);
1178         m_updatedKokoyon = true;
1179         updateScreen(true, true);
1180         gotoAnchor(QString::number(resNum), false);
1181
1182     } else if (action == showBrowserAct) {
1183         str = datManager.threadUrl() + '/' + QString::number(resNum);
1184
1185         KRun::runUrl(str, "text/html", view());
1186     } else if (action == aboneNameAct) {
1187         if (KMessageBox::warningYesNo(view(),
1188                 i18n("Do you want to add '%1' to abone list?", namestr),
1189                 "Kita") == KMessageBox::Yes) {
1190             AboneConfig::aboneNameList().append(namestr);
1191             redrawHTMLPart(m_datUrl, false);
1192         }
1193     }
1194 }
1195
1196
1197
1198 /*--------------------------------------------------*/
1199 /* popup that is opened when user clicked ID        */
1200 /* This funtcion is called in only clickAnchor().   */ /* private */
1201 void HTMLPart::showIdPopup(const QString& refstr)
1202 {
1203     QString strid = refstr.mid(5)
1204                     .replace("%2B", "+")
1205                     .replace("%2F", "/");
1206
1207     // popup
1208     if (m_pushrightbt) {
1209         int num;
1210         QString htmlstr = DatManager(m_datUrl).getHtmlById(strid, num);
1211         if (num <= 1) return ;
1212         QString tmpstr = QString("<DIV>ID:%1:[%2]<BR>").arg(strid).arg(num);
1213         tmpstr += htmlstr + "<BR><BR></DIV>";
1214         showPopup(m_datUrl, tmpstr);
1215         startMultiPopup();
1216     }
1217
1218     else {
1219         KMenu popupMenu(view());
1220
1221         KAction* aboneAct = new KAction(i18nc("@action:inmenu",
1222                     "Add Id to Abone List"), this);
1223         popupMenu.addAction(aboneAct);
1224
1225         QAction* action = popupMenu.exec(QCursor::pos());
1226         if (!action) {
1227             return;
1228         }
1229         if (action == aboneAct) {
1230             // add ID to abone list
1231             if (KMessageBox::warningYesNo(view(),
1232                     i18n("Do you want to add '%1' to abone list?", strid),
1233                     "Kita") == KMessageBox::Yes) {
1234                 AboneConfig::aboneIDList().append(strid);
1235                 redrawHTMLPart(m_datUrl, false);
1236             }
1237         }
1238     }
1239 }
1240
1241
1242
1243 /*---------------------------------------------------------*/
1244 /* popup menu that is opened when user clicked be anchor.  */
1245 /* This funtcion is called in only clickAnchor().          */ /* private */
1246 void HTMLPart::showBePopupMenu(const QString& refstr)
1247 {
1248     QString strUrl = "http://be.2ch.net/test/p.php?i=" + refstr.mid(5)
1249                     + "&u=d:" + DatManager(m_datUrl).threadUrl() + "/l50";
1250
1251     if (m_pushrightbt) {
1252         // create popup menu
1253         KMenu popupMenu(view());
1254         
1255         QClipboard * clipboard = QApplication::clipboard();
1256
1257         KAction* copyUrlAct
1258             = new KAction(i18nc("@action:inmenu", "copy URL"), this);
1259         popupMenu.addAction(copyUrlAct);
1260
1261         KAction* showBrowserAct = new KAction(i18nc("@action:inmenu",
1262                     "Open with Web Browser"), this);
1263
1264         // show popup menu
1265         QAction* action = popupMenu.exec(QCursor::pos());
1266         if (!action) {
1267             return;
1268         }
1269         if (action == copyUrlAct) {
1270             // copy
1271             clipboard->setText(strUrl, QClipboard::Clipboard);
1272             clipboard->setText(strUrl, QClipboard::Selection);
1273         } else if (action == showBrowserAct) {
1274             KRun::runUrl(strUrl, "text/html", view());
1275         }
1276     } else {
1277         KRun::runUrl(strUrl, "text/html", 0);
1278     }
1279 }
1280
1281 /*-------------------------------------------------------*/
1282 /*-------------------------------------------------------*/
1283 /* popup */
1284
1285
1286 /* public */
1287 bool HTMLPart::isPopupVisible()
1288 {
1289     if (!m_popup) return false;
1290     return m_popup->isVisible();
1291 }
1292
1293
1294 /* public slot */
1295 void HTMLPart::slotDeletePopup()
1296 {
1297     delete m_popup;
1298     m_popup = 0;
1299     m_multiPopup = false;
1300 }
1301
1302
1303 /* for convenience */ /* public slot */
1304 void HTMLPart::slotShowResPopup(const QPoint& point, int refNum, int refNum2)
1305 {
1306     QString innerHTML = DatManager(m_datUrl).getHtml(refNum, refNum2);
1307     if (innerHTML.isEmpty()) return ;
1308
1309     showPopupCore(m_datUrl, innerHTML, point);
1310 }
1311
1312
1313 /* for convenience */ /* private */
1314 void HTMLPart::showPopup(const KUrl& url, const QString& innerHTML)
1315 {
1316     showPopupCore(url, innerHTML, QCursor::pos());
1317 }
1318
1319
1320 /* show popup window   */  /* private */
1321 void HTMLPart::showPopupCore(const KUrl& url, const QString& innerHTML, const QPoint& point)
1322 {
1323     slotDeletePopup();
1324     m_multiPopup = false;
1325
1326     m_popup = new ResPopup(view() , url);
1327
1328     connect(m_popup, SIGNAL(hideChildPopup()), SLOT(slotHideChildPopup()));
1329
1330     m_popup->setText(innerHTML);
1331     m_popup->adjustSize();
1332     m_popup->adjustPos(point);
1333     m_popup->show();
1334 }
1335
1336
1337 /*------------------------*/
1338 /* start multi-popup mode */ /* private */
1339 bool HTMLPart::startMultiPopup()
1340 {
1341
1342     if (m_popup && m_popup->isVisible()) {
1343         m_multiPopup = true;
1344         m_popup->moveMouseAbove();
1345     } else {
1346         m_multiPopup = false;
1347     }
1348
1349     return m_multiPopup;
1350 }
1351
1352
1353 /* Is it multi-popup mode now? */ /* private */
1354 bool HTMLPart::isMultiPopupMode()
1355 {
1356     if (!m_popup) {
1357         m_multiPopup = false;
1358     } else if (m_popup->isHidden()) {
1359         m_multiPopup = false;
1360     }
1361
1362     return m_multiPopup;
1363 }
1364
1365 /* private */
1366 void HTMLPart::hidePopup()
1367 {
1368     if (m_popup) {
1369         m_popup->hide();
1370     }
1371     m_multiPopup = false;
1372 }
1373
1374 /* return true if this view is under mouse. */ /* private */
1375 bool HTMLPart::isUnderMouse(int mrgwd, int mrght)
1376 {
1377     QPoint pos = QCursor::pos();
1378     int cx = pos.x(), cy = pos.y();
1379
1380     QPoint viewpos = view() ->mapToGlobal(QPoint(0, 0));
1381     int px = viewpos.x(), py = viewpos.y();
1382     int wd = view() ->visibleWidth(), ht = view() ->visibleHeight();
1383
1384     if ((px < cx && cx < px + wd + mrgwd)
1385             && (py < cy && cy < py + ht + mrght)) {
1386         return true;
1387     }
1388
1389     return false;
1390 }
1391
1392 /* private slot */
1393 void HTMLPart::slotLeave()
1394 {
1395     if (isMultiPopupMode()) return ;
1396     if (view()->horizontalScrollBar()->isSliderDown()) return;
1397     if (view()->verticalScrollBar()->isSliderDown()) return;
1398
1399     hidePopup();
1400
1401     // emit signal to have parent hide this if this is popup.
1402     if (m_mode == HTMLPART_MODE_POPUP && !isUnderMouse(0, 0)) {
1403         emit hideChildPopup();
1404     }
1405 }
1406
1407 /* private slot */
1408 void HTMLPart::slotVSliderReleased()
1409 {
1410     QScrollBar * bar = view() ->verticalScrollBar();
1411     QRect rt = bar->style()->subControlRect(QStyle::CC_Slider, new QStyleOptionComplex(), QStyle::SC_SliderHandle);
1412     int mrg = rt.right() - rt.left();
1413
1414     hidePopup();
1415
1416     // emit signal to have parent hide this if this is popup.
1417     if (m_mode == HTMLPART_MODE_POPUP && !isUnderMouse(mrg, 0)) {
1418         emit hideChildPopup();
1419     }
1420 }
1421
1422
1423 /* private slot */
1424 void HTMLPart::slotHSliderReleased()
1425 {
1426     QScrollBar * bar = view() ->horizontalScrollBar();
1427     QRect rt = bar->style()->subControlRect(QStyle::CC_Slider, new QStyleOptionComplex(), QStyle::SC_SliderHandle);
1428     int mrg = rt.bottom() - rt.top();
1429
1430     hidePopup();
1431
1432     // emit signal to have parent hide this if this is popup.
1433     if (m_mode == HTMLPART_MODE_POPUP && !isUnderMouse(0, mrg)) {
1434         emit hideChildPopup();
1435     }
1436 }
1437
1438
1439
1440 /* private slot */
1441 void HTMLPart::slotHideChildPopup()
1442 {
1443     hidePopup();
1444
1445     // emit signal to have parent hide this if this is popup.
1446     if (m_mode == HTMLPART_MODE_POPUP && !isUnderMouse(0, 0)) {
1447         emit hideChildPopup();
1448     }
1449 }
1450
1451
1452 /*---------------------------------------------------*/
1453 /* This slot is called when mouse moves onto the URL */ /* private slot */
1454 void HTMLPart::slotOnUrl(const QString& url)
1455 {
1456     // config
1457
1458     const int maxpopup = 10; // max number of responses shown in the popup window
1459
1460     //----------------------------
1461
1462     if (isMultiPopupMode()) return ;
1463
1464     slotDeletePopup();
1465
1466     if (url.isEmpty()) return ;
1467     if (url.left(7) == "mailto:") return ;
1468
1469     // Is Kita active now?
1470     if(ViewMediator::getInstance()->isActive() == false) return;
1471
1472     // get reference
1473     QString refstr;
1474     KUrl datUrl = m_datUrl;
1475     if (url.at(0) == '#') {
1476         refstr = url.mid(1);
1477     } else {
1478         datUrl = getDatUrl(KUrl(m_datUrl, url) , refstr);
1479     }
1480
1481     DatManager datManager(m_datUrl);
1482     //------------------------
1483     // id popup
1484
1485     if (url.left(6) == "#idpop") {
1486         int num = datManager.getNumById(url.mid(6));
1487         QString tmpstr;
1488         if (num >= 2) {
1489             tmpstr = QString("<DIV>ID:%1:[%2]</DIV>").arg(url.mid(6)).arg(num);
1490         } else {
1491             tmpstr = "<DIV>"
1492                 + i18nc("@label:textbox This is the first reply", "None")
1493                 + "</DIV>";
1494         }
1495         showPopup(m_datUrl, tmpstr);
1496         return ;
1497     }
1498
1499
1500     //------------------------
1501     // show reffered num
1502
1503     if (refstr.left(5) == "write") {
1504         int no = refstr.mid(5).toInt();
1505         int num = 0;
1506         datManager.getTreeByRes(no, num);
1507         QString tmpstr;
1508         if (num) {
1509             tmpstr = QString("<DIV>No.%1 : [%2]</DIV>").arg(no).arg(num);
1510         } else {
1511             tmpstr = "<DIV>"
1512                 + i18nc("@label:textbox There is no reply", "None") + "</DIV>";
1513         }
1514         showPopup(m_datUrl, tmpstr);
1515         return ;
1516     }
1517
1518
1519     //------------------------
1520     // abone
1521
1522     if (url.left(6) == "#abone") {
1523         int no = url.mid(6).toInt();
1524         QString tmpstr = datManager.getHtml(no, no, false);
1525         showPopup(m_datUrl, tmpstr);
1526         return ;
1527     }
1528
1529     //-------------------------
1530     // popup for anchor
1531
1532     QString innerHTML;
1533     int refNum;
1534     int refNum2;
1535
1536     int i = refstr.indexOf("-");
1537     if (i != -1) { // >>refNum-refNum2
1538
1539         refNum = refstr.left(i).toInt();
1540         refNum2 = refstr.mid(i + 1).toInt();
1541
1542         if (refNum) {
1543             if (refNum2 < refNum) refNum2 = refNum;
1544             if (refNum2 - refNum > maxpopup - 1) refNum2 = refNum + maxpopup - 1;
1545         }
1546
1547     } else { // >>refNum
1548         refNum = refstr.toInt();
1549         refNum2 = refNum;
1550     }
1551
1552     DatManager localDatManager(datUrl);
1553     // another thread?
1554     if (datUrl.host() != m_datUrl.host() || datUrl.path() != m_datUrl.path()) {
1555
1556         // get board name
1557         BoardDatabase db(datUrl);
1558         QString boardName = db.boardName();
1559         if (!boardName.isEmpty()) innerHTML += '[' + boardName + "] ";
1560
1561         // If idx file of datURL is not read, thread name cannot be obtained.
1562         // so, create DatInfo if cache exists, and read idx file in DatInfo::DatInfo().
1563         localDatManager.getDatInfoPointer();
1564
1565         // get thread Name
1566         QString subName = localDatManager.threadName();
1567         if (!subName.isEmpty()) innerHTML += subName + "<br><br>";
1568
1569         if (!refNum) refNum = refNum2 = 1;
1570     }
1571
1572     // get HTML and show it
1573     if (!refNum) return ;
1574     innerHTML += localDatManager.getHtml(refNum, refNum2);
1575
1576     if (!innerHTML.isEmpty())
1577         showPopup(datUrl, innerHTML);
1578 }
1579
1580
1581
1582 /* If selected Text is composed of only digits,
1583    then show res popup.                          */ /* private */
1584 bool HTMLPart::showSelectedDigitPopup()
1585 {
1586     if (!hasSelection()) return false;
1587
1588     QString linkstr;
1589     int refNum;
1590     QString selectText = selectedText();
1591     const QChar *chpt = selectText.unicode();
1592     unsigned int length = selectText.length();
1593
1594     if ((refNum = stringToPositiveNum(chpt, length)) != -1) {
1595         QString innerHTML = DatManager(m_datUrl).getHtml(refNum, refNum);
1596         if (!innerHTML.isEmpty()) {
1597             showPopup(m_datUrl, innerHTML);
1598             startMultiPopup();
1599             return true;
1600         }
1601     }
1602
1603     return false;
1604 }