OSDN Git Service

Move the directories
[kita/kita.git] / src / threadview.cpp
diff --git a/src/threadview.cpp b/src/threadview.cpp
new file mode 100644 (file)
index 0000000..6003843
--- /dev/null
@@ -0,0 +1,572 @@
+/***************************************************************************
+*   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();
+}