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>
17 #include <dom/html_element.h>
18 #include <dom/html_misc.h>
21 #include <qapplication.h>
22 #include <qclipboard.h>
23 #include <qmessagebox.h>
29 #include "viewmediator.h"
31 #include "kitaui/htmlview.h"
33 #include "libkita/kitaconfig.h"
34 #include "libkita/datmanager.h"
35 #include "libkita/boardmanager.h"
36 #include "libkita/datinfo.h"
37 #include "libkita/kita_misc.h"
38 #include "libkita/signalcollection.h"
39 #include "libkita/config_xt.h"
40 #include "libkita/abone.h"
42 /*-------------------------------------------*/
45 /*-------------------------------------*/
46 /* Don't forget to call setup() later. */
48 KitaHTMLPart::KitaHTMLPart( QWidget* parent, const char* name )
49 : KHTMLPart( new KitaHTMLView( this, parent, name ) )
51 m_mode = HTMLPART_MODE_MAINPART;
54 m_datURL = QString::null;
55 m_updatedKokoyon = FALSE;
63 KitaHTMLPart::~KitaHTMLPart()
70 void KitaHTMLPart::clearPart()
74 /* delete KitaDomTree */
75 if ( m_domtree ) delete m_domtree;
79 if ( m_mode == HTMLPART_MODE_MAINPART && !m_updatedKokoyon && !m_datURL.isEmpty() ) {
80 int readNum = Kita::DatManager::getReadNum( m_datURL );
82 Kita::DatManager::setViewPos( m_datURL, readNum );
85 m_updatedKokoyon = FALSE;
88 m_anchorStack.clear();
90 m_jumpNumAfterLoading = 0;
93 if ( !m_datURL.isEmpty() ) { /* This part is opened. */
95 /* don't forget to unlock previous datURL here. */
96 Kita::DatManager::unlock( m_datURL );
98 if ( m_mode == HTMLPART_MODE_MAINPART ) { /* This part is on the main thread view. */
100 /* tell Thread class that "thread is closed" */
101 Kita::DatManager::setMainThreadOpened( m_datURL, FALSE );
103 /* emit "deactivated all thread view" SIGNAL */
104 ViewMediator::getInstance()->changeWriteTab( QString::null );
106 /* update subject tab. */
110 m_datURL = QString::null;
111 m_mode = HTMLPART_MODE_MAINPART;
117 bool KitaHTMLPart::setup( int mode, const KURL& url )
119 Q_ASSERT( !url.isEmpty() );
123 m_datURL = Kita::getDatURL( url );
126 if ( m_mode == HTMLPART_MODE_MAINPART ) { /* This part is on the main thread view. */
128 /* create DatInfo explicitly to open new thread. */
129 /* Usually, DatInfo is NOT created if ReadNum == 0.*/
130 /* See also DatManager::createDatInfo() and */
131 /* DatManager::getDatInfo(). */
132 Kita::DatManager::createDatInfo( m_datURL );
134 /* tell Thread class that "thread is opend" */
135 Kita::DatManager::setMainThreadOpened( m_datURL, TRUE );
138 Kita::DatManager::resetAbone( m_datURL );
141 /* Lock datURL. Don't forget to unlock it later ! */
142 Kita::DatManager::lock ( m_datURL );
144 /* create HTML Document */
145 createHTMLDocument();
147 /* create DOM manager */
148 if ( m_mode == HTMLPART_MODE_MAINPART ) {
149 m_domtree = new KitaDomTree( htmlDocument(), m_datURL );
157 void KitaHTMLPart::connectSignals()
159 Kita::SignalCollection * signalCollection = Kita::SignalCollection::getInstance();
162 connect( this, SIGNAL( onURL( const QString& ) ), SLOT( slotOnURL( const QString& ) ) );
164 connect( view(), SIGNAL( leave() ), SLOT( slotLeave() ) );
165 connect( view(), SIGNAL( verticalSliderReleased() ), SLOT( slotVSliderReleased() ) );
166 connect( view(), SIGNAL( horizontalSliderReleased() ), SLOT( slotHSliderReleased() ) );
168 connect( signalCollection, SIGNAL( windowDeactivated() ), SLOT( slotHideChildPopup() ) );
174 void KitaHTMLPart::createHTMLDocument()
177 QString style = QString( "body { font-size: %1pt; font-family: \"%2\"; color: %3; background-color: %4; }" )
178 .arg( Kita::Config::threadFont().pointSize() )
179 .arg( Kita::Config::threadFont().family() )
180 .arg( Kita::Config::threadColor().name() )
181 .arg( Kita::Config::threadBackground().name() );
183 QString text = "<html><head><style>";
184 text += KitaConfig::defaultStyleSheetText();
186 if ( Kita::Config::useStyleSheet() ) {
187 text += KitaConfig::styleSheetText();
189 text += "</style></head><body></body></html>";
191 setJScriptEnabled( FALSE );
192 setJavaEnabled( FALSE );
194 /* Use dummy URL here, and protocol should be "file:".
195 If protocol is "http:", local image files are not shown
196 (for security reasons ?).
198 begin( "file:/dummy.htm" );
203 /*---------------------------------------------------------------*/
204 /*---------------------------------------------------------------*/
205 /* direct rendering functions */
209 * @warning don't forget to call updateScreen() later.
211 void KitaHTMLPart::showResponses( int startnum, int endnum )
213 if ( !m_domtree ) return ;
215 for ( int i = startnum ; i <= endnum; i++ ) m_domtree->appendRes( i );
219 /* do parsing only. */
220 /* call showResponses() later */ /* public */
221 void KitaHTMLPart::parseResponses( int startnum, int endnum )
223 if ( !m_domtree ) return ;
225 for ( int i = startnum ; i <= endnum; i++ ) m_domtree->createResElement( i );
229 /*------------------------------------------------*/
230 /* Show all responses ,header, footer, and etc,
231 if these are not shown. */
233 /* note that updateScreen() is called internally. */
234 /* So, you need not call it later. */ /* public slot */
235 void KitaHTMLPart::showAll()
237 if ( !m_domtree ) return ;
239 int bottom = m_domtree->getBottomResNumber();
240 int readNum = Kita::DatManager::getReadNum( m_datURL );
241 if ( bottom != readNum ) {
243 QCursor qc; qc.setShape( Qt::WaitCursor );
244 QApplication::setOverrideCursor( qc );
246 showResponses( 1, readNum );
247 updateScreen( TRUE, FALSE );
249 QApplication::restoreOverrideCursor();
256 void KitaHTMLPart::updateScreen( bool showHeaderEtc, bool clock )
263 /* show clock cursor */
265 QCursor qc; qc.setShape( Qt::WaitCursor );
266 QApplication::setOverrideCursor( qc );
269 /* show header, footer, and kokomadeyonda, etc. */
270 if ( showHeaderEtc ) {
271 m_domtree->appendKokoyon();
272 m_domtree->appendFooterAndHeader();
275 /* change color of number of the res which is responsed. */
276 if ( m_mode == HTMLPART_MODE_MAINPART ) {
278 if ( Kita::Config::checkResponsed() ) {
279 m_domtree->changeColorOfAllResponsedNumber();
284 htmlDocument().applyChanges();
286 view()->setVScrollBarMode( QScrollView::AlwaysOn );
291 QApplication::restoreOverrideCursor();
297 void KitaHTMLPart::setInnerHTML( const QString& innerHTML )
299 createHTMLDocument();
300 htmlDocument().body().setInnerHTML( innerHTML );
306 /* These slots are connected to signalCollection. */ /* public slot */
307 void KitaHTMLPart::redrawHTMLPart( const KURL& datURL, bool force )
309 if ( m_domtree == NULL ) return ;
310 if ( m_datURL != datURL ) return ;
312 m_domtree->redraw( force );
316 void KitaHTMLPart::slotSetFaceOfHTMLPart()
318 QFont font = Kita::Config::threadFont();
320 DOM::CSSStyleDeclaration style = htmlDocument().body().style();
321 style.setProperty( "font-family", font.family(), "" );
322 style.setProperty( "font-size", QString( "%1pt" ).arg( font.pointSize() ), "" );
323 style.setProperty( "color", Kita::Config::threadColor().name(), "" );
324 style.setProperty( "background-color", Kita::Config::threadBackground().name(), "" );
325 htmlDocument().applyChanges();
328 /*---------------------------------------------------------------*/
329 /*---------------------------------------------------------------*/
330 /* cache functions */
333 /*----------------------------------*/
334 /* load thread from cache & show it */ /* public */
336 /* top = centerNum - preShowNum
337 bottom = centerNum + afterShowNum
338 readNum = Kita::DatManager::getReadNum
340 No.1 <- show -> No.20 <- not show -> No.(top) <- show -> No.(bottom) <- not show -> No.(readNum) */
342 bool KitaHTMLPart::load( int centerNum )
344 m_centerNum = centerNum;
345 m_jumpNumAfterLoading = 0;
347 if ( m_mode != HTMLPART_MODE_MAINPART ) return FALSE;
348 if ( !m_domtree ) return FALSE;
349 if ( Kita::DatManager::getReadNum( m_datURL ) == 0 ) return FALSE;
351 int endNum = Kita::DatManager::getReadNum( m_datURL );
352 showResponses( 1, endNum );
353 updateScreen( TRUE , FALSE );
354 gotoAnchor( QString().setNum( m_centerNum ), FALSE );
362 /*----------------------------*/
363 /* start reloading */
365 /* see also slotReceiveData()
366 and slotFinishLoad(). */ /* public */
367 bool KitaHTMLPart::reload( int jumpNum )
369 if ( !m_domtree ) return FALSE;
370 if ( m_mode != HTMLPART_MODE_MAINPART ) {
371 /* If this is not MainPart, then open MainPart. */
372 ViewMediator::getInstance()->openURL( m_datURL );
376 m_firstReceive = TRUE;
377 if ( m_centerNum == 0 ) m_centerNum = m_domtree->getBottomResNumber();
378 m_jumpNumAfterLoading = jumpNum;
380 /* DatManager will call back slotReceiveData and slotFinishLoad. */
381 Kita::DatManager::updateCache( m_datURL , this );
389 /*---------------------------------------------*/
390 /* This slot is called after Kita::DatManager
391 received new data, and emits receiveData() */ /* !!! "public" slot !!! */
392 void KitaHTMLPart::slotReceiveData()
394 const int delta = 20;
396 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
397 if ( !m_domtree ) return ;
399 int readNum = Kita::DatManager::getReadNum( m_datURL );
400 int bottom = m_domtree->getBottomResNumber();
403 parseResponses( bottom + 1, readNum );
406 if ( m_firstReceive || bottom + delta < readNum ) {
407 showResponses( bottom + 1, readNum );
408 updateScreen( TRUE, FALSE );
411 if ( m_firstReceive && m_centerNum < readNum ) {
412 gotoAnchor( QString().setNum( m_centerNum ), FALSE );
413 m_firstReceive = FALSE;
420 /*--------------------------------------------*/
421 /* This slot is called after Kita::DatManager
422 finished updating new data,
423 and emits finishReload() */ /* !!! "public" slot !!! */
424 void KitaHTMLPart::slotFinishLoad()
426 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
427 if ( !m_domtree ) return ;
429 int bottom = m_domtree->getBottomResNumber();
430 int shownNum = m_centerNum + 5000;
432 showResponses( bottom + 1, shownNum );
433 updateScreen( TRUE, FALSE );
434 // m_domtree->parseAllRes();
437 if ( m_jumpNumAfterLoading ) gotoAnchor( QString().setNum( m_jumpNumAfterLoading ), FALSE );
438 m_jumpNumAfterLoading = 0;
446 /*---------------------------------------------------------------*/
447 /*---------------------------------------------------------------*/
452 bool KitaHTMLPart::gotoAnchor( const QString& anc, bool pushPosition )
454 if ( anc == QString::null ) return FALSE;
455 if ( !m_domtree || m_mode == HTMLPART_MODE_POPUP )
456 return KHTMLPart::gotoAnchor( anc );
460 QString ancstr = anc;
461 int res = ancstr.toInt();
465 /* is target valid ? */
466 if ( !Kita::DatManager::isResValid( m_datURL, res ) ) return FALSE;
468 ancstr = QString().setNum( res );
471 if ( res == 1 ) ancstr = "header";
472 if ( pushPosition ) pushCurrentPosition();
474 /* KHTMLPart::gotoAnchor() will fail if the thread is not shown. */
475 /* So KHTMLPart::gotoAnchor() should be called via custom event. */
476 /* See also KitaHTMLPart::customEvent() */
477 GotoAnchorEvent * e = new GotoAnchorEvent( ancstr );
478 QApplication::postEvent( this, e ); // Qt will delete it when done
485 /* jump to kokomade yonda */ /* public slot */
486 void KitaHTMLPart::slotGotoKokoyon()
488 if ( !m_domtree ) return ;
489 if ( m_mode != HTMLPART_MODE_MAINPART ) return ;
491 int kokoyon = Kita::DatManager::getViewPos( m_datURL );
492 gotoAnchor( QString().setNum( kokoyon ), FALSE );
498 void KitaHTMLPart::slotGobackAnchor()
500 if ( m_anchorStack.empty() ) return ;
502 QString anc = m_anchorStack.last();
503 m_anchorStack.pop_back();
504 gotoAnchor( anc , FALSE );
511 void KitaHTMLPart::pushCurrentPosition()
513 m_anchorStack += getCurrentIDofNode();
517 /* find the id of current node */ /* private */
518 QString KitaHTMLPart::getCurrentIDofNode()
521 node = nodeUnderMouse();
522 while ( node != NULL && node.nodeName().string() != "div" ) node = node.parentNode();
523 if ( node == NULL ) return QString::null;
525 return static_cast<DOM::Element>( node ).getAttribute( "id" ).string();
529 void KitaHTMLPart::slotClickGotoFooter()
531 if ( !m_domtree || m_mode != HTMLPART_MODE_MAINPART ) {
532 gotoAnchor( "footer", FALSE );
536 int bottom = m_domtree->getBottomResNumber();
537 int readNum = Kita::DatManager::getReadNum( m_datURL );
539 if ( readNum != bottom ) {
540 showResponses( bottom + 1, readNum );
541 updateScreen( TRUE, TRUE );
544 gotoAnchor( "footer", FALSE );
548 /*---------------------------------------------------------------*/
549 /*---------------------------------------------------------------*/
554 void KitaHTMLPart::findTextInit()
564 bool KitaHTMLPart::findText( const QString &query, bool reverse )
566 if ( m_mode != HTMLPART_MODE_MAINPART ) return FALSE;
568 QRegExp regexp( query );
569 regexp.setCaseSensitive( FALSE );
572 if ( m_findNode.isNull() ) {
574 m_findNode = htmlDocument().body();
577 /* move to the last child node */
579 while ( !m_findNode.lastChild().isNull() ) m_findNode = m_findNode.lastChild();
580 m_find_y = view() ->contentsHeight();
586 if ( m_findNode.nodeType() == DOM::Node::TEXT_NODE
587 || m_findNode.nodeType() == DOM::Node::CDATA_SECTION_NODE ) {
589 /* find the word in the current node */
590 DOM::DOMString nodeText = m_findNode.nodeValue();
591 QString nodestr = nodeText.string();
592 if ( reverse && m_findPos != -1 ) nodestr.setLength( m_findPos );
594 if ( reverse ) m_findPos = nodestr.findRev( regexp, m_findPos );
595 else m_findPos = nodestr.find( regexp, m_findPos + 1 );
597 /* scroll & select & return */
598 if ( m_findPos != -1 ) {
599 int matchLen = regexp.matchedLength();
601 QRect qr = m_findNode.getRect();
602 view() ->setContentsPos( qr.left() - 50, m_find_y - 100 );
603 DOM::Range rg( m_findNode, m_findPos, m_findNode, m_findPos + matchLen );
609 } else if ( m_findNode.nodeName().string() == "table" ) {
611 QRect qr = m_findNode.getRect();
613 m_find_y = qr.bottom();
615 } else if ( m_findNode.nodeName().string() == "div" ) {
617 QRect qr = m_findNode.getRect();
620 m_find_y = qr.bottom();
625 } else if ( m_findNode.nodeName().string() == "br" ) {
627 DOM::Node tmpnode = m_findNode.previousSibling();
629 if ( tmpnode != NULL ) {
631 QRect qr = tmpnode.getRect();
632 if ( reverse ) m_find_y -= qr.bottom() - qr.top();
633 else m_find_y += qr.bottom() - qr.top();
637 /*------------------------*/
642 /* move to the next node */
645 next = m_findNode.firstChild();
646 if ( next.isNull() ) next = m_findNode.nextSibling();
648 while ( !m_findNode.isNull() && next.isNull() ) {
649 m_findNode = m_findNode.parentNode();
650 if ( !m_findNode.isNull() ) {
651 next = m_findNode.nextSibling();
658 next = m_findNode.lastChild();
659 if ( next.isNull() ) next = m_findNode.previousSibling();
661 while ( !m_findNode.isNull() && next.isNull() ) {
662 m_findNode = m_findNode.parentNode();
663 if ( !m_findNode.isNull() ) {
664 next = m_findNode.previousSibling();
670 if ( m_findNode.isNull() ) {
684 /*---------------------------------------------------------------*/
685 /*---------------------------------------------------------------*/
690 void KitaHTMLPart::showPopupMenu( const KURL& kurl )
702 /*-----------------*/
703 ID_Back_Link /* stay bottom */
706 QPoint point = QCursor::pos();
707 QString url = kurl.prettyURL();
708 bool showppm = FALSE;
709 const int ID_Goto_Mark = ID_Back_Link + m_anchorStack.size();
713 /* If selected Text is composed of only digits, then show res popup. */
714 if ( !m_pushctrl && showSelectedDigitPopup() ) return ;
716 /*-----------------------------------*/
717 /* create menu items */
719 KPopupMenu* popupMenu = new KPopupMenu( view() );
720 KPopupMenu* backSubMenu = NULL;
721 KPopupMenu* markSubMenu = NULL;
728 ( m_mode == HTMLPART_MODE_MAINPART ) ) {
733 if ( !m_anchorStack.empty() ) {
734 backSubMenu = new KPopupMenu( view() );
735 backSubMenu->clear();
737 int i = m_anchorStack.size();
738 QStringList::iterator it;
739 for ( it = m_anchorStack.begin(); it != m_anchorStack.end(); it++, i-- ) {
740 str = ( *it ) + " " + Kita::DatManager::getPlainBody( m_datURL, ( *it ).toInt() ).left( 10 );
741 backSubMenu->insertItem( str, ID_Back_Link + ( i - 1 ), 0 );
744 popupMenu->insertItem( i18n( "Back" ), backSubMenu );
745 popupMenu->insertSeparator();
749 int readNum = Kita::DatManager::getReadNum( m_datURL );
750 for ( int i = 1; i <= readNum ; i++ ) {
751 if ( Kita::DatManager::isMarked( m_datURL, i ) ) {
752 if ( !markSubMenu ) {
753 markSubMenu = new KPopupMenu( view() );
754 markSubMenu->clear();
755 popupMenu->insertItem( i18n( "Mark" ), markSubMenu );
756 popupMenu->insertSeparator();
759 str = QString().setNum( i ) + " " + Kita::DatManager::getPlainBody( m_datURL, i ).left( 10 );
760 markSubMenu->insertItem( str, ID_Goto_Mark + i );
765 popupMenu->insertItem( i18n( "Start" ), ID_Home_Link );
769 if ( m_mode == HTMLPART_MODE_MAINPART ) {
771 int kokoyon = Kita::DatManager::getViewPos( m_datURL );
773 str = i18n( "Kokomade Yonda (%1)" ).arg( kokoyon );
774 popupMenu->insertItem( str, ID_Koko_Link );
779 popupMenu->insertItem( i18n( "End" ), ID_End_Link );
785 if ( hasSelection() ) {
786 if ( showppm ) popupMenu->insertSeparator();
789 popupMenu->insertItem( "Copy", ID_Copy_Str );
792 QString selectedStr = selectedText();
793 if ( selectedStr.length() > 20 ) {
794 selectedStr.truncate( 20 );
795 selectedStr.append( "..." );
798 popupMenu->insertItem( i18n( "Add '%1' to abone list" ).arg( selectedStr ), ID_Abone_Word );
804 if ( url != QString::null ) {
805 if ( showppm ) popupMenu->insertSeparator();
808 popupMenu->insertItem( i18n( "Open with Web Browser" ), ID_Open_Browser );
809 popupMenu->insertSeparator();
810 popupMenu->insertItem( i18n( "Copy Link Location" ), ID_COPY_Link );
814 /*-----------------------------------*/
819 QClipboard * clipboard = QApplication::clipboard();
821 int ret = popupMenu->exec( point );
824 clipboard->setText( url , QClipboard::Clipboard );
825 clipboard->setText( url , QClipboard::Selection );
828 case ID_Open_Browser:
829 KRun::runURL( url, "text/html" );
832 case ID_Home_Link: gotoAnchor( "header", FALSE ); break;
834 case ID_Koko_Link: slotGotoKokoyon(); break;
836 case ID_End_Link: slotClickGotoFooter(); break;
839 clipboard->setText( selectedText(), QClipboard::Clipboard );
844 if ( QMessageBox::information( view(), "Kita",
845 i18n( "Do you want to add '%1' to abone list ?" ).arg( selectedText() ),
846 QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
847 == QMessageBox::Ok ) {
849 Kita::AboneConfig::aboneWordList().append( selectedText() );
850 redrawHTMLPart( m_datURL, FALSE );
858 if ( ret >= ID_Goto_Mark ) {
859 gotoAnchor( QString().setNum( ret - ID_Goto_Mark ), FALSE );
863 else if ( ret >= ID_Back_Link ) {
864 for ( int i = 0; i < ret - ID_Back_Link; i++ ) m_anchorStack.pop_back();
873 if ( popupMenu ) delete popupMenu;
874 if ( backSubMenu ) delete backSubMenu;
875 if ( markSubMenu ) delete markSubMenu;
878 /*---------------------------------------------------------------*/
879 /*---------------------------------------------------------------*/
883 /* protected */ /* virtual */
884 void KitaHTMLPart::customEvent( QCustomEvent * e )
886 if ( e->type() == EVENT_GotoAnchor ) {
887 KHTMLPart::gotoAnchor( static_cast< GotoAnchorEvent* >( e ) ->getAnc() );
891 KHTMLPart::customEvent( e );
895 /*---------------------------------------------------------------*/
896 /*---------------------------------------------------------------*/
901 void KitaHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent* e )
903 emit mousePressed(); /* to KitaThreadView to focus this view. */
906 if ( e->url().string() != QString::null )
907 kurl = KURL( Kita::BoardManager::boardURL( m_datURL ), e->url().string() );
909 m_pushctrl = m_pushmidbt = m_pushrightbt = FALSE;
910 if ( e->qmouseEvent() ->button() & Qt::RightButton ) m_pushrightbt = TRUE;
911 if ( e->qmouseEvent() ->state() & Qt::ControlButton ) m_pushctrl = TRUE;
912 if ( e->qmouseEvent() ->button() & Qt::MidButton ) m_pushmidbt = TRUE;
914 if ( e->url() != NULL ) {
916 if ( e->url().string().at( 0 ) == '#' ) { /* anchor */
918 kurl.setRef( e->url().string().mid( 1 ) ) ;
922 m_pushctrl = m_pushmidbt = m_pushrightbt = FALSE;
927 if ( m_pushrightbt ) {
928 showPopupMenu( kurl );
929 m_pushctrl = m_pushmidbt = m_pushrightbt = FALSE;
933 KHTMLPart::khtmlMousePressEvent( e );
940 /*-------------------------------------------------------*/
941 /*-------------------------------------------------------*/
947 void KitaHTMLPart::slotOpenURLRequest( const KURL& urlin, const KParts::URLArgs& )
949 clickAnchor( urlin );
953 /*------------------------------------------------------*/
954 /* This function is called when user clicked res anchor */ /* private */
955 void KitaHTMLPart::clickAnchor( const KURL& urlin )
958 KURL datURL = Kita::getDatURL( urlin , refstr );
960 /*--------------------*/
961 /* Ctrl + right click */
962 if ( m_pushctrl && m_pushrightbt ) {
963 showPopupMenu( urlin );
967 /*--------------------------------*/
968 /* If this is not anchor, then */
969 /* emit openURLRequest and return */
971 if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
974 if ( m_pushrightbt ) {
976 /* start multi-popup mode or show popup menu */
977 if ( !startMultiPopup() ) showPopupMenu( urlin );
983 ViewMediator::getInstance()->openURL( urlin );
987 if ( refstr == QString::null ) return ;
989 /*---------------------------*/
990 /* show popupmenu for #write */
992 if ( refstr.left( 5 ) == "write" ) {
993 showWritePopupMenu( refstr );
997 /*----------------------------*/
998 /* extract responses by ID */
1000 if ( refstr.left( 5 ) == "idpop" ) {
1001 showIDPopup( refstr );
1005 /*---------------------------*/
1006 /* show popupmenu for #bepop */
1008 if ( refstr.left( 5 ) == "bepop" ) {
1009 showBePopupMenu( refstr );
1013 /*-------------------------*/
1014 /* start multi-popup mdde */
1015 if ( m_pushrightbt && startMultiPopup() ) return ;
1018 /*----------------------------*/
1019 /* next 100 ,before 100 ,etc. */
1020 if ( m_mode == HTMLPART_MODE_MAINPART ) {
1021 if ( refstr.left( 7 ) == "tosaigo" ) {
1022 slotClickGotoFooter();
1027 /*-------------------------------*/
1028 /* open Kita Navi or goto anchor */
1030 int refNum, refNum2;
1032 int i = refstr.find( "-" );
1034 refNum = refstr.left( i ).toInt();
1035 refNum2 = refstr.mid( i + 1 ).toInt();
1036 if ( refNum2 < refNum ) {
1040 refNum = refNum2 = refstr.toInt();
1043 if ( !refNum ) return ;
1045 if ( m_mode == HTMLPART_MODE_POPUP ) {
1046 ViewMediator::getInstance()->openURL( urlin );
1048 gotoAnchor( QString().setNum( refNum ), TRUE );
1054 /*---------------------------------------------------------*/
1055 /* popup menu that is opened when user clicked res number. */
1056 /* This funtcion is called in only clickAnchor(). */ /* private */
1057 void KitaHTMLPart::showWritePopupMenu( const QString& refstr )
1062 WRITEMENU_SHOWBROWSER,
1064 WRITEMENU_REVERSERESTREE,
1065 WRITEMENU_EXTRACTNAME,
1068 WRITEMENU_COPYTHREADNAME,
1069 WRITEMENU_SETKOKOYON,
1074 QClipboard * clipboard = QApplication::clipboard();
1075 QString str, resstr;
1076 int resNum = refstr.mid( 5 ).toInt();
1077 QString namestr = Kita::DatManager::getPlainName( m_datURL, resNum );
1080 if ( m_pushrightbt ) {
1082 QString htmlstr = Kita::DatManager::getTreeByRes( m_datURL, resNum, num );
1083 if ( !num ) return ;
1084 QString tmpstr = QString( "<DIV>No.%1 : [%2]<BR>" ).arg( resNum ).arg( num );
1085 tmpstr += htmlstr + "<BR><BR></DIV>";
1086 showPopup( m_datURL, tmpstr );
1091 /*---------------------*/
1092 /* create popup menu */
1095 KPopupMenu *popupMenu = new KPopupMenu( view() );
1099 if ( m_mode == HTMLPART_MODE_MAINPART ) {
1101 popupMenu->insertItem( i18n( "write response" ), WRITEMENU_RES );
1102 popupMenu->insertItem( i18n( "quote this" ), WRITEMENU_QUOTE );
1103 popupMenu->insertSeparator();
1108 popupMenu->insertItem( i18n( "Mark" ), WRITEMENU_MARK );
1109 popupMenu->setItemChecked( WRITEMENU_MARK, Kita::DatManager::isMarked( m_datURL, resNum ) );
1110 popupMenu->insertSeparator();
1113 popupMenu->insertItem( i18n( "Open with Web Browser" ), WRITEMENU_SHOWBROWSER );
1114 popupMenu->insertSeparator();
1117 popupMenu->insertItem( i18n( "res tree" ), WRITEMENU_RESTREE );
1118 popupMenu->insertItem( i18n( "reverse res tree" ), WRITEMENU_REVERSERESTREE );
1119 popupMenu->insertItem( i18n( "extract by name" ), WRITEMENU_EXTRACTNAME );
1120 popupMenu->insertSeparator();
1123 popupMenu->insertItem( i18n( "copy URL" ), WRITEMENU_COPYURL );
1124 popupMenu->insertItem( i18n( "Copy title and URL" ), WRITEMENU_COPYTHREADNAME );
1125 popupMenu->insertItem( i18n( "copy" ), WRITEMENU_COPY );
1127 /* kokkoma de yonda */
1128 if ( m_domtree && m_mode == HTMLPART_MODE_MAINPART ) {
1129 popupMenu->insertSeparator();
1130 popupMenu->insertItem( i18n( "set Kokomade Yonda" ), WRITEMENU_SETKOKOYON );
1134 popupMenu->insertSeparator();
1135 popupMenu->insertItem( i18n( "add name to abone list" ), WRITEMENU_ABONENAME );
1138 /*--------------------------------------*/
1139 /* show popup menu */
1141 int ret = popupMenu->exec( QCursor::pos() );
1146 resstr = ">>" + QString().setNum( resNum ) + "\n";
1147 ViewMediator::getInstance()->showWriteView( m_datURL, resstr );
1150 case WRITEMENU_QUOTE:
1151 resstr = ">>" + QString().setNum( resNum ) + "\n"
1152 + "> " + Kita::DatManager::getPlainTitle( m_datURL, resNum ) + "\n"
1153 + "> " + Kita::DatManager::getPlainBody( m_datURL, resNum ).replace( "\n", "\n> " ) + "\n";
1154 ViewMediator::getInstance()->showWriteView( m_datURL, resstr );
1157 case WRITEMENU_MARK:
1158 Kita::DatManager::setMark( m_datURL, resNum, ! Kita::DatManager::isMarked( m_datURL, resNum ) );
1161 case WRITEMENU_COPY:
1162 case WRITEMENU_COPYURL:
1163 case WRITEMENU_COPYTHREADNAME:
1164 str = QString::null;
1167 if ( ret == WRITEMENU_COPYTHREADNAME || ret == WRITEMENU_COPY ) {
1168 str = Kita::DatManager::threadName( m_datURL );
1172 if ( str != QString::null ) str += "\n";
1173 str += Kita::DatManager::threadURL( m_datURL ) + "/" + QString().setNum( resNum ) + "\n";
1176 if ( ret == WRITEMENU_COPY ) {
1178 + Kita::DatManager::getPlainTitle( m_datURL, resNum ) + "\n"
1179 + Kita::DatManager::getPlainBody( m_datURL, resNum ) + "\n";
1183 clipboard->setText( str , QClipboard::Clipboard );
1184 clipboard->setText( str , QClipboard::Selection );
1188 case WRITEMENU_SETKOKOYON:
1189 Kita::DatManager::setViewPos( m_datURL, resNum );
1190 ViewMediator::getInstance()->updateBoardView( m_datURL );
1191 m_updatedKokoyon = TRUE;
1192 updateScreen( TRUE, TRUE );
1193 gotoAnchor( QString().setNum( resNum ), FALSE );
1196 case WRITEMENU_SHOWBROWSER:
1197 str = Kita::DatManager::threadURL( m_datURL ) + "/" + QString().setNum( resNum );
1199 KRun::runURL( str, "text/html" );
1202 case WRITEMENU_ABONENAME:
1203 if ( QMessageBox::information( view(), "Kita",
1204 i18n( "Do you want to add '%1' to abone list ?" ).arg( namestr ),
1205 QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
1206 == QMessageBox::Ok ) {
1208 Kita::AboneConfig::aboneNameList().append( namestr );
1209 redrawHTMLPart( m_datURL, FALSE );
1221 /*--------------------------------------------------*/
1222 /* popup that is opened when user clicked ID */
1223 /* This funtcion is called in only clickAnchor(). */ /* private */
1224 void KitaHTMLPart::showIDPopup( const QString& refstr )
1226 QString strid = refstr.mid( 5 )
1227 .replace( "%2B", "+" )
1228 .replace( "%2F", "/" );
1231 if ( m_pushrightbt ) {
1234 = Kita::DatManager::getHtmlByID( m_datURL, strid, num );
1235 if ( num <= 1 ) return ;
1236 QString tmpstr = QString( "<DIV>ID:%1:[%2]<BR>" ).arg( strid ).arg( num );
1237 tmpstr += htmlstr + "<BR><BR></DIV>";
1238 showPopup( m_datURL, tmpstr );
1248 KPopupMenu *popupMenu = new KPopupMenu( view() );
1250 popupMenu->insertItem( i18n( "add id to abone list" ), IDMENU_ABONE );
1251 int ret = popupMenu->exec( QCursor::pos() );
1256 /* add ID to abone list */
1257 if ( QMessageBox::information( view(), "Kita",
1258 i18n( "Do you want to add '%1' to abone list ?" ).arg( strid ),
1259 QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
1260 == QMessageBox::Ok ) {
1262 Kita::AboneConfig::aboneIDList().append( strid );
1263 redrawHTMLPart( m_datURL, FALSE );
1275 /*---------------------------------------------------------*/
1276 /* popup menu that is opened when user clicked be anchor. */
1277 /* This funtcion is called in only clickAnchor(). */ /* private */
1278 void KitaHTMLPart::showBePopupMenu( const QString& refstr )
1280 QString strURL = "http://be.2ch.net/test/p.php?i=" + refstr.mid( 5 )
1281 + "&u=d:" + Kita::DatManager::threadURL( m_datURL ) + "/l50";
1283 if ( m_pushrightbt ) {
1284 /*---------------------*/
1285 /* create popup menu */
1286 KPopupMenu *popupMenu = new KPopupMenu( view() );
1294 QClipboard * clipboard = QApplication::clipboard();
1296 popupMenu->insertItem( i18n( "copy URL" ), BEMENU_COPYURL );
1297 popupMenu->insertItem( i18n( "Open with Web Browser" ), BEMENU_SHOWBROWSER );
1299 /*--------------------------------------*/
1300 /* show popup menu */
1302 int ret = popupMenu->exec( QCursor::pos() );
1306 case BEMENU_COPYURL:
1308 clipboard->setText( strURL, QClipboard::Clipboard );
1309 clipboard->setText( strURL, QClipboard::Selection );
1312 case BEMENU_SHOWBROWSER:
1313 KRun::runURL( strURL, "text/html" );
1320 KRun::runURL( strURL, "text/html" );
1324 /*-------------------------------------------------------*/
1325 /*-------------------------------------------------------*/
1330 bool KitaHTMLPart::isPopupVisible()
1332 if ( !m_popup ) return FALSE;
1333 return m_popup->isVisible();
1338 void KitaHTMLPart::slotDeletePopup()
1340 if ( m_popup ) delete m_popup;
1342 m_multiPopup = FALSE;
1346 /* for convenience */ /* public slot */
1347 void KitaHTMLPart::slotShowResPopup( QPoint point, int refNum, int refNum2 )
1349 QString innerHTML = Kita::DatManager::getHtml( m_datURL, refNum, refNum2 );
1350 if ( innerHTML == QString::null ) return ;
1352 showPopupCore( m_datURL, innerHTML, point );
1356 /* for convenience */ /* private */
1357 void KitaHTMLPart::showPopup( const KURL& url, const QString& innerHTML )
1359 showPopupCore( url, innerHTML, QCursor::pos() );
1363 /* show popup window */ /* private */
1364 void KitaHTMLPart::showPopupCore( const KURL& url, const QString& innerHTML, QPoint point )
1367 m_multiPopup = FALSE;
1369 m_popup = new Kita::ResPopup( view() , url );
1371 connect( m_popup, SIGNAL( hideChildPopup() ), SLOT( slotHideChildPopup() ) );
1373 m_popup->setText( innerHTML );
1374 m_popup->adjustSize();
1375 m_popup->adjustPos( point );
1380 /*------------------------*/
1381 /* start multi-popup mode */ /* private */
1382 bool KitaHTMLPart::startMultiPopup()
1385 if ( m_popup && m_popup->isVisible() ) {
1386 m_multiPopup = TRUE;
1387 m_popup->moveMouseAbove();
1389 m_multiPopup = FALSE;
1392 return m_multiPopup;
1396 /* Is it multi-popup mode now ? */ /* private */
1397 bool KitaHTMLPart::isMultiPopupMode()
1400 m_multiPopup = FALSE;
1401 } else if ( m_popup->isHidden() ) {
1402 m_multiPopup = FALSE;
1405 return m_multiPopup;
1409 void KitaHTMLPart::hidePopup()
1414 m_multiPopup = FALSE;
1417 /* return TRUE if this view is under mouse. */ /* private */
1418 bool KitaHTMLPart::isUnderMouse( int mrgwd, int mrght )
1420 QPoint pos = QCursor::pos();
1421 int cx = pos.x(), cy = pos.y();
1423 QPoint viewpos = view() ->mapToGlobal( QPoint( 0, 0 ) );
1424 int px = viewpos.x(), py = viewpos.y();
1425 int wd = view() ->visibleWidth(), ht = view() ->visibleHeight();
1427 if ( ( px < cx && cx < px + wd + mrgwd )
1428 && ( py < cy && cy < py + ht + mrght ) ) {
1436 void KitaHTMLPart::slotLeave()
1438 if ( isMultiPopupMode() ) return ;
1439 if ( view() ->isHorizontalSliderPressed() ) return ;
1440 if ( view() ->isVerticalSliderPressed () ) return ;
1444 /* emit signal to have parent hide this if this is popup . */
1445 if ( m_mode == HTMLPART_MODE_POPUP && !isUnderMouse( 0, 0 ) ) {
1446 emit hideChildPopup();
1451 void KitaHTMLPart::slotVSliderReleased()
1453 QScrollBar * bar = view() ->verticalScrollBar();
1454 QRect rt = bar->sliderRect();
1455 int mrg = rt.right() - rt.left();
1459 /* emit signal to have parent hide this if this is popup . */
1460 if ( m_mode == HTMLPART_MODE_POPUP && !isUnderMouse( mrg, 0 ) ) {
1461 emit hideChildPopup();
1467 void KitaHTMLPart::slotHSliderReleased()
1469 QScrollBar * bar = view() ->horizontalScrollBar();
1470 QRect rt = bar->sliderRect();
1471 int mrg = rt.bottom() - rt.top();
1475 /* emit signal to have parent hide this if this is popup . */
1476 if ( m_mode == HTMLPART_MODE_POPUP && !isUnderMouse( 0, mrg ) ) {
1477 emit hideChildPopup();
1484 void KitaHTMLPart::slotHideChildPopup()
1488 /* emit signal to have parent hide this if this is popup . */
1489 if ( m_mode == HTMLPART_MODE_POPUP && !isUnderMouse( 0, 0 ) ) {
1490 emit hideChildPopup();
1495 /*---------------------------------------------------*/
1496 /* This slot is called when mouse moves onto the URL */ /* private slot */
1497 void KitaHTMLPart::slotOnURL( const QString& url )
1501 const int maxpopup = 10; /* max number of responses shown in the popup window */
1503 /*----------------------------*/
1505 if ( isMultiPopupMode() ) return ;
1509 if ( url.isEmpty() ) return ;
1510 if ( url.left( 7 ) == "mailto:" ) return ;
1512 /* Is Kita active now ? */
1513 if( ViewMediator::getInstance()->isKitaActive() == FALSE ) return;
1517 KURL datURL = m_datURL;
1518 if ( url.at( 0 ) == '#' ) {
1519 refstr = url.mid( 1 );
1521 datURL = Kita::getDatURL( KURL( m_datURL, url ) , refstr );
1524 /*------------------------*/
1527 if ( url.left( 6 ) == "#idpop" ) {
1528 int num = Kita::DatManager::getNumByID( m_datURL, url.mid( 6 ) );
1531 tmpstr = QString( "<DIV>ID:%1:[%2]</DIV>" ).arg( url.mid( 6 ) ).arg( num );
1533 tmpstr = "<DIV>" + i18n( "None" ) + "</DIV>";
1535 showPopup( m_datURL, tmpstr );
1540 /*------------------------*/
1541 /* show reffered num */
1543 if ( refstr.left( 5 ) == "write" ) {
1544 int no = refstr.mid( 5 ).toInt();
1546 Kita::DatManager::getTreeByRes( m_datURL, no, num );
1549 tmpstr = QString( "<DIV>No.%1 : [%2]</DIV>" ).arg( no ).arg( num );
1551 tmpstr = "<DIV>" + i18n( "None" ) + "</DIV>";
1553 showPopup( m_datURL, tmpstr );
1558 /*------------------------*/
1561 if ( url.left( 6 ) == "#abone" ) {
1562 int no = url.mid( 6 ).toInt();
1563 QString tmpstr = Kita::DatManager::getHtml( m_datURL, no, no, FALSE );
1564 showPopup( m_datURL, tmpstr );
1568 /*-------------------------*/
1569 /* popup for anchor */
1571 QString innerHTML = QString::null;
1575 int i = refstr.find( "-" );
1576 if ( i != -1 ) { /* >>refNum-refNum2 */
1578 refNum = refstr.left( i ).toInt();
1579 refNum2 = refstr.mid( i + 1 ).toInt();
1582 if ( refNum2 < refNum ) refNum2 = refNum;
1583 if ( refNum2 - refNum > maxpopup - 1 ) refNum2 = refNum + maxpopup - 1;
1586 } else { /* >>refNum */
1587 refNum = refstr.toInt();
1591 /* another thread ? */
1592 if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
1594 /* get board name */
1595 QString boardName = Kita::BoardManager::boardName( datURL );
1596 if ( boardName != QString::null ) innerHTML += "[" + boardName + "] ";
1598 /* If idx file of datURL is not read, thread name cannot be obtained.
1599 so, create DatInfo if cache exists, and read idx file in DatInfo::DatInfo(). */
1600 Kita::DatManager::getDatInfoPointer( datURL );
1602 /* get thread Name */
1603 QString subName = Kita::DatManager::threadName( datURL );
1604 if ( subName != QString::null ) innerHTML += subName + "<br><br>";
1606 if ( !refNum ) refNum = refNum2 = 1;
1609 /* get HTML and show it */
1610 if ( !refNum ) return ;
1611 innerHTML += Kita::DatManager::getHtml( datURL, refNum, refNum2 );
1613 if ( innerHTML != QString::null ) showPopup( datURL, innerHTML );
1618 /* If selected Text is composed of only digits,
1619 then show res popup. */ /* private */
1620 bool KitaHTMLPart::showSelectedDigitPopup()
1622 if ( !hasSelection() ) return FALSE;
1626 QString selectText = selectedText();
1627 const QChar *chpt = selectText.unicode();
1628 unsigned int length = selectText.length();
1630 if ( ( refNum = Kita::stringToPositiveNum( chpt, length ) ) != -1 ) {
1631 QString innerHTML = Kita::DatManager::getHtml( m_datURL, refNum, refNum );
1632 if ( innerHTML != QString::null ) {
1633 showPopup( m_datURL, innerHTML );