1 /***************************************************************************
2 * Copyright (C) 2004 by Kita Developers *
3 * ikemo@users.sourceforge.jp *
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 ***************************************************************************/
11 #include <kpopupmenu.h>
13 #include <khtml_events.h>
16 #include <dom/html_element.h>
17 #include <dom/html_misc.h>
20 #include <qapplication.h>
21 #include <qclipboard.h>
22 #include <qmessagebox.h>
29 #include "kitaui/htmlview.h"
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"
40 /*-------------------------------------------*/
43 /*-------------------------------------*/
44 /* Don't forget to call setup() later. */
46 KitaHTMLPart::KitaHTMLPart( QWidget* parent, const char* name )
47 : KHTMLPart( new KitaHTMLView( this, parent, name ) )
49 m_mode = HTMLPART_MODE_MAINPART;
52 m_datURL = QString::null;
53 m_updatedKokoyon = FALSE;
61 KitaHTMLPart::~KitaHTMLPart()
68 void KitaHTMLPart::clearPart()
72 /* delete KitaDomTree */
73 if ( m_domtree ) delete m_domtree;
77 if ( m_mode == HTMLPART_MODE_MAINPART && !m_updatedKokoyon && !m_datURL.isEmpty() ) {
78 int readNum = Kita::DatManager::getReadNum( m_datURL );
80 Kita::DatManager::setViewPos( m_datURL, readNum );
83 m_updatedKokoyon = FALSE;
86 m_anchorStack.clear();
88 m_jumpNumAfterLoading = 0;
91 if ( !m_datURL.isEmpty() ) { /* This part is opened. */
93 /* don't forget to unlock previous datURL here. */
94 Kita::DatManager::unlock( m_datURL );
96 if ( m_mode == HTMLPART_MODE_MAINPART ) { /* This part is on the main thread view. */
98 /* tell Thread class that "thread is closed" */
99 Kita::DatManager::setMainThreadOpened( m_datURL, FALSE );
101 /* emit "deactivated all thread view" SIGNAL */
102 emit activateThreadView( QString::null );
104 /* update subject tab. */
105 emit updateSubjectTab( m_datURL );
109 m_datURL = QString::null;
110 m_mode = HTMLPART_MODE_MAINPART;
116 bool KitaHTMLPart::setup( int mode, const KURL& url )
118 Q_ASSERT( !url.isEmpty() );
122 m_datURL = Kita::getDatURL( url );
125 if ( m_mode == HTMLPART_MODE_MAINPART ) { /* This part is on the main thread view. */
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 );
133 /* tell Thread class that "thread is opend" */
134 Kita::DatManager::setMainThreadOpened( m_datURL, TRUE );
137 Kita::DatManager::resetAbone( m_datURL );
140 /* Lock datURL. Don't forget to unlock it later ! */
141 Kita::DatManager::lock ( m_datURL );
143 /* create HTML Document */
144 createHTMLDocument();
146 /* create DOM manager */
147 if ( m_mode == HTMLPART_MODE_MAINPART ) {
148 m_domtree = new KitaDomTree( htmlDocument(), m_datURL );
156 void KitaHTMLPart::connectSignals()
158 Kita::SignalCollection * signalCollection = Kita::SignalCollection::getInstance();
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() ) );
168 connect( this, SIGNAL( onURL( const QString& ) ), SLOT( slotOnURL( const QString& ) ) );
169 connect( this, SIGNAL( isKitaActive() ), signalCollection, SIGNAL( isKitaActive() ) );
171 connect( view(), SIGNAL( leave() ), SLOT( slotLeave() ) );
172 connect( view(), SIGNAL( verticalSliderReleased() ), SLOT( slotVSliderReleased() ) );
173 connect( view(), SIGNAL( horizontalSliderReleased() ), SLOT( slotHSliderReleased() ) );
175 connect( signalCollection, SIGNAL( kitaIsActive() ), SLOT( slotKitaIsActive() ) );
176 connect( signalCollection, SIGNAL( windowDeactivated() ), SLOT( slotHideChildPopup() ) );
179 connect( this, SIGNAL( openURLRequestExt( const KURL&, const QString ) ),
180 signalCollection, SIGNAL( openURLRequestExt( const KURL&, const QString ) ) );
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& ) ) );
189 connect( this, SIGNAL( updateSubjectTab( const KURL& ) ),
190 signalCollection, SIGNAL( updateSubjectTab( const KURL& ) ) );
196 void KitaHTMLPart::createHTMLDocument()
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() );
205 QString text = "<html><head><style>";
206 text += KitaConfig::defaultStyleSheetText();
208 if ( Kita::Config::useStyleSheet() ) {
209 text += KitaConfig::styleSheetText();
211 text += "</style></head><body></body></html>";
213 setJScriptEnabled( false );
214 setJavaEnabled( false );
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 ?).
220 begin( "file:/dummy.htm" );
225 /*---------------------------------------------------------------*/
226 /*---------------------------------------------------------------*/
227 /* direct rendering functions */
231 * @warning don't forget to call updateScreen() later.
233 void KitaHTMLPart::showResponses( int startnum, int endnum )
235 if ( !m_domtree ) return ;
237 for ( int i = startnum ; i <= endnum; i++ ) m_domtree->appendRes( i );
241 /* do parsing only. */
242 /* call showResponses() later */ /* public */
243 void KitaHTMLPart::parseResponses( int startnum, int endnum )
245 if ( !m_domtree ) return ;
247 for ( int i = startnum ; i <= endnum; i++ ) m_domtree->createResElement( i );
251 /*------------------------------------------------*/
252 /* Show all responses ,header, footer, and etc,
253 if these are not shown. */
255 /* note that updateScreen() is called internally. */
256 /* So, you need not call it later. */ /* public slot */
257 void KitaHTMLPart::showAll()
259 if ( !m_domtree ) return ;
261 int bottom = m_domtree->getBottomResNumber();
262 int readNum = Kita::DatManager::getReadNum( m_datURL );
263 if ( bottom != readNum ) {
265 QCursor qc; qc.setShape( Qt::WaitCursor );
266 QApplication::setOverrideCursor( qc );
268 showResponses( 1, readNum );
269 updateScreen( TRUE, FALSE );
271 QApplication::restoreOverrideCursor();
278 void KitaHTMLPart::updateScreen( bool showHeaderEtc, bool clock )
285 /* show clock cursor */
287 QCursor qc; qc.setShape( Qt::WaitCursor );
288 QApplication::setOverrideCursor( qc );
291 /* show header, footer, and kokomadeyonda, etc. */
292 if ( showHeaderEtc ) {
293 m_domtree->appendKokoyon();
294 m_domtree->appendFooterAndHeader();
297 /* change color of number of the res which is responsed. */
298 if ( m_mode == HTMLPART_MODE_MAINPART ) {
300 if ( Kita::Config::checkResponsed() ) {
301 m_domtree->changeColorOfAllResponsedNumber();
306 htmlDocument().applyChanges();
308 view()->setVScrollBarMode( QScrollView::AlwaysOn );
313 QApplication::restoreOverrideCursor();
319 void KitaHTMLPart::setInnerHTML( const QString& innerHTML )
321 createHTMLDocument();
322 htmlDocument().body().setInnerHTML( innerHTML );
328 /* These slots are connected to signalCollection. */ /* public slot */
329 void KitaHTMLPart::slotRedrawHTMLPart( const KURL& datURL, bool force )
331 if ( m_domtree == NULL ) return ;
332 if ( m_datURL != datURL ) return ;
334 m_domtree->redraw( force );
338 void KitaHTMLPart::slotRedrawAllHTMLPart( bool force )
340 if ( m_domtree == NULL ) return ;
342 m_domtree->redraw( force );
346 void KitaHTMLPart::slotSetFaceOfHTMLPart()
348 QFont font = Kita::Config::threadFont();
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();
359 void KitaHTMLPart::slotSetStyleSheetOfHTMLPart()
361 /* [0]<html> -> [1]<head> -> [2]<style> */
362 DOM::HTMLCollection collection = htmlDocument().all();
363 DOM::HTMLElement elm;
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() );
374 QString style0 = KitaConfig::defaultStyleSheetText();
376 if ( Kita::Config::useStyleSheet() ) {
377 style0 += KitaConfig::styleSheetText();
380 elm.setInnerText( style0 );
381 htmlDocument().applyChanges();
387 /*---------------------------------------------------------------*/
388 /*---------------------------------------------------------------*/
389 /* cache functions */
392 /*----------------------------------*/
393 /* load thread from cache & show it */ /* public */
395 /* top = centerNum - preShowNum
396 bottom = centerNum + afterShowNum
397 readNum = Kita::DatManager::getReadNum
399 No.1 <- show -> No.20 <- not show -> No.(top) <- show -> No.(bottom) <- not show -> No.(readNum) */
401 bool KitaHTMLPart::load( int centerNum )
403 m_centerNum = centerNum;
404 m_jumpNumAfterLoading = 0;
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;
410 int endNum = Kita::DatManager::getReadNum( m_datURL );
411 showResponses( 1, endNum );
412 updateScreen( TRUE , FALSE );
413 gotoAnchor( QString().setNum( m_centerNum ), FALSE );
421 /*----------------------------*/
422 /* start reloading */
424 /* see also slotReceiveData()
425 and slotFinishLoad(). */ /* public */
426 bool KitaHTMLPart::reload( int jumpNum )
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 );
435 m_firstReceive = TRUE;
436 if ( m_centerNum == 0 ) m_centerNum = m_domtree->getBottomResNumber();
437 m_jumpNumAfterLoading = jumpNum;
439 /* DatManager will call back slotReceiveData and slotFinishLoad. */
440 Kita::DatManager::updateCache( m_datURL , this );
448 /*---------------------------------------------*/
449 /* This slot is called after Kita::DatManager
450 received new data, and emits receiveData() */ /* !!! "public" slot !!! */
451 void KitaHTMLPart::slotReceiveData()
453 const int delta = 20;
455 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
456 if ( !m_domtree ) return ;
458 int readNum = Kita::DatManager::getReadNum( m_datURL );
459 int bottom = m_domtree->getBottomResNumber();
462 parseResponses( bottom + 1, readNum );
465 if ( m_firstReceive || bottom + delta < readNum ) {
466 showResponses( bottom + 1, readNum );
467 updateScreen( TRUE, FALSE );
470 if ( m_firstReceive && m_centerNum < readNum ) {
471 gotoAnchor( QString().setNum( m_centerNum ), FALSE );
472 m_firstReceive = FALSE;
479 /*--------------------------------------------*/
480 /* This slot is called after Kita::DatManager
481 finished updating new data,
482 and emits finishReload() */ /* !!! "public" slot !!! */
483 void KitaHTMLPart::slotFinishLoad()
485 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
486 if ( !m_domtree ) return ;
488 int bottom = m_domtree->getBottomResNumber();
489 int shownNum = m_centerNum + 5000;
491 showResponses( bottom + 1, shownNum );
492 updateScreen( TRUE, FALSE );
493 // m_domtree->parseAllRes();
496 if ( m_jumpNumAfterLoading ) gotoAnchor( QString().setNum( m_jumpNumAfterLoading ), FALSE );
497 m_jumpNumAfterLoading = 0;
505 /*---------------------------------------------------------------*/
506 /*---------------------------------------------------------------*/
511 bool KitaHTMLPart::gotoAnchor( const QString& anc, bool pushPosition )
513 if ( anc == QString::null ) return FALSE;
514 if ( !m_domtree || m_mode == HTMLPART_MODE_POPUP )
515 return KHTMLPart::gotoAnchor( anc );
519 QString ancstr = anc;
520 int res = ancstr.toInt();
524 /* is target valid ? */
525 if ( !Kita::DatManager::isResValid( m_datURL, res ) ) return FALSE;
527 ancstr = QString().setNum( res );
530 if ( res == 1 ) ancstr = "header";
531 if ( pushPosition ) pushCurrentPosition();
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
544 /* jump to kokomade yonda */ /* public slot */
545 void KitaHTMLPart::slotGotoKokoyon()
547 if ( !m_domtree ) return ;
548 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
550 int kokoyon = Kita::DatManager::getViewPos( m_datURL );
551 gotoAnchor( QString().setNum( kokoyon ), FALSE );
557 void KitaHTMLPart::slotGobackAnchor()
559 if ( m_anchorStack.empty() ) return ;
561 QString anc = m_anchorStack.last();
562 m_anchorStack.pop_back();
563 gotoAnchor( anc , FALSE );
570 void KitaHTMLPart::pushCurrentPosition()
572 m_anchorStack += getCurrentIDofNode();
576 /* find the id of current node */ /* private */
577 QString KitaHTMLPart::getCurrentIDofNode()
580 node = nodeUnderMouse();
581 while ( node != NULL && node.nodeName().string() != "div" ) node = node.parentNode();
582 if ( node == NULL ) return QString::null;
584 return static_cast<DOM::Element>( node ).getAttribute( "id" ).string();
588 void KitaHTMLPart::slotClickGotoFooter()
590 if ( !m_domtree || m_mode != HTMLPART_MODE_MAINPART ) {
591 gotoAnchor( "footer", FALSE );
595 int bottom = m_domtree->getBottomResNumber();
596 int readNum = Kita::DatManager::getReadNum( m_datURL );
598 if ( readNum != bottom ) {
599 showResponses( bottom + 1, readNum );
600 updateScreen( TRUE, TRUE );
603 gotoAnchor( "footer", FALSE );
607 /*---------------------------------------------------------------*/
608 /*---------------------------------------------------------------*/
613 void KitaHTMLPart::findTextInit()
623 bool KitaHTMLPart::findText( const QString &query, bool reverse )
625 if ( m_mode != HTMLPART_MODE_MAINPART ) return FALSE;
627 QRegExp regexp( query );
628 regexp.setCaseSensitive( FALSE );
631 if ( m_findNode.isNull() ) {
633 m_findNode = htmlDocument().body();
636 /* move to the last child node */
638 while ( !m_findNode.lastChild().isNull() ) m_findNode = m_findNode.lastChild();
639 m_find_y = view() ->contentsHeight();
645 if ( m_findNode.nodeType() == DOM::Node::TEXT_NODE
646 || m_findNode.nodeType() == DOM::Node::CDATA_SECTION_NODE ) {
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 );
653 if ( reverse ) m_findPos = nodestr.findRev( regexp, m_findPos );
654 else m_findPos = nodestr.find( regexp, m_findPos + 1 );
656 /* scroll & select & return */
657 if ( m_findPos != -1 ) {
658 int matchLen = regexp.matchedLength();
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 );
668 } else if ( m_findNode.nodeName().string() == "table" ) {
670 QRect qr = m_findNode.getRect();
672 m_find_y = qr.bottom();
674 } else if ( m_findNode.nodeName().string() == "div" ) {
676 QRect qr = m_findNode.getRect();
679 m_find_y = qr.bottom();
684 } else if ( m_findNode.nodeName().string() == "br" ) {
686 DOM::Node tmpnode = m_findNode.previousSibling();
688 if ( tmpnode != NULL ) {
690 QRect qr = tmpnode.getRect();
691 if ( reverse ) m_find_y -= qr.bottom() - qr.top();
692 else m_find_y += qr.bottom() - qr.top();
696 /*------------------------*/
701 /* move to the next node */
704 next = m_findNode.firstChild();
705 if ( next.isNull() ) next = m_findNode.nextSibling();
707 while ( !m_findNode.isNull() && next.isNull() ) {
708 m_findNode = m_findNode.parentNode();
709 if ( !m_findNode.isNull() ) {
710 next = m_findNode.nextSibling();
717 next = m_findNode.lastChild();
718 if ( next.isNull() ) next = m_findNode.previousSibling();
720 while ( !m_findNode.isNull() && next.isNull() ) {
721 m_findNode = m_findNode.parentNode();
722 if ( !m_findNode.isNull() ) {
723 next = m_findNode.previousSibling();
729 if ( m_findNode.isNull() ) {
743 /*---------------------------------------------------------------*/
744 /*---------------------------------------------------------------*/
749 void KitaHTMLPart::showPopupMenu( const KURL& kurl )
761 /*-----------------*/
762 ID_Back_Link /* stay bottom */
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();
772 /* If selected Text is composed of only digits, then show res popup. */
773 if ( !m_pushctrl && showSelectedDigitPopup() ) return ;
775 /*-----------------------------------*/
776 /* create menu items */
778 KPopupMenu* popupMenu = new KPopupMenu( view() );
779 KPopupMenu* backSubMenu = NULL;
780 KPopupMenu* markSubMenu = NULL;
787 ( m_mode == HTMLPART_MODE_MAINPART ) ) {
792 if ( !m_anchorStack.empty() ) {
793 backSubMenu = new KPopupMenu( view() );
794 backSubMenu->clear();
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 );
803 popupMenu->insertItem( i18n( "Back" ), backSubMenu );
804 popupMenu->insertSeparator();
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();
818 str = QString().setNum( i ) + " " + Kita::DatManager::getPlainBody( m_datURL, i ).left( 10 );
819 markSubMenu->insertItem( str, ID_Goto_Mark + i );
824 popupMenu->insertItem( i18n( "Start" ), ID_Home_Link );
828 if ( m_mode == HTMLPART_MODE_MAINPART ) {
830 int kokoyon = Kita::DatManager::getViewPos( m_datURL );
832 str = i18n( "Kokomade Yonda (%1)" ).arg( kokoyon );
833 popupMenu->insertItem( str, ID_Koko_Link );
838 popupMenu->insertItem( i18n( "End" ), ID_End_Link );
844 if ( hasSelection() ) {
845 if ( showppm ) popupMenu->insertSeparator();
848 popupMenu->insertItem( "Copy", ID_Copy_Str );
851 QString selectedStr = selectedText();
852 if ( selectedStr.length() > 20 ) {
853 selectedStr.truncate( 20 );
854 selectedStr.append( "..." );
857 popupMenu->insertItem( i18n( "Add '%1' to abone list" ).arg( selectedStr ), ID_Abone_Word );
863 if ( url != QString::null ) {
864 if ( showppm ) popupMenu->insertSeparator();
867 popupMenu->insertItem( i18n( "Open with Web Browser" ), ID_Open_Browser );
868 popupMenu->insertSeparator();
869 popupMenu->insertItem( i18n( "Copy Link Location" ), ID_COPY_Link );
873 /*-----------------------------------*/
878 QClipboard * clipboard = QApplication::clipboard();
880 int ret = popupMenu->exec( point );
883 clipboard->setText( url , QClipboard::Clipboard );
884 clipboard->setText( url , QClipboard::Selection );
887 case ID_Open_Browser:
888 emit openURLRequestExt( url, "text/html" );
891 case ID_Home_Link: gotoAnchor( "header", FALSE ); break;
893 case ID_Koko_Link: slotGotoKokoyon(); break;
895 case ID_End_Link: slotClickGotoFooter(); break;
898 clipboard->setText( selectedText(), QClipboard::Clipboard );
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 ) {
908 Kita::AboneConfig::aboneWordList().append( selectedText() );
909 emit redrawHTMLPart( m_datURL, FALSE );
917 if ( ret >= ID_Goto_Mark ) {
918 gotoAnchor( QString().setNum( ret - ID_Goto_Mark ), FALSE );
922 else if ( ret >= ID_Back_Link ) {
923 for ( int i = 0; i < ret - ID_Back_Link; i++ ) m_anchorStack.pop_back();
932 if ( popupMenu ) delete popupMenu;
933 if ( backSubMenu ) delete backSubMenu;
934 if ( markSubMenu ) delete markSubMenu;
937 /*---------------------------------------------------------------*/
938 /*---------------------------------------------------------------*/
942 /* protected */ /* virtual */
943 void KitaHTMLPart::customEvent( QCustomEvent * e )
945 if ( e->type() == EVENT_GotoAnchor ) {
946 KHTMLPart::gotoAnchor( static_cast< GotoAnchorEvent* >( e ) ->getAnc() );
950 KHTMLPart::customEvent( e );
954 /*---------------------------------------------------------------*/
955 /*---------------------------------------------------------------*/
960 void KitaHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent* e )
962 emit mousePressed(); /* to KitaThreadView to focus this view. */
965 if ( e->url().string() != QString::null )
966 kurl = KURL( Kita::BoardManager::boardURL( m_datURL ), e->url().string() );
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;
973 if ( e->url() != NULL ) {
975 if ( e->url().string().at( 0 ) == '#' ) { /* anchor */
977 kurl.setRef( e->url().string().mid( 1 ) ) ;
981 m_pushctrl = m_pushmidbt = m_pushrightbt = FALSE;
986 if ( m_pushrightbt ) {
987 showPopupMenu( kurl );
988 m_pushctrl = m_pushmidbt = m_pushrightbt = FALSE;
992 KHTMLPart::khtmlMousePressEvent( e );
999 /*-------------------------------------------------------*/
1000 /*-------------------------------------------------------*/
1006 void KitaHTMLPart::slotOpenURLRequest( const KURL& urlin, const KParts::URLArgs& )
1008 clickAnchor( urlin );
1012 /*------------------------------------------------------*/
1013 /* This function is called when user clicked res anchor */ /* private */
1014 void KitaHTMLPart::clickAnchor( const KURL& urlin )
1017 KURL datURL = Kita::getDatURL( urlin , refstr );
1019 /*--------------------*/
1020 /* Ctrl + right click */
1021 if ( m_pushctrl && m_pushrightbt ) {
1022 showPopupMenu( urlin );
1026 /*--------------------------------*/
1027 /* If this is not anchor, then */
1028 /* emit openURLRequest and return */
1030 if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
1033 if ( m_pushrightbt ) {
1035 /* start multi-popup mode or show popup menu */
1036 if ( !startMultiPopup() ) showPopupMenu( urlin );
1042 emit openURLRequestExt( urlin );
1046 if ( refstr == QString::null ) return ;
1048 /*---------------------------*/
1049 /* show popupmenu for #write */
1051 if ( refstr.left( 5 ) == "write" ) {
1052 showWritePopupMenu( refstr );
1056 /*----------------------------*/
1057 /* extract responses by ID */
1059 if ( refstr.left( 5 ) == "idpop" ) {
1060 showIDPopup( refstr );
1064 /*---------------------------*/
1065 /* show popupmenu for #bepop */
1067 if ( refstr.left( 5 ) == "bepop" ) {
1068 showBePopupMenu( refstr );
1072 /*-------------------------*/
1073 /* start multi-popup mdde */
1074 if ( m_pushrightbt && startMultiPopup() ) return ;
1077 /*----------------------------*/
1078 /* next 100 ,before 100 ,etc. */
1079 if ( m_mode == HTMLPART_MODE_MAINPART ) {
1080 if ( refstr.left( 7 ) == "tosaigo" ) {
1081 slotClickGotoFooter();
1086 /*-------------------------------*/
1087 /* open Kita Navi or goto anchor */
1089 int refNum, refNum2;
1091 int i = refstr.find( "-" );
1093 refNum = refstr.left( i ).toInt();
1094 refNum2 = refstr.mid( i + 1 ).toInt();
1095 if ( refNum2 < refNum ) {
1099 refNum = refNum2 = refstr.toInt();
1102 if ( !refNum ) return ;
1104 if ( m_mode == HTMLPART_MODE_POPUP ) {
1105 emit openURLRequestExt( urlin );
1107 gotoAnchor( QString().setNum( refNum ), TRUE );
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 )
1121 WRITEMENU_SHOWBROWSER,
1123 WRITEMENU_REVERSERESTREE,
1124 WRITEMENU_EXTRACTNAME,
1127 WRITEMENU_COPYTHREADNAME,
1128 WRITEMENU_SETKOKOYON,
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 );
1139 if ( m_pushrightbt ) {
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 );
1150 /*---------------------*/
1151 /* create popup menu */
1154 KPopupMenu *popupMenu = new KPopupMenu( view() );
1158 if ( m_mode == HTMLPART_MODE_MAINPART ) {
1160 popupMenu->insertItem( i18n( "write response" ), WRITEMENU_RES );
1161 popupMenu->insertItem( i18n( "quote this" ), WRITEMENU_QUOTE );
1162 popupMenu->insertSeparator();
1167 popupMenu->insertItem( i18n( "Mark" ), WRITEMENU_MARK );
1168 popupMenu->setItemChecked( WRITEMENU_MARK, Kita::DatManager::isMarked( m_datURL, resNum ) );
1169 popupMenu->insertSeparator();
1172 popupMenu->insertItem( i18n( "Open with Web Browser" ), WRITEMENU_SHOWBROWSER );
1173 popupMenu->insertSeparator();
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();
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 );
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 );
1193 popupMenu->insertSeparator();
1194 popupMenu->insertItem( i18n( "add name to abone list" ), WRITEMENU_ABONENAME );
1197 /*--------------------------------------*/
1198 /* show popup menu */
1200 int ret = popupMenu->exec( QCursor::pos() );
1205 resstr = ">>" + QString().setNum( resNum ) + "\n";
1206 emit openWriteDialog( resstr );
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 );
1216 case WRITEMENU_MARK:
1217 Kita::DatManager::setMark( m_datURL, resNum, ! Kita::DatManager::isMarked( m_datURL, resNum ) );
1220 case WRITEMENU_COPY:
1221 case WRITEMENU_COPYURL:
1222 case WRITEMENU_COPYTHREADNAME:
1223 str = QString::null;
1226 if ( ret == WRITEMENU_COPYTHREADNAME || ret == WRITEMENU_COPY ) {
1227 str = Kita::DatManager::threadName( m_datURL );
1231 if ( str != QString::null ) str += "\n";
1232 str += Kita::DatManager::threadURL( m_datURL ) + "/" + QString().setNum( resNum ) + "\n";
1235 if ( ret == WRITEMENU_COPY ) {
1237 + Kita::DatManager::getPlainTitle( m_datURL, resNum ) + "\n"
1238 + Kita::DatManager::getPlainBody( m_datURL, resNum ) + "\n";
1242 clipboard->setText( str , QClipboard::Clipboard );
1243 clipboard->setText( str , QClipboard::Selection );
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 );
1255 case WRITEMENU_SHOWBROWSER:
1256 str = Kita::DatManager::threadURL( m_datURL ) + "/" + QString().setNum( resNum );
1258 emit openURLRequestExt( str, "text/html" );
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 ) {
1267 Kita::AboneConfig::aboneNameList().append( namestr );
1268 emit redrawHTMLPart( m_datURL, FALSE );
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 )
1285 QString strid = refstr.mid( 5 )
1286 .replace( "%2B", "+" )
1287 .replace( "%2F", "/" );
1290 if ( m_pushrightbt ) {
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 );
1307 KPopupMenu *popupMenu = new KPopupMenu( view() );
1309 popupMenu->insertItem( i18n( "add id to abone list" ), IDMENU_ABONE );
1310 int ret = popupMenu->exec( QCursor::pos() );
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 ) {
1321 Kita::AboneConfig::aboneIDList().append( strid );
1322 emit redrawHTMLPart( m_datURL, FALSE );
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 )
1339 QString strURL = "http://be.2ch.net/test/p.php?i=" + refstr.mid( 5 )
1340 + "&u=d:" + Kita::DatManager::threadURL( m_datURL ) + "/l50";
1342 if ( m_pushrightbt ) {
1343 /*---------------------*/
1344 /* create popup menu */
1345 KPopupMenu *popupMenu = new KPopupMenu( view() );
1353 QClipboard * clipboard = QApplication::clipboard();
1355 popupMenu->insertItem( i18n( "copy URL" ), BEMENU_COPYURL );
1356 popupMenu->insertItem( i18n( "Open with Web Browser" ), BEMENU_SHOWBROWSER );
1358 /*--------------------------------------*/
1359 /* show popup menu */
1361 int ret = popupMenu->exec( QCursor::pos() );
1365 case BEMENU_COPYURL:
1367 clipboard->setText( strURL, QClipboard::Clipboard );
1368 clipboard->setText( strURL, QClipboard::Selection );
1371 case BEMENU_SHOWBROWSER:
1372 emit openURLRequestExt( strURL, "text/html" );
1379 emit openURLRequestExt( strURL, "text/html" );
1383 /*-------------------------------------------------------*/
1384 /*-------------------------------------------------------*/
1389 bool KitaHTMLPart::isPopupVisible()
1391 if ( !m_popup ) return FALSE;
1392 return m_popup->isVisible();
1397 void KitaHTMLPart::slotDeletePopup()
1399 if ( m_popup ) delete m_popup;
1401 m_multiPopup = FALSE;
1405 /* for convenience */ /* public slot */
1406 void KitaHTMLPart::slotShowResPopup( QPoint point, int refNum, int refNum2 )
1408 QString innerHTML = Kita::DatManager::getHtml( m_datURL, refNum, refNum2 );
1409 if ( innerHTML == QString::null ) return ;
1411 showPopupCore( m_datURL, innerHTML, point );
1415 /* for convenience */ /* private */
1416 void KitaHTMLPart::showPopup( const KURL& url, const QString& innerHTML )
1418 showPopupCore( url, innerHTML, QCursor::pos() );
1422 /* show popup window */ /* private */
1423 void KitaHTMLPart::showPopupCore( const KURL& url, const QString& innerHTML, QPoint point )
1426 m_multiPopup = FALSE;
1428 m_popup = new Kita::ResPopup( view() , url );
1430 connect( m_popup, SIGNAL( hideChildPopup() ), SLOT( slotHideChildPopup() ) );
1432 m_popup->setText( innerHTML );
1433 m_popup->adjustSize();
1434 m_popup->adjustPos( point );
1439 /*------------------------*/
1440 /* start multi-popup mode */ /* private */
1441 bool KitaHTMLPart::startMultiPopup()
1444 if ( m_popup && m_popup->isVisible() ) {
1445 m_multiPopup = TRUE;
1446 m_popup->moveMouseAbove();
1448 m_multiPopup = FALSE;
1451 return m_multiPopup;
1455 /* Is it multi-popup mode now ? */ /* private */
1456 bool KitaHTMLPart::isMultiPopupMode()
1459 m_multiPopup = FALSE;
1460 } else if ( m_popup->isHidden() ) {
1461 m_multiPopup = FALSE;
1464 return m_multiPopup;
1468 void KitaHTMLPart::hidePopup()
1473 m_multiPopup = FALSE;
1476 /* return TRUE if this view is under mouse. */ /* private */
1477 bool KitaHTMLPart::isUnderMouse( int mrgwd, int mrght )
1479 QPoint pos = QCursor::pos();
1480 int cx = pos.x(), cy = pos.y();
1482 QPoint viewpos = view() ->mapToGlobal( QPoint( 0, 0 ) );
1483 int px = viewpos.x(), py = viewpos.y();
1484 int wd = view() ->visibleWidth(), ht = view() ->visibleHeight();
1486 if ( ( px < cx && cx < px + wd + mrgwd )
1487 && ( py < cy && cy < py + ht + mrght ) ) {
1495 void KitaHTMLPart::slotLeave()
1497 if ( isMultiPopupMode() ) return ;
1498 if ( view() ->isHorizontalSliderPressed() ) return ;
1499 if ( view() ->isVerticalSliderPressed () ) return ;
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();
1510 void KitaHTMLPart::slotVSliderReleased()
1512 QScrollBar * bar = view() ->verticalScrollBar();
1513 QRect rt = bar->sliderRect();
1514 int mrg = rt.right() - rt.left();
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();
1526 void KitaHTMLPart::slotHSliderReleased()
1528 QScrollBar * bar = view() ->horizontalScrollBar();
1529 QRect rt = bar->sliderRect();
1530 int mrg = rt.bottom() - rt.top();
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();
1543 void KitaHTMLPart::slotHideChildPopup()
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();
1555 /*------------------------------------------*/
1556 /* called back when kita is active .
1557 see also an explanation in slotOnURL. */ /* private slot */
1558 void KitaHTMLPart::slotKitaIsActive()
1560 m_kitaIsActive = TRUE;
1565 /*---------------------------------------------------*/
1566 /* This slot is called when mouse moves onto the URL */ /* private slot */
1567 void KitaHTMLPart::slotOnURL( const QString& url )
1571 const int maxpopup = 10; /* max number of responses shown in the popup window */
1573 /*----------------------------*/
1575 if ( isMultiPopupMode() ) return ;
1579 if ( url.isEmpty() ) return ;
1580 if ( url.left( 7 ) == "mailto:" ) return ;
1582 /* Is Kita active now ?
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 ;
1593 KURL datURL = m_datURL;
1594 if ( url.at( 0 ) == '#' ) {
1595 refstr = url.mid( 1 );
1597 datURL = Kita::getDatURL( KURL( m_datURL, url ) , refstr );
1600 /*------------------------*/
1603 if ( url.left( 6 ) == "#idpop" ) {
1604 int num = Kita::DatManager::getNumByID( m_datURL, url.mid( 6 ) );
1607 tmpstr = QString( "<DIV>ID:%1:[%2]</DIV>" ).arg( url.mid( 6 ) ).arg( num );
1609 tmpstr = "<DIV>" + i18n( "None" ) + "</DIV>";
1611 showPopup( m_datURL, tmpstr );
1616 /*------------------------*/
1617 /* show reffered num */
1619 if ( refstr.left( 5 ) == "write" ) {
1620 int no = refstr.mid( 5 ).toInt();
1622 Kita::DatManager::getTreeByRes( m_datURL, no, num );
1625 tmpstr = QString( "<DIV>No.%1 : [%2]</DIV>" ).arg( no ).arg( num );
1627 tmpstr = "<DIV>" + i18n( "None" ) + "</DIV>";
1629 showPopup( m_datURL, tmpstr );
1634 /*------------------------*/
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 );
1644 /*-------------------------*/
1645 /* popup for anchor */
1647 QString innerHTML = QString::null;
1651 int i = refstr.find( "-" );
1652 if ( i != -1 ) { /* >>refNum-refNum2 */
1654 refNum = refstr.left( i ).toInt();
1655 refNum2 = refstr.mid( i + 1 ).toInt();
1658 if ( refNum2 < refNum ) refNum2 = refNum;
1659 if ( refNum2 - refNum > maxpopup - 1 ) refNum2 = refNum + maxpopup - 1;
1662 } else { /* >>refNum */
1663 refNum = refstr.toInt();
1667 /* another thread ? */
1668 if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
1670 /* get board name */
1671 QString boardName = Kita::BoardManager::boardName( datURL );
1672 if ( boardName != QString::null ) innerHTML += "[" + boardName + "] ";
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 );
1678 /* get thread Name */
1679 QString subName = Kita::DatManager::threadName( datURL );
1680 if ( subName != QString::null ) innerHTML += subName + "<br><br>";
1682 if ( !refNum ) refNum = refNum2 = 1;
1685 /* get HTML and show it */
1686 if ( !refNum ) return ;
1687 innerHTML += Kita::DatManager::getHtml( datURL, refNum, refNum2 );
1689 if ( innerHTML != QString::null ) showPopup( datURL, innerHTML );
1694 /* If selected Text is composed of only digits,
1695 then show res popup. */ /* private */
1696 bool KitaHTMLPart::showSelectedDigitPopup()
1698 if ( !hasSelection() ) return FALSE;
1702 QString selectText = selectedText();
1703 const QChar *chpt = selectText.unicode();
1704 unsigned int length = selectText.length();
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 );