OSDN Git Service

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