OSDN Git Service

refactoring.
[kita/kita.git] / kita / src / write / previewpart.cpp
1 /***************************************************************************
2  *   Copyright (C) 2004 by Kita Developers                                 *
3  *   ikemo@users.sourceforge.jp                                            *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10
11 #include "previewpart.h"
12
13 #include <qcursor.h>
14
15 #include <khtml_events.h>
16
17 #include <dom/html_misc.h>
18
19 #include "thread/respopup.h"
20
21 #include "kitaui/htmlview.h"
22
23 #include "libkita/kitaconfig.h"
24 #include "libkita/datmanager.h"
25 #include "libkita/kita_misc.h"
26 #include "libkita/signalcollection.h"
27 #include "libkita/config_xt.h"
28
29 /*-------------------------------------*/
30 /* Don't forget to call setup() later. */
31
32 KitaPreviewPart::KitaPreviewPart( QWidget* parent, const char* name )
33         : KHTMLPart( new KitaHTMLView( this, parent, name ) )
34 {
35     m_popup = NULL;
36     m_datURL = QString::null;
37
38     clearPart();
39     createHTMLDocument();
40     connectSignals();
41 }
42
43 KitaPreviewPart::~KitaPreviewPart()
44 {
45     clearPart();
46 }
47
48 /* private */
49 void KitaPreviewPart::clearPart()
50 {
51     slotDeletePopup();
52
53     if ( !m_datURL.isEmpty() ) {  /* This part is opened. */
54
55         /* don't forget to unlock previous datURL here. */
56         Kita::DatManager::unlock( m_datURL );
57     }
58     m_datURL = QString::null;
59 }
60
61 /* public */
62 bool KitaPreviewPart::setup( const KURL& url )
63 {
64     if ( url.isEmpty() ) return FALSE;
65
66     clearPart();
67
68     m_datURL = Kita::getDatURL( url );
69
70     /* Lock datURL. Don't forget to unlock it later ! */
71     Kita::DatManager::lock ( m_datURL );
72
73     /* create HTML Document */
74     createHTMLDocument();
75
76     return TRUE;
77 }
78
79 /* private */
80 void KitaPreviewPart::connectSignals()
81 {
82     Kita::SignalCollection * signalCollection = Kita::SignalCollection::getInstance();
83
84     /* rendering */
85     connect( signalCollection, SIGNAL( threadFaceChanged() ), SLOT( slotSetFaceOfHTMLPart() ) );
86     connect( signalCollection, SIGNAL( setStyleSheetOfHTMLPart() ), SLOT( slotSetStyleSheetOfHTMLPart() ) );
87
88     /* popup */
89     connect( this, SIGNAL( onURL( const QString& ) ), SLOT( slotOnURL( const QString& ) ) );
90     connect( this, SIGNAL( isKitaActive() ), signalCollection, SIGNAL( isKitaActive() ) );
91
92     connect( view(), SIGNAL( leave() ), SLOT( slotLeave() ) );
93     connect( view(), SIGNAL( verticalSliderReleased() ), SLOT( slotVSliderReleased() ) );
94     connect( view(), SIGNAL( horizontalSliderReleased() ), SLOT( slotHSliderReleased() ) );
95
96     connect( signalCollection, SIGNAL( kitaIsActive() ), SLOT( slotKitaIsActive() ) );
97     connect( signalCollection, SIGNAL( windowDeactivated() ), SLOT( slotHideChildPopup() ) );
98
99     /* click */
100     connect( this, SIGNAL( openURLRequestExt(
101                                const KURL&, const KParts::URLArgs&, QString, int,
102                                const KURL& ) ),
103              signalCollection, SIGNAL( openURLRequestExt(
104                                            const KURL& , const KParts::URLArgs&, QString, int,
105                                            const KURL& ) ) );
106 }
107
108 /* private */
109 void KitaPreviewPart::createHTMLDocument()
110 {
111     /* style */
112     QString style = QString( "body { font-size: %1pt; font-family: \"%2\"; color: %3; background-color: %4; }" )
113                     .arg( Kita::Config::threadFont().pointSize() )
114                     .arg( Kita::Config::threadFont().family() )
115                     .arg( Kita::Config::threadColor().name() )
116                     .arg( Kita::Config::threadBackground().name() );
117
118     QString text = "<html><head><style>";
119     text += KitaConfig::defaultStyleSheetText();
120     text += style;
121     if ( Kita::Config::useStyleSheet() ) {
122         text += KitaConfig::styleSheetText();
123     }
124     text += "</style></head><body></body></html>";
125
126     setJScriptEnabled( false );
127     setJavaEnabled( false );
128
129     /* Use dummy URL here, and protocol should be "file:".
130        If protocol is "http:", local image files are not shown
131        (for security reasons ?).
132      */
133     begin( "file:/dummy.htm" );
134     write( text );
135     end();
136 }
137
138 /*---------------------------------------------------------------*/
139 /*---------------------------------------------------------------*/
140 /* direct rendering functions */
141
142 /* public */
143 void KitaPreviewPart::setInnerHTML( const QString& innerHTML )
144 {
145     createHTMLDocument();
146     htmlDocument().body().setInnerHTML( innerHTML );
147 }
148
149 /* public slot */
150 void KitaPreviewPart::slotSetFaceOfHTMLPart()
151 {
152     QFont font = Kita::Config::threadFont();
153
154     DOM::CSSStyleDeclaration style = htmlDocument().body().style();
155     style.setProperty( "font-family", font.family(), "" );
156     style.setProperty( "font-size", QString( "%1pt" ).arg( font.pointSize() ), "" );
157     style.setProperty( "color", Kita::Config::threadColor().name(), "" );
158     style.setProperty( "background-color", Kita::Config::threadBackground().name(), "" );
159     htmlDocument().applyChanges();
160 }
161
162 /* public slot */
163 void KitaPreviewPart::slotSetStyleSheetOfHTMLPart()
164 {
165     /* [0]<html> -> [1]<head> -> [2]<style> */
166     DOM::HTMLCollection collection = htmlDocument().all();
167     DOM::HTMLElement element;
168     unsigned int i;
169     for ( i = 0 ; i < collection.length() ; i++ ) {
170         element = collection.item( i );
171         if ( element.tagName().upper() == "STYLE" ) {
172             QString style = QString( "body { font-size: %1pt; font-family: %2; color: %3; background-color: %4; }" )
173                             .arg( Kita::Config::threadFont().pointSize() )
174                             .arg( Kita::Config::threadFont().family() )
175                             .arg( Kita::Config::threadColor().name() )
176                             .arg( Kita::Config::threadBackground().name() );
177
178             QString style0 = KitaConfig::defaultStyleSheetText();
179             style0 += style;
180             if ( Kita::Config::useStyleSheet() ) {
181                 style0 += KitaConfig::styleSheetText();
182             }
183
184             element.setInnerText( style0 );
185             htmlDocument().applyChanges();
186             break;
187         }
188     }
189 }
190
191 /*---------------------------------------------------------------*/
192 /*---------------------------------------------------------------*/
193 /* user event */
194
195 /* protected */ /* virtual */
196 void KitaPreviewPart::customEvent( QCustomEvent * e )
197 {
198     if ( e->type() == EVENT_GotoAnchor ) {
199         KHTMLPart::gotoAnchor( static_cast< GotoAnchorEvent* >( e ) ->getAnc() );
200         return ;
201     }
202
203     KHTMLPart::customEvent( e );
204 }
205
206 /*---------------------------------------------------------------*/
207 /*---------------------------------------------------------------*/
208 /* mouse event */
209
210 /* protected */
211 void KitaPreviewPart::khtmlMousePressEvent( khtml::MousePressEvent* e )
212 {
213     emit mousePressed(); /* to KitaThreadView to focus this view. */
214
215     KURL kurl;
216     if ( e->url().string() != QString::null ) {
217         kurl = KURL( Kita::BoardManager::boardURL( m_datURL ), e->url().string() );
218     }
219
220     if ( e->qmouseEvent()->button() & Qt::RightButton ) {
221         m_isPushedRightButton = TRUE;
222     } else {
223         m_isPushedRightButton = FALSE;
224     }
225
226     if ( e->url() != NULL ) {
227
228         if ( e->url().string().at( 0 ) == '#' ) { /* anchor */
229             kurl = m_datURL;
230             kurl.setRef( e->url().string().mid( 1 ) ) ;
231         }
232
233         clickAnchor( kurl );
234         m_isPushedRightButton = FALSE;
235         return;
236     }
237
238     KHTMLPart::khtmlMousePressEvent( e );
239 }
240
241 /*-------------------------------------------------------*/
242 /*-------------------------------------------------------*/
243 /* click */
244
245 /*------------------------------------------------------*/
246 /* This function is called when user clicked res anchor */ /* private */
247 void KitaPreviewPart::clickAnchor( const KURL& urlin )
248 {
249     QString refstr;
250     KURL datURL = Kita::getDatURL( urlin , refstr );
251
252     /*--------------------------------*/
253     /* If this is not anchor, then    */
254     /* emit openURLRequest and return */
255
256     if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
257         emit openURLRequestExt( urlin );
258         return ;
259     }
260
261     if ( refstr == QString::null ) return ;
262
263     /*-------------------------*/
264     /* start multi-popup mdde  */
265     if ( m_isPushedRightButton && startMultiPopup() ) return ;
266
267     /*-------------------------------*/
268     /* open Kita Navi or goto anchor */
269
270     int refNum, refNum2;
271
272     int i = refstr.find( "-" );
273     if ( i != -1 ) {
274         refNum = refstr.left( i ).toInt();
275         refNum2 = refstr.mid( i + 1 ).toInt();
276         if ( refNum2 < refNum ) refNum2 = refNum;
277     } else refNum = refNum2 = refstr.toInt();
278
279     if ( !refNum ) return ;
280
281     emit openURLRequestExt( urlin );
282 }
283
284 /*-------------------------------------------------------*/
285 /*-------------------------------------------------------*/
286 /* popup */
287
288 void KitaPreviewPart::slotDeletePopup()
289 {
290     if ( m_popup ) delete m_popup;
291     m_popup = NULL;
292     m_multiPopup = FALSE;
293 }
294
295 /* for convenience */ /* private */
296 void KitaPreviewPart::showPopup( const KURL& url, const QString& innerHTML )
297 {
298     slotDeletePopup();
299     m_multiPopup = FALSE;
300
301     m_popup = new Kita::ResPopup( view() , url );
302
303     connect( m_popup, SIGNAL( hideChildPopup() ), SLOT( slotHideChildPopup() ) );
304
305     m_popup->setText( innerHTML );
306     m_popup->adjustSize();
307     m_popup->adjustPos( QCursor::pos() );
308     m_popup->show();
309 }
310
311 /*------------------------*/
312 /* start multi-popup mode */ /* private */
313 bool KitaPreviewPart::startMultiPopup()
314 {
315     if ( m_popup && m_popup->isVisible() ) {
316         m_multiPopup = TRUE;
317         m_popup->moveMouseAbove();
318     } else {
319         m_multiPopup = FALSE;
320     }
321
322     return m_multiPopup;
323 }
324
325 /* Is it multi-popup mode now ? */ /* private */
326 bool KitaPreviewPart::isMultiPopupMode()
327 {
328     if ( !m_popup ) {
329         m_multiPopup = FALSE;
330     } else if ( m_popup->isHidden() ) {
331         m_multiPopup = FALSE;
332     }
333
334     return m_multiPopup;
335 }
336
337 /* private */
338 void KitaPreviewPart::hidePopup()
339 {
340     if ( m_popup ) {
341         m_popup->hide();
342     }
343
344     m_multiPopup = FALSE;
345 }
346
347 /* private slot */
348 void KitaPreviewPart::slotLeave()
349 {
350     if ( isMultiPopupMode() ) return ;
351     if ( view()->isHorizontalSliderPressed() ) return ;
352     if ( view()->isVerticalSliderPressed () ) return ;
353
354     hidePopup();
355 }
356
357 /* private slot */
358 void KitaPreviewPart::slotVSliderReleased()
359 {
360     QScrollBar* bar = view()->verticalScrollBar();
361     QRect rt = bar->sliderRect();
362
363     hidePopup();
364 }
365
366 /* private slot */
367 void KitaPreviewPart::slotHSliderReleased()
368 {
369     QScrollBar* bar = view()->horizontalScrollBar();
370     QRect rt = bar->sliderRect();
371
372     hidePopup();
373 }
374
375 /* private slot */
376 void KitaPreviewPart::slotHideChildPopup()
377 {
378     hidePopup();
379 }
380
381 /*------------------------------------------*/
382 /* called back when kita is active .
383    see also an explanation in slotOnURL.    */ /* private slot */
384 void KitaPreviewPart::slotKitaIsActive()
385 {
386     m_kitaIsActive = TRUE;
387 }
388
389 /*---------------------------------------------------*/
390 /* This slot is called when mouse moves onto the URL */ /* private slot */
391 void KitaPreviewPart::slotOnURL( const QString& url )
392 {
393     /* config */
394
395     const int maxpopup = 10;  /* max number of responses shown in the popup window */
396
397     /*----------------------------*/
398
399     if ( isMultiPopupMode() ) return ;
400
401     slotDeletePopup();
402
403     if ( url.isEmpty() ) return ;
404     if ( url.left( 7 ) == "mailto:" ) return ;
405
406     /* Is Kita active now ?
407
408        emit SIGNAL( isKitaActive() ) to KitaMainWindow, KitaNavi, etc. ,
409        and if one of them is active, then slotKitaIsActive() is called
410        back, and m_kitaIsActive is set to TRUE.   */
411     m_kitaIsActive = FALSE;
412     emit isKitaActive();
413     if ( !m_kitaIsActive ) return ;
414
415     /* get reference */
416     QString refstr;
417     KURL datURL = m_datURL;
418     if ( url.at( 0 ) == '#' ) refstr = url.mid( 1 );
419     else datURL = Kita::getDatURL( KURL( m_datURL, url ) , refstr );
420
421     /*-------------------------*/
422     /* popup for anchor        */
423
424     QString innerHTML = QString::null;
425     int refNum;
426     int refNum2;
427
428     int i = refstr.find( "-" );
429     if ( i != -1 ) { /* >>refNum-refNum2 */
430
431         refNum = refstr.left( i ).toInt();
432         refNum2 = refstr.mid( i + 1 ).toInt();
433
434         if ( refNum ) {
435             if ( refNum2 < refNum ) refNum2 = refNum;
436             if ( refNum2 - refNum > maxpopup - 1 ) refNum2 = refNum + maxpopup - 1;
437         }
438
439     } else { /* >>refNum */
440         refNum = refstr.toInt();
441         refNum2 = refNum;
442     }
443
444     /* another thread ? */
445     if ( datURL.host() != m_datURL.host() || datURL.path() != m_datURL.path() ) {
446
447         /* get board name */
448         QString boardName = Kita::BoardManager::boardName( datURL );
449         if ( boardName != QString::null ) innerHTML += "[" + boardName + "] ";
450
451         /* If idx file of datURL is not read, thread name cannot be obtained.
452            so, create DatInfo if cache exists, and read idx file in DatInfo::DatInfo(). */
453         Kita::DatManager::getDatInfoPointer( datURL );
454
455         /* get thread Name */
456         QString subName = Kita::DatManager::threadName( datURL );
457         if ( subName != QString::null ) innerHTML += subName + "<br><br>";
458
459         if ( !refNum ) refNum = refNum2 = 1;
460     }
461
462     /* get HTML and show it */
463     if ( !refNum ) return ;
464     innerHTML += Kita::DatManager::getHtml( datURL, refNum, refNum2 );
465
466     if ( innerHTML != QString::null ) showPopup( datURL, innerHTML );
467 }