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 <QtGui/QHBoxLayout>
15 #include <QtGui/QToolButton>
16 #include <QtGui/QVBoxLayout>
19 #include <kcombobox.h>
20 #include <khtmlview.h>
21 #include <kmessagebox.h>
23 #include <dom/html_document.h>
24 #include <dom/html_inline.h>
27 #include "threadtabwidget.h"
28 #include "viewmediator.h"
29 #include "libkita/boarddatabase.h"
30 #include "libkita/datmanager.h"
31 #include "libkita/favoritethreads.h"
32 #include "libkita/kita_misc.h"
33 #include "libkita/kita-utf8.h"
35 static const int MAX_LABEL_LENGTH = 60;
39 ThreadView::ThreadView(ThreadTabWidget* parent)
43 /* copied from Base class */
44 setFocusPolicy(Qt::ClickFocus);
45 threadViewBaseLayout = new QVBoxLayout(this);
47 layout2 = new QHBoxLayout(0);
48 layout2->setSpacing(6);
50 writeButton = new QToolButton(this);
51 writeButton->setEnabled(false);
52 layout2->addWidget(writeButton);
54 searchCombo = new KComboBox(this);
55 searchCombo->setMinimumSize(QSize(200, 0));
56 searchCombo->setEditable(true);
57 searchCombo->setMaxVisibleItems(10);
58 searchCombo->setMaxCount(15);
59 searchCombo->setInsertPolicy(KComboBox::InsertAtTop);
60 searchCombo->setDuplicatesEnabled(false);
61 layout2->addWidget(searchCombo);
63 highLightButton = new QToolButton(this);
64 highLightButton->setCheckable(true);
65 layout2->addWidget(highLightButton);
67 bookmarkButton = new QToolButton(this);
68 bookmarkButton->setEnabled(false);
69 bookmarkButton->setCheckable(true);
70 bookmarkButton->setToolTip(i18nc("@info:tooltip", "Add to bookmark"));
71 layout2->addWidget(bookmarkButton);
73 reloadButton = new QToolButton(this);
74 reloadButton->setEnabled(false);
75 reloadButton->setToolTip(i18nc("@info:tooltip", "Reload"));
76 layout2->addWidget(reloadButton);
78 gotoCombo = new KComboBox(this);
79 gotoCombo->setMinimumSize(QSize(200, 0));
80 layout2->addWidget(gotoCombo);
82 deleteButton = new QToolButton(this);
83 deleteButton->setEnabled(false);
84 deleteButton->setToolTip(i18nc("@info:tooltip", "Delete"));
85 layout2->addWidget(deleteButton);
86 spacer2 = new QSpacerItem(30, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
87 layout2->addItem(spacer2);
89 closeButton = new QToolButton(this);
90 closeButton->setEnabled(false);
91 closeButton->setToolTip(i18nc("@info:tooltip", "Close tab"));
92 layout2->addWidget(closeButton);
93 threadViewBaseLayout->addLayout(layout2);
95 threadFrame = new QFrame(this);
96 threadFrame->setFrameShape(QFrame::StyledPanel);
97 threadFrame->setFrameShadow(QFrame::Raised);
98 threadViewBaseLayout->addWidget(threadFrame);
99 resize(QSize(870, 480).expandedTo(minimumSizeHint()));
100 setAttribute(Qt::WA_WState_Polished);
103 m_threadPart = new HTMLPart(threadFrame);
104 QHBoxLayout* aLayout = new QHBoxLayout(threadFrame);
105 aLayout->addWidget(m_threadPart->view());
108 highLightButton->setIcon(SmallIcon("help-hint"));
109 reloadButton->setIcon(SmallIcon("view-refresh"));
110 bookmarkButton->setIcon(SmallIcon("bookmark-new"));
111 writeButton->setIcon(SmallIcon("draw-freehand"));
112 deleteButton->setIcon(SmallIcon("trash-empty"));
113 closeButton->setIcon(SmallIcon("tab-close"));
116 setAcceptDrops(true); // DND Drop eneble: 2nd stage. - enable on "ThreadView" widget and disable on the others(child widgets of "ThreadView").
117 threadFrame->setAcceptDrops(false); // don't treat Drop event on child.
118 m_threadPart->view() ->setAcceptDrops(false); // don't treat Drop event on child.
120 // m_threadPart->enableMetaRefresh(false); //disable <meta refresh="..."> // TODO
122 connect(deleteButton, SIGNAL(clicked()),
123 SLOT(slotDeleteButtonClicked()));
124 connect(writeButton, SIGNAL(clicked()),
125 SLOT(slotWriteButtonClicked()));
126 connect(m_threadPart, SIGNAL(finishReload()),
127 SLOT(slotUpdateInfo()));
128 connect(m_threadPart, SIGNAL(nodeActivated(const DOM::Node&)),
129 SLOT(slotDOMNodeActivated(const DOM::Node&)));
130 connect(m_threadPart, SIGNAL(mousePressed()),
133 connect(bookmarkButton, SIGNAL(toggled(bool)),
134 SLOT(slotBookmarkButtonClicked(bool)));
135 connect(searchCombo, SIGNAL(activated(int)),
136 SLOT(slotSearchButton()));
137 connect(reloadButton, SIGNAL(clicked()),
138 SLOT(slotReloadButton()));
139 connect(gotoCombo, SIGNAL(activated(int)),
140 SLOT(slotComboActivated(int)));
141 connect(closeButton, SIGNAL(clicked()),
142 SLOT(slotCloseButton()));
144 m_viewmode = VIEWMODE_MAINVIEW;
151 ThreadView::~ThreadView()
160 const KUrl ThreadView::threadUrl() const
162 return getThreadUrl(m_datUrl);
165 const KUrl ThreadView::datUrl() const
170 void ThreadView::slotDOMNodeActivated(const DOM::Node& node)
172 { //process Anchor tags. Anchor tags not proccessed here cause 'emit KParts::BrowserExtention::openURLRequest()'
173 DOM::HTMLAnchorElement anchor = node;
175 if (! anchor.href().isEmpty()) {
176 // kdDebug() << "AnchorNodeActivated::" << endl;
177 } // end: anchor.href().isEmpty()
178 } // end of Anchor tags.
181 void ThreadView::setSubjectLabel(const QString& boardName, const QString& threadName, const QString& boardUrl)
184 if (boardName.isEmpty()) {
187 disp = QString("<a href=\"%1\">[%2]</a> %3").arg(boardUrl).arg(boardName).arg(threadName);
190 //disp.truncate(MAX_LABEL_LENGTH);
193 void ThreadView::updateButton()
195 writeButton->setEnabled(true);
196 bookmarkButton->setEnabled(true);
197 reloadButton->setEnabled(true);
198 deleteButton->setEnabled(true);
199 closeButton->setEnabled(true);
201 if (highLightButton->isChecked()) {
202 highLightButton->toggle();
205 // don't emit SIGNAL(toggled())
206 disconnect(bookmarkButton, SIGNAL(toggled(bool)), this, SLOT(slotBookmarkButtonClicked(bool)));
207 if (FavoriteThreads::getInstance() ->contains(m_datUrl.prettyUrl())) {
208 bookmarkButton->setChecked(true);
210 bookmarkButton->setChecked(false);
212 connect(bookmarkButton, SIGNAL(toggled(bool)), SLOT(slotBookmarkButtonClicked(bool)));
216 /*--------------------*/
218 /*--------------------*/ /* private slots */
219 void ThreadView::slotWriteButtonClicked(const QString& resStr)
221 ViewMediator::getInstance()->showWriteView(m_datUrl, resStr);
225 void ThreadView::insertSearchCombo()
227 for (int count = 0; count < searchCombo->count(); ++count) {
228 if (searchCombo->itemText(count) == searchCombo->currentText()) {
233 searchCombo->addItem(searchCombo->currentText());
237 void ThreadView::setFont(const QFont& font)
239 // m_threadPart->setStandardFont(font.family());
240 searchCombo->setFont(font);
242 DOM::CSSStyleDeclaration style = m_threadPart->htmlDocument().body().style();
243 style.setProperty("font-family", font.family(), "");
244 style.setProperty("font-size", QString("%1pt").arg(font.pointSize()), "");
248 void ThreadView::slotBookmarkButtonClicked(bool on)
250 ViewMediator::getInstance()->bookmark(m_datUrl.prettyUrl(), on);
254 void ThreadView::focusSearchCombo()
256 if (! searchCombo->hasFocus()) {
257 searchCombo->setFocus();
264 /* public slot */ /* virtual */
265 void ThreadView::setFocus()
267 ViewMediator::getInstance()->changeWriteTab(m_datUrl);
268 showStatusBar(QString());
269 m_threadPart->view() ->setFocus();
272 /*-------------------------------------------------*/
273 /* shobon extension */
274 /*-------------------------------------------------*/
280 void ThreadView::setup(const KUrl& datUrl, int mode)
284 /*---------------------------------------*/
287 m_datUrl = getDatUrl(datUrl);
290 int partMode = HTMLPART_MODE_MAINPART;
291 m_threadPart->setup(partMode, m_datUrl);
293 /* mode. Mode is defined in threadview.h */
296 /* reset search direction */
301 /*--------------------------------------------------------*/
303 /* This function is called from ThreadTabWidget class */
304 /*--------------------------------------------------------*/
305 void ThreadView::showThread(const KUrl& datUrl, int num)
307 /* If this widget is not parent, then do nothing. */
308 if (m_viewmode != VIEWMODE_MAINVIEW) return ;
310 if (num == 0) num = DatManager(datUrl).getViewPos();
312 if (topLevelWidget() ->isMinimized()) topLevelWidget() ->showNormal();
313 topLevelWidget() ->raise();
317 setup(datUrl, VIEWMODE_MAINVIEW);
319 /* get log from cahce */
321 if (!m_threadPart->load(num)) showStatusBar("");
332 /*---------*/ /* public slot */
333 void ThreadView::slotReloadButton(int jumpNum)
335 topLevelWidget() ->raise();
338 if (m_threadPart->reload(jumpNum)) {
339 showStatusBar(QString::fromUtf8(KITAUTF8_NOWRENEW));
344 /*-----------------------------------*/
345 /* stop loading the thread */ /* public slot */
346 void ThreadView::slotStopLoading()
349 if (m_threadPart->isPopupVisible()) {
350 m_threadPart->slotDeletePopup();
354 /* unforcus search combo */
355 if (searchCombo->hasFocus()) {
360 DatManager(m_datUrl).stopLoading();
364 /*-----------------------------------------*/
365 /* show the information at the statusbar. */
366 /*-----------------------------------------*/
367 void ThreadView::showStatusBar(const QString &information)
369 if (m_datUrl.isEmpty()) return ;
370 QString info = information;
374 DatManager datManager(m_datUrl);
375 int viewPos = datManager.getViewPos();
376 int resNum = datManager.getResNum();
377 bool broken = datManager.isBroken();
378 int datSize = datManager.getDatSize();
380 switch (m_viewmode) {
382 case VIEWMODE_MAINVIEW:
385 if (m_rescode != 200 && m_rescode != 206 && m_rescode != 0)
386 errstr = QString("Error %1").arg(m_rescode);
388 info += " " + i18nc("@info:status", "This thread is broken.");
390 /* show status bar,caption, url */
391 infostr = datManager.threadName() +
392 QString(" [Total: %1 New: %2] %3 k").arg(resNum)
393 .arg(resNum - viewPos).arg(datSize / 1024)
394 + info + ' ' + errstr;
396 captionStr = datManager.threadName() + QString(" (%1)").arg(viewPos);
398 ViewMediator::getInstance()->setMainCaption(captionStr);
399 ViewMediator::getInstance()->setMainStatus(infostr);
400 ViewMediator::getInstance()->setMainUrlLine(getThreadUrl(m_datUrl));
414 /*--------------------*/
415 /* update information */ /* public */
416 void ThreadView::slotUpdateInfo()
418 DatManager datManager(m_datUrl);
419 m_rescode = datManager.getResponseCode();
420 m_serverTime = datManager.getServerTime();
422 /* uptate information */
423 BoardDatabase db(m_datUrl);
424 setSubjectLabel(db.boardName(), datManager.threadName() + QString(" (%1)")
425 .arg(datManager.getReadNum()), db.boardUrl());
429 gotoCombo->addItem(QString::fromUtf8(KITAUTF8_GOTO));
430 gotoCombo->addItem(QString::fromUtf8(KITAUTF8_KOKOYON));
431 for (int i = 1; i < datManager.getReadNum(); i += 100) {
432 gotoCombo->addItem(QString::number(i) + '-');
434 gotoCombo->addItem(QString::fromUtf8(KITAUTF8_SAIGO));
435 gotoCombo->adjustSize();
437 ViewMediator::getInstance()->updateBoardView(m_datUrl);
438 ViewMediator::getInstance()->updateThreadView(m_datUrl);
442 emit showThreadCompleted(); /* to ThreadPart */
448 /*------------------------*/
449 /* search function */
450 /*------------------------*/ /* private slots */
451 void ThreadView::slotSearchButton()
453 if (m_datUrl.isEmpty()) return ; /* Nothing is shown on the screen.*/
455 QString str = searchCombo->currentText();
456 if (str.at(0) == ':') {
459 if (str.at(1) == 'p') {
460 int refNum = str.mid(2).toInt();
461 QPoint pos = mapToGlobal(searchCombo->pos());
462 pos.setY(pos.y() + searchCombo->height() / 2);
463 m_threadPart->slotShowResPopup(pos , refNum, refNum);
466 /* find by find dialog */
467 else if (str.at(1) == 'f') {
468 KAction * act = static_cast< KAction* >(m_threadPart->action("find"));
469 if (act) act->trigger();
474 QString anc = str.mid(1);
475 m_threadPart->gotoAnchor(anc, false);
476 searchCombo->setFocus();
480 slotSearchPrivate(false);
484 void ThreadView::slotSearchNext() { slotSearchPrivate(false); }
485 void ThreadView::slotSearchPrev() { slotSearchPrivate(true); }
488 void ThreadView::slotSearchPrivate(bool rev)
490 if (m_datUrl.isEmpty()) return ; /* Nothing is shown on the screen.*/
493 QString str = searchCombo->currentText();
494 if (str.isEmpty()) return ;
495 if (str.isEmpty()) return ;
496 if (str.at(0) == ':') return ;
497 if (str.at(0) == '?') return ;
500 query += searchCombo->currentText();
501 DatManager datManager(m_datUrl);
502 int ResNum = datManager.getResNum();
503 for (int i = 1; i <= ResNum; i++) {
505 if (datManager.checkWord(query, i, false)) {
507 /* if this is parent, then show all responses, and search */
508 if (m_viewmode == VIEWMODE_MAINVIEW) m_threadPart->showAll();
511 QStringList list = parseSearchQuery(searchCombo->currentText());
512 m_threadPart->findText(searchCombo->currentText(), rev);
513 searchCombo->setFocus();
519 KMessageBox::information(this, i18n("Not Found"), i18n("kita"));
523 void ThreadView::slotGobackAnchor() { m_threadPart->slotGobackAnchor(); }
524 void ThreadView::slotGotoHeader() { m_threadPart->gotoAnchor("header", false);}
525 void ThreadView::slotGotoFooter() { m_threadPart->slotClickGotoFooter(); }
529 void ThreadView::slotComboActivated(int index)
531 if (index == gotoCombo->count() - 1) {
533 m_threadPart->gotoAnchor("footer", false);
534 } else if (index == 1) {
536 m_threadPart->gotoAnchor("kokomade_yonda", false);
537 } else if (index != 0) {
538 QString numText = gotoCombo->itemText(index);
539 numText.truncate(numText.length() - 1);
540 m_threadPart->gotoAnchor(numText, false);
544 void ThreadView::slotDeleteButtonClicked()
546 if (m_datUrl.isEmpty())
549 DatManager datManager(m_datUrl);
550 int rescode = datManager.getResponseCode();
551 if ((rescode != 200 && rescode != 206)
552 || FavoriteThreads::getInstance()->contains(m_datUrl.prettyUrl())) {
553 if (KMessageBox::warningYesNo(this, i18n("Do you want to delete Log?"),
554 "Kita") != KMessageBox::Ok)
558 if (datManager.deleteCache()) {
559 m_parent->slotCloseThreadTab(m_datUrl);
560 ViewMediator::getInstance()->updateBoardView(m_datUrl);
564 void ThreadView::slotCloseButton()
566 m_parent->slotCloseCurrentTab();
569 const QString ThreadView::selectedText() const
571 return m_threadPart->selectedText();