--- /dev/null
+/***************************************************************************
+* Copyright (C) 2003 by Hideki Ikemoto *
+* ikemo@users.sourceforge.jp *
+* linux konqueror plugin no hito *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+***************************************************************************/
+
+#include "threadview.h"
+
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QVBoxLayout>
+
+#include <kaction.h>
+#include <kcombobox.h>
+#include <khtmlview.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+#include <dom/html_document.h>
+#include <dom/html_inline.h>
+
+#include "htmlpart.h"
+#include "threadtabwidget.h"
+#include "viewmediator.h"
+#include "libkita/boarddatabase.h"
+#include "libkita/datmanager.h"
+#include "libkita/favoritethreads.h"
+#include "libkita/kita_misc.h"
+#include "libkita/kita-utf8.h"
+
+static const int MAX_LABEL_LENGTH = 60;
+
+using namespace Kita;
+
+ThreadView::ThreadView(ThreadTabWidget* parent)
+{
+ m_parent = parent;
+
+ /* copied from Base class */
+ setFocusPolicy(Qt::ClickFocus);
+ threadViewBaseLayout = new QVBoxLayout(this);
+
+ layout2 = new QHBoxLayout(0);
+ layout2->setSpacing(6);
+
+ writeButton = new QToolButton(this);
+ writeButton->setEnabled(false);
+ layout2->addWidget(writeButton);
+
+ searchCombo = new KComboBox(this);
+ searchCombo->setMinimumSize(QSize(200, 0));
+ searchCombo->setEditable(true);
+ searchCombo->setMaxVisibleItems(10);
+ searchCombo->setMaxCount(15);
+ searchCombo->setInsertPolicy(KComboBox::InsertAtTop);
+ searchCombo->setDuplicatesEnabled(false);
+ layout2->addWidget(searchCombo);
+
+ highLightButton = new QToolButton(this);
+ highLightButton->setCheckable(true);
+ layout2->addWidget(highLightButton);
+
+ bookmarkButton = new QToolButton(this);
+ bookmarkButton->setEnabled(false);
+ bookmarkButton->setCheckable(true);
+ bookmarkButton->setToolTip(i18nc("@info:tooltip", "Add to bookmark"));
+ layout2->addWidget(bookmarkButton);
+
+ reloadButton = new QToolButton(this);
+ reloadButton->setEnabled(false);
+ reloadButton->setToolTip(i18nc("@info:tooltip", "Reload"));
+ layout2->addWidget(reloadButton);
+
+ gotoCombo = new KComboBox(this);
+ gotoCombo->setMinimumSize(QSize(200, 0));
+ layout2->addWidget(gotoCombo);
+
+ deleteButton = new QToolButton(this);
+ deleteButton->setEnabled(false);
+ deleteButton->setToolTip(i18nc("@info:tooltip", "Delete"));
+ layout2->addWidget(deleteButton);
+ spacer2 = new QSpacerItem(30, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ layout2->addItem(spacer2);
+
+ closeButton = new QToolButton(this);
+ closeButton->setEnabled(false);
+ closeButton->setToolTip(i18nc("@info:tooltip", "Close tab"));
+ layout2->addWidget(closeButton);
+ threadViewBaseLayout->addLayout(layout2);
+
+ threadFrame = new QFrame(this);
+ threadFrame->setFrameShape(QFrame::StyledPanel);
+ threadFrame->setFrameShadow(QFrame::Raised);
+ threadViewBaseLayout->addWidget(threadFrame);
+ resize(QSize(870, 480).expandedTo(minimumSizeHint()));
+ setAttribute(Qt::WA_WState_Polished);
+ /* copy end */
+
+ m_threadPart = new HTMLPart(threadFrame);
+ QHBoxLayout* aLayout = new QHBoxLayout(threadFrame);
+ aLayout->addWidget(m_threadPart->view());
+
+ {
+ highLightButton->setIcon(SmallIcon("help-hint"));
+ reloadButton->setIcon(SmallIcon("view-refresh"));
+ bookmarkButton->setIcon(SmallIcon("bookmark-new"));
+ writeButton->setIcon(SmallIcon("draw-freehand"));
+ deleteButton->setIcon(SmallIcon("trash-empty"));
+ closeButton->setIcon(SmallIcon("tab-close"));
+ }
+
+ setAcceptDrops(true); // DND Drop eneble: 2nd stage. - enable on "ThreadView" widget and disable on the others(child widgets of "ThreadView").
+ threadFrame->setAcceptDrops(false); // don't treat Drop event on child.
+ m_threadPart->view() ->setAcceptDrops(false); // don't treat Drop event on child.
+
+// m_threadPart->enableMetaRefresh(false); //disable <meta refresh="..."> // TODO
+
+ connect(deleteButton, SIGNAL(clicked()),
+ SLOT(slotDeleteButtonClicked()));
+ connect(writeButton, SIGNAL(clicked()),
+ SLOT(slotWriteButtonClicked()));
+ connect(m_threadPart, SIGNAL(finishReload()),
+ SLOT(slotUpdateInfo()));
+ connect(m_threadPart, SIGNAL(nodeActivated(const DOM::Node&)),
+ SLOT(slotDOMNodeActivated(const DOM::Node&)));
+ connect(m_threadPart, SIGNAL(mousePressed()),
+ SLOT(setFocus()));
+
+ connect(bookmarkButton, SIGNAL(toggled(bool)),
+ SLOT(slotBookmarkButtonClicked(bool)));
+ connect(searchCombo, SIGNAL(activated(int)),
+ SLOT(slotSearchButton()));
+ connect(reloadButton, SIGNAL(clicked()),
+ SLOT(slotReloadButton()));
+ connect(gotoCombo, SIGNAL(activated(int)),
+ SLOT(slotComboActivated(int)));
+ connect(closeButton, SIGNAL(clicked()),
+ SLOT(slotCloseButton()));
+
+ m_viewmode = VIEWMODE_MAINVIEW;
+ m_rescode = 200;
+ m_serverTime = 0;
+ m_datUrl.clear();
+
+}
+
+ThreadView::~ThreadView()
+{
+
+ if (m_threadPart) {
+ delete m_threadPart;
+ m_threadPart = 0;
+ }
+}
+
+const KUrl ThreadView::threadUrl() const
+{
+ return getThreadUrl(m_datUrl);
+}
+
+const KUrl ThreadView::datUrl() const
+{
+ return m_datUrl;
+}
+
+void ThreadView::slotDOMNodeActivated(const DOM::Node& node)
+{
+ { //process Anchor tags. Anchor tags not proccessed here cause 'emit KParts::BrowserExtention::openURLRequest()'
+ DOM::HTMLAnchorElement anchor = node;
+
+ if (! anchor.href().isEmpty()) {
+// kdDebug() << "AnchorNodeActivated::" << endl;
+ } // end: anchor.href().isEmpty()
+ } // end of Anchor tags.
+}
+
+void ThreadView::setSubjectLabel(const QString& boardName, const QString& threadName, const QString& boardUrl)
+{
+ QString disp;
+ if (boardName.isEmpty()) {
+ disp = threadName;
+ } else {
+ disp = QString("<a href=\"%1\">[%2]</a> %3").arg(boardUrl).arg(boardName).arg(threadName);
+ }
+
+ //disp.truncate(MAX_LABEL_LENGTH);
+}
+
+void ThreadView::updateButton()
+{
+ writeButton->setEnabled(true);
+ bookmarkButton->setEnabled(true);
+ reloadButton->setEnabled(true);
+ deleteButton->setEnabled(true);
+ closeButton->setEnabled(true);
+
+ if (highLightButton->isChecked()) {
+ highLightButton->toggle();
+ }
+
+ // don't emit SIGNAL(toggled())
+ disconnect(bookmarkButton, SIGNAL(toggled(bool)), this, SLOT(slotBookmarkButtonClicked(bool)));
+ if (FavoriteThreads::getInstance() ->contains(m_datUrl.prettyUrl())) {
+ bookmarkButton->setChecked(true);
+ } else {
+ bookmarkButton->setChecked(false);
+ }
+ connect(bookmarkButton, SIGNAL(toggled(bool)), SLOT(slotBookmarkButtonClicked(bool)));
+}
+
+
+/*--------------------*/
+/* write response */
+/*--------------------*/ /* private slots */
+void ThreadView::slotWriteButtonClicked(const QString& resStr)
+{
+ ViewMediator::getInstance()->showWriteView(m_datUrl, resStr);
+}
+
+
+void ThreadView::insertSearchCombo()
+{
+ for (int count = 0; count < searchCombo->count(); ++count) {
+ if (searchCombo->itemText(count) == searchCombo->currentText()) {
+ // found
+ return ;
+ }
+ }
+ searchCombo->addItem(searchCombo->currentText());
+}
+
+
+void ThreadView::setFont(const QFont& font)
+{
+ // m_threadPart->setStandardFont(font.family());
+ searchCombo->setFont(font);
+
+ DOM::CSSStyleDeclaration style = m_threadPart->htmlDocument().body().style();
+ style.setProperty("font-family", font.family(), "");
+ style.setProperty("font-size", QString("%1pt").arg(font.pointSize()), "");
+}
+
+
+void ThreadView::slotBookmarkButtonClicked(bool on)
+{
+ ViewMediator::getInstance()->bookmark(m_datUrl.prettyUrl(), on);
+}
+
+
+void ThreadView::focusSearchCombo()
+{
+ if (! searchCombo->hasFocus()) {
+ searchCombo->setFocus();
+ } else {
+ setFocus();
+ }
+}
+
+
+/* public slot */ /* virtual */
+void ThreadView::setFocus()
+{
+ ViewMediator::getInstance()->changeWriteTab(m_datUrl);
+ showStatusBar(QString());
+ m_threadPart->view() ->setFocus();
+}
+
+/*-------------------------------------------------*/
+/* shobon extension */
+/*-------------------------------------------------*/
+
+
+/*-------*/
+/* setup */
+/*-------*/
+void ThreadView::setup(const KUrl& datUrl, int mode)
+{
+ /* config. */
+
+ /*---------------------------------------*/
+ /* setup */
+
+ m_datUrl = getDatUrl(datUrl);
+
+ /* setup HTMLPart */
+ int partMode = HTMLPART_MODE_MAINPART;
+ m_threadPart->setup(partMode, m_datUrl);
+
+ /* mode. Mode is defined in threadview.h */
+ m_viewmode = mode;
+
+ /* reset search direction */
+ m_revsearch = false;
+}
+
+
+/*--------------------------------------------------------*/
+/* Show thread */
+/* This function is called from ThreadTabWidget class */
+/*--------------------------------------------------------*/
+void ThreadView::showThread(const KUrl& datUrl, int num)
+{
+ /* If this widget is not parent, then do nothing. */
+ if (m_viewmode != VIEWMODE_MAINVIEW) return ;
+
+ if (num == 0) num = DatManager(datUrl).getViewPos();
+
+ if (topLevelWidget() ->isMinimized()) topLevelWidget() ->showNormal();
+ topLevelWidget() ->raise();
+ activateWindow();
+
+ /* setup */
+ setup(datUrl, VIEWMODE_MAINVIEW);
+
+ /* get log from cahce */
+ m_rescode = 200;
+ if (!m_threadPart->load(num)) showStatusBar("");
+
+ /* update data */
+ slotUpdateInfo();
+ slotReloadButton();
+}
+
+
+
+/*---------*/
+/* reload */
+/*---------*/ /* public slot */
+void ThreadView::slotReloadButton(int jumpNum)
+{
+ topLevelWidget() ->raise();
+ activateWindow();
+
+ if (m_threadPart->reload(jumpNum)) {
+ showStatusBar(QString::fromUtf8(KITAUTF8_NOWRENEW));
+ }
+}
+
+
+/*-----------------------------------*/
+/* stop loading the thread */ /* public slot */
+void ThreadView::slotStopLoading()
+{
+ /* hide popup */
+ if (m_threadPart->isPopupVisible()) {
+ m_threadPart->slotDeletePopup();
+ return ;
+ }
+
+ /* unforcus search combo */
+ if (searchCombo->hasFocus()) {
+ setFocus();
+ return ;
+ }
+
+ DatManager(m_datUrl).stopLoading();
+}
+
+
+/*-----------------------------------------*/
+/* show the information at the statusbar. */
+/*-----------------------------------------*/
+void ThreadView::showStatusBar(const QString &information)
+{
+ if (m_datUrl.isEmpty()) return ;
+ QString info = information;
+ QString captionStr;
+ QString infostr;
+ QString errstr;
+ DatManager datManager(m_datUrl);
+ int viewPos = datManager.getViewPos();
+ int resNum = datManager.getResNum();
+ bool broken = datManager.isBroken();
+ int datSize = datManager.getDatSize();
+
+ switch (m_viewmode) {
+
+ case VIEWMODE_MAINVIEW:
+
+ errstr.clear();
+ if (m_rescode != 200 && m_rescode != 206 && m_rescode != 0)
+ errstr = QString("Error %1").arg(m_rescode);
+ if (broken)
+ info += " " + i18nc("@info:status", "This thread is broken.");
+
+ /* show status bar,caption, url */
+ infostr = datManager.threadName() +
+ QString(" [Total: %1 New: %2] %3 k").arg(resNum)
+ .arg(resNum - viewPos).arg(datSize / 1024)
+ + info + ' ' + errstr;
+
+ captionStr = datManager.threadName() + QString(" (%1)").arg(viewPos);
+
+ ViewMediator::getInstance()->setMainCaption(captionStr);
+ ViewMediator::getInstance()->setMainStatus(infostr);
+ ViewMediator::getInstance()->setMainUrlLine(getThreadUrl(m_datUrl));
+
+ return ;
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+
+
+
+/*--------------------*/
+/* update information */ /* public */
+void ThreadView::slotUpdateInfo()
+{
+ DatManager datManager(m_datUrl);
+ m_rescode = datManager.getResponseCode();
+ m_serverTime = datManager.getServerTime();
+
+ /* uptate information */
+ BoardDatabase db(m_datUrl);
+ setSubjectLabel(db.boardName(), datManager.threadName() + QString(" (%1)")
+ .arg(datManager.getReadNum()), db.boardUrl());
+ updateButton();
+
+ gotoCombo->clear();
+ gotoCombo->addItem(QString::fromUtf8(KITAUTF8_GOTO));
+ gotoCombo->addItem(QString::fromUtf8(KITAUTF8_KOKOYON));
+ for (int i = 1; i < datManager.getReadNum(); i += 100) {
+ gotoCombo->addItem(QString::number(i) + '-');
+ }
+ gotoCombo->addItem(QString::fromUtf8(KITAUTF8_SAIGO));
+ gotoCombo->adjustSize();
+
+ ViewMediator::getInstance()->updateBoardView(m_datUrl);
+ ViewMediator::getInstance()->updateThreadView(m_datUrl);
+
+ showStatusBar("");
+
+ emit showThreadCompleted(); /* to ThreadPart */
+}
+
+
+
+
+/*------------------------*/
+/* search function */
+/*------------------------*/ /* private slots */
+void ThreadView::slotSearchButton()
+{
+ if (m_datUrl.isEmpty()) return ; /* Nothing is shown on the screen.*/
+
+ QString str = searchCombo->currentText();
+ if (str.at(0) == ':') {
+
+ /* show res popup */
+ if (str.at(1) == 'p') {
+ int refNum = str.mid(2).toInt();
+ QPoint pos = mapToGlobal(searchCombo->pos());
+ pos.setY(pos.y() + searchCombo->height() / 2);
+ m_threadPart->slotShowResPopup(pos , refNum, refNum);
+ return ;
+ }
+ /* find by find dialog */
+ else if (str.at(1) == 'f') {
+ KAction * act = static_cast< KAction* >(m_threadPart->action("find"));
+ if (act) act->trigger();
+ return ;
+ }
+
+ /* jump */
+ QString anc = str.mid(1);
+ m_threadPart->gotoAnchor(anc, false);
+ searchCombo->setFocus();
+ return ;
+ }
+
+ slotSearchPrivate(false);
+}
+
+/* public slot */
+void ThreadView::slotSearchNext() { slotSearchPrivate(false); }
+void ThreadView::slotSearchPrev() { slotSearchPrivate(true); }
+
+/* private */
+void ThreadView::slotSearchPrivate(bool rev)
+{
+ if (m_datUrl.isEmpty()) return ; /* Nothing is shown on the screen.*/
+
+ /* jump */
+ QString str = searchCombo->currentText();
+ if (str.isEmpty()) return ;
+ if (str.isEmpty()) return ;
+ if (str.at(0) == ':') return ;
+ if (str.at(0) == '?') return ;
+
+ QStringList query;
+ query += searchCombo->currentText();
+ DatManager datManager(m_datUrl);
+ int ResNum = datManager.getResNum();
+ for (int i = 1; i <= ResNum; i++) {
+
+ if (datManager.checkWord(query, i, false)) {
+
+ /* if this is parent, then show all responses, and search */
+ if (m_viewmode == VIEWMODE_MAINVIEW) m_threadPart->showAll();
+
+ insertSearchCombo();
+ QStringList list = parseSearchQuery(searchCombo->currentText());
+ m_threadPart->findText(searchCombo->currentText(), rev);
+ searchCombo->setFocus();
+
+ return ;
+ }
+ }
+
+ KMessageBox::information(this, i18n("Not Found"), i18n("kita"));
+}
+
+/* public slot */
+void ThreadView::slotGobackAnchor() { m_threadPart->slotGobackAnchor(); }
+void ThreadView::slotGotoHeader() { m_threadPart->gotoAnchor("header", false);}
+void ThreadView::slotGotoFooter() { m_threadPart->slotClickGotoFooter(); }
+
+// vim:sw=2:
+
+void ThreadView::slotComboActivated(int index)
+{
+ if (index == gotoCombo->count() - 1) {
+ // last
+ m_threadPart->gotoAnchor("footer", false);
+ } else if (index == 1) {
+ // kokomade yonda
+ m_threadPart->gotoAnchor("kokomade_yonda", false);
+ } else if (index != 0) {
+ QString numText = gotoCombo->itemText(index);
+ numText.truncate(numText.length() - 1);
+ m_threadPart->gotoAnchor(numText, false);
+ }
+}
+
+void ThreadView::slotDeleteButtonClicked()
+{
+ if (m_datUrl.isEmpty())
+ return;
+
+ DatManager datManager(m_datUrl);
+ int rescode = datManager.getResponseCode();
+ if ((rescode != 200 && rescode != 206)
+ || FavoriteThreads::getInstance()->contains(m_datUrl.prettyUrl())) {
+ if (KMessageBox::warningYesNo(this, i18n("Do you want to delete Log?"),
+ "Kita") != KMessageBox::Ok)
+ return;
+ }
+
+ if (datManager.deleteCache()) {
+ m_parent->slotCloseThreadTab(m_datUrl);
+ ViewMediator::getInstance()->updateBoardView(m_datUrl);
+ }
+}
+
+void ThreadView::slotCloseButton()
+{
+ m_parent->slotCloseCurrentTab();
+}
+
+const QString ThreadView::selectedText() const
+{
+ return m_threadPart->selectedText();
+}