OSDN Git Service

Fix a bug in sorting rows
[kita/kita.git] / kita / src / boardview.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 "boardview.h"
12
13 #include <QtCore/QDateTime>
14 #include <QtCore/QList>
15 #include <QtGui/QApplication>
16 #include <QtGui/QMouseEvent>
17
18 #include <kaction.h>
19 #include <kconfig.h>
20 #include <kmessagebox.h>
21 #include <kstandarddirs.h>
22
23 #include "boardtabwidget.h"
24 #include "threadlistheaderview.h"
25 #include "threadlistviewitem.h"
26 #include "viewmediator.h"
27 #include "libkita/boardmanager.h"
28 #include "libkita/datmanager.h"
29 #include "libkita/globalconfig.h"
30 #include "libkita/kita_misc.h"
31 #include "libkita/thread.h"
32
33 using namespace Kita;
34
35 BoardView::BoardView(BoardTabWidget* parent) : ThreadListView(parent)
36 {
37     init();
38     m_parent = parent;
39     closeButton->setEnabled(true);
40
41     connect(reloadButton, SIGNAL(clicked()),
42              SLOT(reloadSubject()));
43
44     connect(closeButton, SIGNAL(clicked()),
45              SLOT(slotCloseButton()));
46
47     //connect(subjectList, SIGNAL(columnResized(int, int, int)),
48     //         SLOT(slotSizeChange(int, int, int))); TODO
49
50     loadLayout();
51     loadHeaderOnOff();
52
53     m_deleteLogAct->setVisible(true);
54 }
55
56 /* public */
57 void BoardView::init()
58 {
59     m_unreadNum = 0;
60     m_readNum = 0;
61     m_newNum = 0;
62     m_showOldLogs = false;
63     m_enableSizeChange = false;
64 }
65
66
67 void BoardView::reloadSubject()
68 {
69     if (!m_boardUrl.isEmpty()) {
70         loadBoard(m_boardUrl);
71     }
72 }
73
74
75 /* private slot */
76 void BoardView::slotCloseButton()
77 {
78     m_parent->slotCloseCurrentTab();
79 }
80
81
82 const KUrl BoardView::boardUrl()
83 {
84     return m_boardUrl;
85 }
86
87 void BoardView::toggleShowOldLogs()
88 {
89     m_showOldLogs = !m_showOldLogs;
90     loadBoard(m_boardUrl, false);
91 }
92
93 // used to sort rows
94 enum {
95     Thread_Old,
96     Thread_Readed,
97     Thread_Normal,
98     Thread_New,
99     Thread_Read,
100     Thread_HasUnread
101 };
102
103 void BoardView::loadBoard(const KUrl& url, bool online)
104 {
105     activateWindow();
106     topLevelWidget()->raise();
107     m_enableSizeChange = false;
108
109     // reset member variables.
110     // FIXME: FavoriteListView::update()
111     {
112         m_hitList.clear();
113         m_nextHitIndex = 0;
114         m_prevquery = QStringList();
115     }
116
117     m_boardUrl = url;
118     m_unreadNum = 0;
119     m_readNum = 0;
120     m_newNum = 0;
121
122     /* get list of pointers of Thread classes */
123     QList<Thread*> oldLogList;
124     QList<Thread*> threadList;
125     BoardManager::getThreadList(
126             m_boardUrl, m_showOldLogs, online, threadList, oldLogList);
127
128     // reset list
129     subjectList->clearContents();
130
131     QDateTime current = QDateTime::currentDateTime();
132     int countNew = threadList.count();
133     int countOld = oldLogList.count();
134     int count = countNew + countOld;
135     subjectList->setRowCount(count);
136     subjectList->setSortingEnabled(false);
137     for (int i = 0; i < count; i++) {
138         Thread* thread
139             = i < countNew ? threadList.at(i) : oldLogList.at(i - countNew);
140         KUrl datUrl = thread->datUrl();
141         for (int j = 0, k = subjectList->columnCount(); j < k; j++) {
142             ThreadListViewItem* item = new ThreadListViewItem(j);
143             subjectList->setItem(i, j, item);
144         }
145         int id = (i < countNew ? i + 1 : 0);
146         int order = i + 1;
147         updateRow(i, datUrl, current, id, order);
148     }
149     subjectList->setSortingEnabled(true);
150
151     if (hideButton->isChecked()) {
152         hideButton->toggle();
153     }
154     ViewMediator::getInstance()->setMainUrlLine(m_boardUrl);
155
156     switch (GlobalConfig::listSortOrder()) {
157     case GlobalConfig::EnumListSortOrder::Mark:
158         subjectList->sortItems(ColumnMark);
159         break;
160     case GlobalConfig::EnumListSortOrder::ID:
161         subjectList->sortItems(ColumnId);
162         break;
163     default:
164         // do nothing
165         break;
166     }
167
168     subjectList->setFocus();
169     updateKindLabel();
170
171     /* restore column size */
172     loadLayout();
173     loadHeaderOnOff();
174     m_enableSizeChange = true;
175     for (int i = 0, j = subjectList->columnCount(); i < j; i++) {
176         subjectList->resizeColumnToContents(i);
177     }
178     for (int i = 0, j = subjectList->rowCount(); i < j; i++) {
179         subjectList->resizeRowToContents(i);
180     }
181 }
182
183 /* public slot */ /* virtual */
184 void BoardView::setFocus()
185 {
186     subjectList->setFocus();
187 }
188
189 /* public slot */
190 void BoardView::slotFocusSearchCombo()
191 {
192     searchCombo->hasFocus() ? setFocus() : searchCombo->setFocus();
193 }
194
195 void BoardView::updateKindLabel()
196 {
197     QString fmtstr;
198     fmtstr += QString("<font color=#C50000>%1</font>").arg(m_unreadNum);
199     fmtstr += QString("/<font color=#00C200>%1</font>").arg(m_readNum);
200     fmtstr += QString("/<font color=#5AAAFF>%1</font>").arg(m_newNum);
201     kindLabel->setText(fmtstr);
202 }
203
204 void BoardView::setFont(const QFont& font)
205 {
206     subjectList->setFont(font);
207     searchCombo->setFont(font);
208 }
209
210 void BoardView::slotUpdateSubject(const KUrl& url)
211 {
212     QDateTime current = QDateTime::currentDateTime();
213
214     KUrl datUrl = getDatUrl(url);
215     for (int i = 0, j = subjectList->rowCount(); i < j; i++) {
216         if (subjectList->item(i, ColumnDatUrl)->text() == datUrl.prettyUrl()) {
217
218             switch (subjectList->item(i, ColumnMark)->data(Qt::UserRole)
219                     .toInt()) {
220             case Thread_Readed:
221             case Thread_Read:
222                 m_readNum--;
223                 break;
224             case Thread_New:
225                 m_newNum--;
226                 break;
227             case Thread_HasUnread:
228                 m_unreadNum--;
229                 break;
230             }
231
232             Thread* thread = Thread::getByUrlNew(datUrl);
233             if (thread == 0)
234                 return;
235             int id = subjectList->item(i, ColumnId)->text().toInt();
236             int order = subjectList->item(i, ColumnIdOrder)->text().toInt();
237             updateRow(i, datUrl, current, id, order);
238
239             updateKindLabel();
240
241             return;
242         }
243     }
244 }
245
246 /* if id == 0, this thread is old thread. */
247 /* private */
248 void BoardView::updateRow(int row, const KUrl& datUrl,
249         const QDateTime& current, int id, int order)
250 {
251     QDateTime since;
252     since.setTime_t(datToSince(datUrl));
253     DatManager datManager(datUrl);
254     QString threadName = datManager.threadName();
255     int resNum = datManager.getResNum();
256     int readNum = datManager.getReadNum();
257     int viewPos = datManager.getViewPos();
258     double speed = resNum / (since.secsTo(current) / (60.0 * 60.0 * 24.0));
259
260     if (id)
261         subjectList->item(row, ColumnId)->setText(QString::number(id));
262     subjectList->item(row, ColumnIdOrder)->setText(QString::number(order));
263     subjectList->item(row, ColumnSubject)->setText(threadName);
264     subjectList->item(row, ColumnResNum)->setText(QString("%1").arg(resNum, 4));
265     subjectList->item(row, ColumnReadNum)
266         ->setText((viewPos > 0) ? QString("%1").arg(viewPos, 4) : QString());
267     subjectList->item(row, ColumnUnread)
268         ->setText((viewPos > 0 && resNum > viewPos)
269                 ? QString("%1").arg(resNum - viewPos, 4) : QString());
270     subjectList->item(row, ColumnSince)
271         ->setText(since.toString("yy/MM/dd hh:mm"));
272     subjectList->item(row, ColumnDatUrl)->setText(datUrl.prettyUrl());
273     subjectList->item(row, ColumnSpeed)
274         ->setText(QString(" %1 ").arg(speed, 0, 'f', 2));
275
276     /* set mark order */
277     QTableWidgetItem *item = subjectList->item(row, ColumnMark);
278     int orderValue;
279     if (!id) { /* old thread */
280         orderValue = Thread_Old;
281     } else if (readNum > 0 && (resNum > readNum || resNum > viewPos)) {
282         /* There are new responses. */
283         item->setIcon(QIcon(SmallIcon("unread")));
284         m_unreadNum++;
285         orderValue = Thread_HasUnread;
286     } else if (readNum > 0) { /* Cache exists */
287         item->setIcon(QIcon(SmallIcon("read")));
288         m_readNum++;
289         orderValue = (viewPos > 1000) ? Thread_Readed : Thread_Read;
290     } else if (since.secsTo(current) < 3600 * GlobalConfig::markTime()) {
291         /* new thread */
292         item->setIcon(QIcon(SmallIcon("newthread")));
293         m_newNum++;
294         orderValue = Thread_New;
295     } else { /* normal */
296         item->setIcon(QIcon());
297         orderValue = Thread_Normal;
298     }
299     item->setData(Qt::UserRole, orderValue);
300
301     // no effect: m_unreadNum, m_readNum, m_newNum, markOrder
302     if (datManager.isMainThreadOpened() && resNum == readNum) {
303         /* opened */
304         subjectList->item(row, ColumnMark)->setIcon(QIcon(SmallIcon("open")));
305     }
306 }
307
308 void BoardView::deleteLog(const KUrl& url)
309 {
310     if (KMessageBox::warningYesNo(this, i18n("Do you want to delete Log?"),
311             "Kita") == KMessageBox::Yes) {
312         if (DatManager(url).deleteCache()) {
313             ViewMediator::getInstance()->closeThreadTab(url);
314             slotUpdateSubject(url);
315         }
316     }
317 }
318
319 void BoardView::slotSizeChange(int section, int oldSize, int newSize)
320 {
321     if (!m_enableSizeChange) return ;
322     if (autoResize()) return ;
323
324     QString configPath
325         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
326 //    KConfig config(configPath); TODO
327 //    subjectList->saveLayout(&config, "Layout"); TODO
328 }
329
330 void BoardView::loadLayout()
331 {
332     if (autoResize()) return ;
333     QString configPath
334         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
335     KConfig config(configPath);
336     // subjectList->restoreLayout(&config, "Layout"); TODO
337 }
338
339 void BoardView::saveHeaderOnOff()
340 {
341     QString configPath
342         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
343     KConfig config(configPath);
344
345     KConfigGroup group = config.group("Column");
346     for (int i = ColumnBegin; i <= ColumnEnd; i++) {
347         group.writeEntry(ThreadListHeaderView::attribute[i].keyName,
348                 subjectList->columnWidth(i) != 0);
349     }
350 }
351
352 void BoardView::loadHeaderOnOff()
353 {
354     QString configPath
355         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
356     KConfig config(configPath);
357
358     KConfigGroup group = config.group("Column");
359     for (int i = ColumnBegin; i <= ColumnEnd; i++) {
360         bool isShown = group.readEntry(
361                 ThreadListHeaderView::attribute[i].keyName,
362                 ThreadListHeaderView::attribute[i].showDefault);
363         isShown ? showColumn(i) : hideColumn(i);
364     }
365 }
366
367 bool BoardView::autoResize()
368 {
369     QString configPath
370         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
371     KConfig config(configPath);
372
373     return config.group("Column").readEntry("AutoResize", true);
374 }
375
376 void BoardView::setAutoResize(bool flag)
377 {
378     QString configPath
379         = KStandardDirs::locateLocal("appdata", "subjectview.conf");
380     KConfig config(configPath);
381
382     config.group("Column").writeEntry("AutoResize", flag);
383 }