1 /***************************************************************************
2 * Copyright (C) 2003 by Hideki Ikemoto *
3 * ikemo@users.sourceforge.jp *
4 * linux konqueror plugin no hito *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 ***************************************************************************/
12 #include "threadview.h"
14 #include <kpopupmenu.h>
17 #include <khtmlview.h>
18 #include <kiconloader.h>
21 #include <kmessagebox.h>
23 #include <kapplication.h>
24 #include <ktextbrowser.h>
25 #include <kcombobox.h>
27 #include <dom/html_inline.h>
28 #include <dom/html_base.h>
29 #include <dom/html_list.h>
31 #include <qclipboard.h>
33 #include <qtoolbutton.h>
35 #include <qcombobox.h>
36 #include <qprogressdialog.h>
38 #include <qtextbrowser.h>
39 #include <qmessagebox.h>
40 #include <qdatetime.h>
41 #include <qeucjpcodec.h>
42 #include <qsimplerichtext.h>
43 #include <qpopupmenu.h>
46 #include "viewmediator.h"
48 #include "libkita/kitaconfig.h"
49 #include "libkita/kita-utf8.h"
50 #include "libkita/qcp932codec.h"
51 #include "libkita/favoritethreads.h"
52 #include "libkita/favoriteboards.h"
53 #include "libkita/datmanager.h"
54 #include "libkita/boardmanager.h"
55 #include "libkita/signalcollection.h"
56 #include "libkita/kita_misc.h"
57 #include "libkita/config_xt.h"
59 #define MAX_LABEL_LENGTH 60
62 KitaThreadView::KitaThreadView( KitaThreadTabWidget* parent, const char* name )
66 /* copied from Base class */
68 setName( "KitaThreadViewBase" );
69 setFocusPolicy( QWidget::ClickFocus );
70 KitaThreadViewBaseLayout = new QVBoxLayout( this, 0, 0, "KitaThreadViewBaseLayout");
72 layout2 = new QHBoxLayout( 0, 0, 6, "layout2");
74 writeButton = new QToolButton( this, "writeButton" );
75 writeButton->setEnabled( FALSE );
76 layout2->addWidget( writeButton );
78 SearchCombo = new QComboBox( FALSE, this, "SearchCombo" );
79 SearchCombo->setMinimumSize( QSize( 200, 0 ) );
80 SearchCombo->setEditable( TRUE );
81 SearchCombo->setSizeLimit( 10 );
82 SearchCombo->setMaxCount( 15 );
83 SearchCombo->setInsertionPolicy( QComboBox::AtTop );
84 SearchCombo->setDuplicatesEnabled( FALSE );
85 layout2->addWidget( SearchCombo );
87 HighLightButton = new QToolButton( this, "HighLightButton" );
88 HighLightButton->setToggleButton( TRUE );
89 layout2->addWidget( HighLightButton );
91 BookmarkButton = new QToolButton( this, "BookmarkButton" );
92 BookmarkButton->setEnabled( FALSE );
93 BookmarkButton->setToggleButton( TRUE );
94 layout2->addWidget( BookmarkButton );
96 ReloadButton = new QToolButton( this, "ReloadButton" );
97 ReloadButton->setEnabled( FALSE );
98 layout2->addWidget( ReloadButton );
100 gotoCombo = new QComboBox( FALSE, this, "gotoCombo" );
101 gotoCombo->setMinimumSize( QSize( 200, 0 ) );
102 layout2->addWidget( gotoCombo );
104 deleteButton = new QToolButton( this, "deleteButton" );
105 deleteButton->setEnabled( FALSE );
106 layout2->addWidget( deleteButton );
107 spacer2 = new QSpacerItem( 30, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
108 layout2->addItem( spacer2 );
110 closeButton = new QToolButton( this, "closeButton" );
111 closeButton->setEnabled( FALSE );
112 layout2->addWidget( closeButton );
113 KitaThreadViewBaseLayout->addLayout( layout2 );
115 threadFrame = new QFrame( this, "threadFrame" );
116 threadFrame->setFrameShape( QFrame::StyledPanel );
117 threadFrame->setFrameShadow( QFrame::Raised );
118 KitaThreadViewBaseLayout->addWidget( threadFrame );
119 resize( QSize(870, 480).expandedTo(minimumSizeHint()) );
120 clearWState( WState_Polished );
123 m_threadPart = new KitaHTMLPart( threadFrame );
124 QHBoxLayout* aLayout = new QHBoxLayout( threadFrame );
125 aLayout->addWidget( m_threadPart->view() );
128 HighLightButton->setPixmap( SmallIcon( "idea" ) );
129 ReloadButton->setPixmap( SmallIcon( "reload" ) );
130 BookmarkButton->setPixmap( SmallIcon( "bookmark_add" ) );
131 writeButton->setPixmap( SmallIcon( "pencil" ) );
132 deleteButton->setPixmap( SmallIcon( "edittrash" ) );
133 closeButton->setPixmap( SmallIcon( "fileclose" ) );
136 setAcceptDrops( true ); // DND Drop eneble: 2nd stage. - enable on "KitaThreadView" widget and disable on the others(child widgets of "KitaThreadView").
137 threadFrame->setAcceptDrops( false ); // don't treat Drop event on child.
138 m_threadPart->view() ->setAcceptDrops( false ); // don't treat Drop event on child.
140 m_threadPart->enableMetaRefresh( false ); //disable <meta refresh="...">
142 connect( deleteButton, SIGNAL( clicked() ),
143 SLOT( slotDeleteButtonClicked() ) );
144 connect( writeButton, SIGNAL( clicked() ),
145 SLOT( slotWriteButtonClicked() ) );
146 connect( m_threadPart, SIGNAL( finishReload() ),
147 SLOT( slotUpdateInfo() ) );
148 connect( m_threadPart, SIGNAL( nodeActivated( const DOM::Node& ) ),
149 SLOT( slotDOMNodeActivated( const DOM::Node& ) ) );
150 connect( m_threadPart, SIGNAL( mousePressed() ),
151 SLOT( setFocus() ) );
153 connect( BookmarkButton, SIGNAL( toggled( bool ) ),
154 SLOT( slotBookmarkButtonClicked( bool ) ) );
155 connect( SearchCombo, SIGNAL( activated( int ) ),
156 SLOT( slotSearchButton() ) );
157 connect( ReloadButton, SIGNAL( clicked() ),
158 SLOT( slotReloadButton() ) );
159 connect( gotoCombo, SIGNAL( activated( int ) ),
160 SLOT( slotComboActivated( int ) ) );
161 connect( closeButton, SIGNAL( clicked() ),
162 SLOT( slotCloseButton() ) );
164 Kita::SignalCollection* signalCollection = Kita::SignalCollection::getInstance();
165 connect( this, SIGNAL( openURLRequestExt( const KURL&, const QString ) ),
166 signalCollection, SIGNAL( openURLRequestExt( const KURL&, const QString ) ) );
168 m_viewmode = VIEWMODE_MAINVIEW;
171 m_datURL = QString::null;
175 KitaThreadView::~KitaThreadView()
178 if ( m_threadPart ) {
184 const KURL KitaThreadView::threadURL() const
186 return Kita::getThreadURL( m_datURL );
189 const KURL KitaThreadView::datURL() const
194 void KitaThreadView::slotDOMNodeActivated( const DOM::Node& node )
196 { //process Anchor tags. Anchor tags not proccessed here cause 'emit KParts::BrowserExtention::openURLRequest()'
197 DOM::HTMLAnchorElement anchor = node;
199 if ( ! anchor.href().isEmpty() ) {
200 kdDebug() << "AnchorNodeActivated::" << endl;
201 } // end: anchor.href().isEmpty()
202 } // end of Anchor tags.
205 void KitaThreadView::setSubjectLabel( const QString& boardName, const QString& threadName, const QString boardURL )
208 if ( boardName.isEmpty() ) {
211 disp = QString( "<a href=\"%1\">[%2]</a> %3" ).arg( boardURL ).arg( boardName ).arg( threadName );
214 //disp.truncate( MAX_LABEL_LENGTH );
217 void KitaThreadView::updateButton()
219 writeButton->setEnabled( true );
220 BookmarkButton->setEnabled( true );
221 ReloadButton->setEnabled( true );
222 deleteButton->setEnabled( true );
223 closeButton->setEnabled( true );
225 if ( HighLightButton->isOn() ) {
226 HighLightButton->toggle();
229 // don't emit SIGNAL( toggled() )
230 disconnect( BookmarkButton, SIGNAL( toggled( bool ) ), this, SLOT( slotBookmarkButtonClicked( bool ) ) );
231 if ( FavoriteThreads::getInstance() ->contains( m_datURL.prettyURL() ) ) {
232 BookmarkButton->setOn( true );
234 BookmarkButton->setOn( false );
236 connect( BookmarkButton, SIGNAL( toggled( bool ) ), SLOT( slotBookmarkButtonClicked( bool ) ) );
240 /*--------------------*/
242 /*--------------------*/ /* private slots */
243 void KitaThreadView::slotWriteButtonClicked( QString resStr )
245 ViewMediator::getInstance()->showWriteView( m_datURL, resStr );
249 void KitaThreadView::insertSearchCombo()
251 for ( int count = 0; count < SearchCombo->count(); ++count ) {
252 if ( SearchCombo->text( count ) == SearchCombo->currentText() ) {
257 SearchCombo->insertItem( SearchCombo->currentText() );
260 void KitaThreadView::slotPopupMenu( KXMLGUIClient* client, const QPoint& global, const KURL& url, const QString& mimeType, mode_t mode )
262 KActionCollection * collection = client->actionCollection();
264 action = new KAction( i18n( "goback anchor" ), SmallIcon( "idea" ), KShortcut(), m_threadPart, SLOT( gobackAnchor() ), collection, "goback_anchor" );
265 emit popupMenu( client, global, url, mimeType, mode );
268 void KitaThreadView::setFont( const QFont& font )
270 // m_threadPart->setStandardFont(font.family());
271 SearchCombo->setFont( font );
273 DOM::CSSStyleDeclaration style = m_threadPart->htmlDocument().body().style();
274 style.setProperty( "font-family", font.family(), "" );
275 style.setProperty( "font-size", QString( "%1pt" ).arg( font.pointSize() ), "" );
279 void KitaThreadView::slotBookmarkButtonClicked( bool on )
281 ViewMediator::getInstance()->bookmark( m_datURL.prettyURL(), on );
285 void KitaThreadView::focusSearchCombo()
287 if ( ! SearchCombo->hasFocus() ) {
288 SearchCombo->setFocus();
295 /* public slot */ /* virtual */
296 void KitaThreadView::setFocus()
298 ViewMediator::getInstance()->changeWriteTab( m_datURL );
299 showStatusBar( QString::null );
300 m_threadPart->view() ->setFocus();
303 /*-------------------------------------------------*/
304 /* shobon extension */
305 /*-------------------------------------------------*/
311 void KitaThreadView::setup( const KURL& datURL, int mode )
315 /*---------------------------------------*/
318 m_datURL = Kita::getDatURL( datURL );
321 int partMode = HTMLPART_MODE_MAINPART;
322 m_threadPart->setup( partMode, m_datURL );
324 /* mode. Mode is defined in kitathreadview.h */
327 /* reset search direction */
330 /* load SETTING.TXT */
331 Kita::BoardManager::loadBBSSetting( m_datURL, FALSE );
335 /*--------------------------------------------------------*/
337 /* This function is called from KitaThreadTabWidget class */
338 /*--------------------------------------------------------*/
339 void KitaThreadView::showThread( const KURL& datURL, int num )
341 /* If this widget is not parent, then do nothing. */
342 if ( m_viewmode != VIEWMODE_MAINVIEW ) return ;
344 if ( num == 0 ) num = Kita::DatManager::getViewPos( datURL );
346 if ( topLevelWidget() ->isMinimized() ) topLevelWidget() ->showNormal();
347 topLevelWidget() ->raise();
351 setup( datURL, VIEWMODE_MAINVIEW );
353 /* get log from cahce */
355 if ( !m_threadPart->load( num ) ) showStatusBar( "" );
366 /*---------*/ /* public slot */
367 void KitaThreadView::slotReloadButton( int jumpNum )
369 topLevelWidget() ->raise();
372 if ( m_threadPart->reload( jumpNum ) ) {
373 showStatusBar( Kita::utf8ToUnicode( KITAUTF8_NOWRENEW ) );
378 /*-----------------------------------*/
379 /* stop loading the thread */ /* public slot */
380 void KitaThreadView::slotStopLoading()
383 if ( m_threadPart->isPopupVisible() ) {
384 m_threadPart->slotDeletePopup();
388 /* unforcus search combo */
389 if ( SearchCombo->hasFocus() ) {
394 Kita::DatManager::stopLoading( m_datURL );
398 /*-----------------------------------------*/
399 /* show the information at the statusbar. */
400 /*-----------------------------------------*/
401 void KitaThreadView::showStatusBar( QString info )
403 if ( m_datURL.isEmpty() ) return ;
404 QString captionStr = QString::null;
405 QString infostr = QString::null;
406 QString errstr = QString::null;
407 int viewPos = Kita::DatManager::getViewPos( m_datURL );
408 int resNum = Kita::DatManager::getResNum( m_datURL );
409 bool broken = Kita::DatManager::isBroken( m_datURL );
410 int datSize = Kita::DatManager::getDatSize( m_datURL );
412 switch ( m_viewmode ) {
414 case VIEWMODE_MAINVIEW:
416 errstr = QString::null;
417 if ( m_rescode != 200 && m_rescode != 206 && m_rescode != 0 )
418 errstr = QString( "Error %1" ).arg( m_rescode );
419 if ( broken ) info += " This thread is broken.";
421 /* show status bar,caption, url */
422 infostr = Kita::DatManager::threadName( m_datURL ) +
423 QString( " [Total: %1 New: %2] %3 k" ).arg( resNum ).arg( resNum - viewPos ).arg( datSize / 1024 )
424 + info + " " + errstr;
426 captionStr = Kita::DatManager::threadName( m_datURL ) + QString( " (%1)" ).arg( viewPos );
428 ViewMediator::getInstance()->setMainCaption( captionStr );
429 ViewMediator::getInstance()->setMainStatusBar( infostr );
430 ViewMediator::getInstance()->setMainURLLine( Kita::getThreadURL( m_datURL ) );
444 /*--------------------*/
445 /* update information */ /* public */
446 void KitaThreadView::slotUpdateInfo()
448 m_rescode = Kita::DatManager::getResponseCode( m_datURL );
449 m_serverTime = Kita::DatManager::getServerTime( m_datURL );
451 /* uptate informations */
452 setSubjectLabel( Kita::BoardManager::boardName( m_datURL ),
453 Kita::DatManager::threadName( m_datURL )
455 .arg( Kita::DatManager::getReadNum( m_datURL ) ),
456 Kita::BoardManager::boardURL( m_datURL ) );
460 gotoCombo->insertItem( Kita::utf8ToUnicode( KITAUTF8_GOTO ) );
461 gotoCombo->insertItem( Kita::utf8ToUnicode( KITAUTF8_KOKOYON ) );
462 for ( int i = 1; i < Kita::DatManager::getReadNum( m_datURL ); i += 100 ) {
463 gotoCombo->insertItem( QString().setNum( i ) + "-" );
465 gotoCombo->insertItem( Kita::utf8ToUnicode( KITAUTF8_SAIGO ) );
466 gotoCombo->adjustSize();
468 ViewMediator::getInstance()->updateBoardView( m_datURL );
469 ViewMediator::getInstance()->updateThreadView( m_datURL );
473 emit showThreadCompleted(); /* to KitaThreadPart */
479 /*------------------------*/
480 /* search function */
481 /*------------------------*/ /* private slots */
482 void KitaThreadView::slotSearchButton()
484 if ( m_datURL.isEmpty() ) return ; /* Nothing is shown on the screen.*/
486 QString str = SearchCombo->currentText();
487 if ( str.at( 0 ) == ':' ) {
490 if ( str.at( 1 ) == 'p' ) {
491 int refNum = str.mid( 2 ).toInt();
492 QPoint pos = mapToGlobal( SearchCombo->pos() );
493 pos.setY( pos.y() + SearchCombo->height() / 2 );
494 m_threadPart->slotShowResPopup( pos , refNum, refNum );
497 /* find by find dialog */
498 else if ( str.at( 1 ) == 'f' ) {
499 KAction * act = static_cast< KAction* >( m_threadPart->action( "find" ) );
500 if ( act ) act->activate();
505 QString anc = str.mid( 1 );
506 m_threadPart->gotoAnchor( anc, FALSE );
507 SearchCombo->setFocus();
511 slotSearchPrivate( FALSE );
515 void KitaThreadView::slotSearchNext() { slotSearchPrivate( FALSE ); }
516 void KitaThreadView::slotSearchPrev() { slotSearchPrivate( TRUE ); }
519 void KitaThreadView::slotSearchPrivate( bool rev )
521 if ( m_datURL.isEmpty() ) return ; /* Nothing is shown on the screen.*/
524 QString str = SearchCombo->currentText();
525 if ( str == QString::null ) return ;
526 if ( str == "" ) return ;
527 if ( str.at( 0 ) == ':' ) return ;
528 if ( str.at( 0 ) == '?' ) return ;
531 query += SearchCombo->currentText();
532 int ResNum = Kita::DatManager::getResNum( m_datURL );
533 for ( int i = 1; i <= ResNum; i++ ) {
535 if ( Kita::DatManager::checkWord( m_datURL, query, i, FALSE ) ) {
537 /* if this is parent, then show all responses, and search */
538 if ( m_viewmode == VIEWMODE_MAINVIEW ) m_threadPart->showAll();
541 QStringList list = Kita::parseSearchQuery( SearchCombo->currentText() );
542 m_threadPart->findText( SearchCombo->currentText(), rev );
543 SearchCombo->setFocus();
549 QMessageBox::information( this, i18n( "kita" ), i18n( "Not Found" ) );
553 void KitaThreadView::slotGobackAnchor() { m_threadPart->slotGobackAnchor(); }
554 void KitaThreadView::slotGotoHeader() { m_threadPart->gotoAnchor( "header", FALSE );}
555 void KitaThreadView::slotGotoFooter() { m_threadPart->slotClickGotoFooter(); }
559 void KitaThreadView::slotComboActivated( int index )
561 if ( index == gotoCombo->count() - 1 ) {
563 m_threadPart->gotoAnchor( "footer", FALSE );
564 } else if ( index == 1 ) {
566 m_threadPart->gotoAnchor( "kokomade_yonda", FALSE );
567 } else if ( index != 0 ) {
568 QString numText = gotoCombo->text( index );
569 numText.truncate( numText.length() - 1 );
570 m_threadPart->gotoAnchor( numText, FALSE );
574 void KitaThreadView::slotDeleteButtonClicked()
576 if ( m_datURL.isEmpty() ) return ;
578 int rescode = Kita::DatManager::getResponseCode( m_datURL );
579 if ( ( rescode != 200 && rescode != 206 )
580 || FavoriteThreads::getInstance() ->contains( m_datURL.prettyURL() ) ) {
581 if ( QMessageBox::warning( this,
583 i18n( "Do you want to delete Log ?" ),
584 QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
585 != QMessageBox::Ok ) return ;
588 if ( Kita::DatManager::deleteCache( m_datURL ) ) {
589 m_parent->slotCloseThreadTab( m_datURL );
590 ViewMediator::getInstance()->updateBoardView( m_datURL );
594 void KitaThreadView::slotCloseButton()
596 m_parent->slotCloseCurrentTab();
599 const QString KitaThreadView::selectedText() const
601 return m_threadPart->selectedText();