Drop some more data from Channel on disconnect.
[konversation:konversation.git] / src / irc / channeloptionsdialog.cpp
1 /*
2   This program is free software; you can redistribute it and/or modify
3   it under the terms of the GNU General Public License as published by
4   the Free Software Foundation; either version 2 of the License, or
5   (at your option) any later version.
6 */
7
8 /*
9   Copyright (C) 2005-2007 Peter Simonsson <psn@linux.se>
10   Copyright (C) 2006 Dario Abatianni <eisfuchs@tigress.com>
11   Copyright (C) 2006-2007 Eike Hein <hein@kde.org>
12 */
13
14 #include "channeloptionsdialog.h"
15 #include "application.h"
16 #include "channel.h"
17
18 #include <QCheckBox>
19 #include <QHeaderView>
20 #include <QPushButton>
21 #include <QRegExp>
22 #include <QStandardItemModel>
23 #include <QKeyEvent>
24 #include <QItemSelectionModel>
25 #include <QTreeWidget>
26
27 namespace Konversation
28 {
29     ChannelOptionsDialog::ChannelOptionsDialog(Channel *channel)
30         : KDialog(channel)
31     {
32         setCaption(  i18n("Channel Settings for %1", channel->getName() ) );
33         setButtons( KDialog::Ok|KDialog::Cancel );
34         setDefaultButton( KDialog::Ok );
35
36         Q_ASSERT(channel);
37         m_ui.setupUi(mainWidget());
38
39         m_ui.addBan->setIcon(KIcon("list-add"));
40         m_ui.updateBan->setIcon(KIcon("edit-rename"));
41         m_ui.removeBan->setIcon(KIcon("list-remove"));
42
43         QStandardItemModel *modesModel = new QStandardItemModel(m_ui.otherModesList);
44         m_ui.otherModesList->setModel(modesModel);
45         m_ui.otherModesList->hide();
46
47         m_ui.banListSearchLine->setTreeWidget(m_ui.banList);
48
49         m_topicModel = new TopicListModel(m_ui.topicHistoryView);
50         m_ui.topicHistoryView->setModel(m_topicModel);
51         m_ui.topicHistoryView->sortByColumn(0, Qt::DescendingOrder);
52
53         m_channel = channel;
54         m_editingTopic = false;
55
56         connect(m_ui.topicHistoryView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
57                 this, SLOT(topicHistoryItemClicked(const QItemSelection&)));
58         connect(m_ui.toggleAdvancedModes, SIGNAL(clicked()), this, SLOT(toggleAdvancedModes()));
59         connect(m_ui.topicEdit, SIGNAL(undoAvailable(bool)), this, SLOT(topicBeingEdited(bool)));
60         connect(this, SIGNAL(finished()), m_ui.topicEdit, SLOT(clear()));
61
62         connect(m_channel, SIGNAL(topicHistoryChanged()), this, SLOT(refreshTopicHistory()));
63
64         connect(m_channel, SIGNAL(modesChanged()), this, SLOT(refreshModes()));
65         connect(m_channel->getServer(), SIGNAL(channelNickChanged(const QString&)), this, SLOT(refreshEnableModes()));
66
67         connect(this, SIGNAL(okClicked()), this, SLOT(changeOptions()));
68
69         connect(m_channel, SIGNAL(banAdded(const QString&)), this, SLOT(addBan(const QString&)));
70         connect(m_channel, SIGNAL(banRemoved(const QString&)), this, SLOT(removeBan(const QString&)));
71         connect(m_channel, SIGNAL(banListCleared()), m_ui.banList, SLOT(clear()));
72
73         connect(m_ui.addBan, SIGNAL(clicked()), this, SLOT(addBanClicked()));
74         connect(m_ui.updateBan, SIGNAL(clicked()), this, SLOT(updateBanClicked()));
75         connect(m_ui.removeBan, SIGNAL(clicked()), this, SLOT(removeBanClicked()));
76         connect(m_ui.banList, SIGNAL(itemSelectionChanged()), this, SLOT(banSelectionChanged()));
77         connect(m_ui.hostmask, SIGNAL(textChanged(QString)), this, SLOT(hostmaskChanged(QString)));
78
79         m_ui.topicModeChBox->setWhatsThis(whatsThisForMode('T'));
80         m_ui.messageModeChBox->setWhatsThis(whatsThisForMode('N'));
81         m_ui.secretModeChBox->setWhatsThis(whatsThisForMode('S'));
82         m_ui.inviteModeChBox->setWhatsThis(whatsThisForMode('I'));
83         m_ui.moderatedModeChBox->setWhatsThis(whatsThisForMode('M'));
84         m_ui.keyModeChBox->setWhatsThis(whatsThisForMode('P'));
85         m_ui.keyModeEdit->setWhatsThis(whatsThisForMode('P'));
86         m_ui.userLimitEdit->setWhatsThis(whatsThisForMode('L'));
87         m_ui.userLimitChBox->setWhatsThis(whatsThisForMode('L'));
88
89         refreshTopicHistory();
90         refreshBanList();
91         refreshAllowedChannelModes();
92         refreshModes();
93
94         setInitialSize(QSize(450, 380));
95     }
96
97     ChannelOptionsDialog::~ChannelOptionsDialog()
98     {
99     }
100
101     void ChannelOptionsDialog::changeOptions()
102     {
103         QString newTopic = topic();
104         QString oldTopic = m_channel->getTopicHistory().isEmpty() ? 0 : m_channel->getTopicHistory().first().section(' ', 2);
105
106         if(newTopic != oldTopic)
107         {
108             // Pass a ^A so we can determine if we want to clear the channel topic.
109             if (newTopic.isEmpty())
110             {
111                 if (!oldTopic.isEmpty())
112                     m_channel->sendChannelText(Preferences::self()->commandChar() + "TOPIC " + m_channel->getName() + " \x01");
113             }
114             else
115                 m_channel->sendChannelText(Preferences::self()->commandChar() + "TOPIC " + m_channel->getName() + ' ' + newTopic);
116         }
117
118         QStringList newModeList = modes();
119         QStringList currentModeList = m_channel->getModeList();
120         QStringList rmModes;
121         QStringList addModes;
122         QStringList tmp;
123         QString modeString;
124         bool plus;
125         QString command("MODE %1 %2%3 %4");
126
127         for(QStringList::ConstIterator it = newModeList.constBegin(); it != newModeList.constEnd(); ++it)
128         {
129             modeString = (*it).mid(1);
130             plus = ((*it)[0] == '+');
131             tmp = currentModeList.filter(QRegExp('^' + modeString));
132
133             if(tmp.isEmpty() && plus)
134             {
135                 m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("+").arg(modeString[0]).arg(modeString.mid(1)));
136             }
137             else if(!tmp.isEmpty() && !plus)
138             {
139                 //FIXME: Bahamuth requires the key parameter for -k, but ircd breaks on -l with limit number.
140                 //Hence two versions of this.
141                 if (modeString[0] == 'k')
142                     m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("-").arg(modeString[0]).arg(modeString.mid(1)));
143                 else
144                     m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("-").arg(modeString[0]).arg(""));
145             }
146         }
147         hide();
148     }
149
150     void ChannelOptionsDialog::toggleAdvancedModes()
151     {
152         bool ison = m_ui.toggleAdvancedModes->isChecked();
153         m_ui.otherModesList->setVisible(ison);
154         if(ison)
155         {
156             m_ui.toggleAdvancedModes->setText(i18n("&Hide Advanced Modes &lt;&lt;"));
157         }
158         else
159         {
160             m_ui.toggleAdvancedModes->setText(i18n("&Show Advanced Modes &gt;&gt;"));
161         }
162     }
163
164     void ChannelOptionsDialog::topicBeingEdited(bool edited)
165     {
166         m_editingTopic = edited;
167     }
168
169     QString ChannelOptionsDialog::topic()
170     {
171         return m_ui.topicEdit->toPlainText().replace('\n',' ');
172     }
173
174     void ChannelOptionsDialog::refreshTopicHistory()
175     {
176         QStringList history = m_channel->getTopicHistory();
177         QList<TopicItem> topicList;
178
179         for(QStringList::ConstIterator it = --history.constEnd(); it != --history.constBegin(); --it)
180         {
181             TopicItem item;
182             item.author = (*it).section(' ', 1, 1);
183             item.timestamp.setTime_t((*it).section(' ', 0 ,0).toUInt());
184             item.topic = (*it).section(' ', 2);
185             topicList.append(item);
186         }
187         m_topicModel->setTopicList(topicList);
188         m_topicModel->sort(m_ui.topicHistoryView->header()->sortIndicatorSection(),
189                            m_ui.topicHistoryView->header()->sortIndicatorOrder());
190         if (topicList.count() > 0)
191         {
192             // Save current topic
193             TopicItem topic = topicList.last();
194             // Find current topic's row index
195             int row = 0;
196             QList<TopicItem> sortedList = m_topicModel->topicList();
197             for (int i = 0; i < sortedList.count(); ++i)
198             {
199                 if (sortedList.at(i).author == topic.author &&
200                     sortedList.at(i).timestamp == topic.timestamp &&
201                     sortedList.at(i).topic == topic.topic)
202                 {
203                     row = i;
204                     break;
205                 }
206             }
207             // Select current topic and update topic preview
208             QItemSelection selection(m_topicModel->index(row, 0, QModelIndex()), m_topicModel->index(row, 1, QModelIndex()));
209             m_ui.topicHistoryView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
210             // Make sure that the item is visible
211             m_ui.topicHistoryView->scrollTo(m_topicModel->index(row, 0, QModelIndex()));
212         }
213     }
214
215     void ChannelOptionsDialog::topicHistoryItemClicked(const QItemSelection& selection)
216     {
217         if (!selection.isEmpty())
218         {
219             // update topic preview
220             m_ui.topicPreview->setText(m_topicModel->data(selection.indexes().first(), Qt::UserRole).toString());
221
222             if (!m_editingTopic)
223                 m_ui.topicEdit->setText(m_topicModel->data(selection.indexes().first(), Qt::UserRole).toString());
224         }
225         else
226         {
227             // clear topic preview
228             m_ui.topicPreview->clear();
229
230             if (!m_editingTopic)
231                 m_ui.topicEdit->clear();
232         }
233     }
234
235     void ChannelOptionsDialog::refreshEnableModes(bool forceUpdate)
236     {
237         if(!m_channel->getOwnChannelNick() || m_channel->getOwnChannelNick()->isChanged() || forceUpdate)
238         {
239             // cache the value
240             m_isAnyTypeOfOp = m_channel->getOwnChannelNick() ? m_channel->getOwnChannelNick()->isAnyTypeOfOp() : false;
241
242             m_ui.topicEdit->setReadOnly(!m_isAnyTypeOfOp && m_ui.topicModeChBox->isChecked());
243
244             m_ui.topicModeChBox->setEnabled(m_isAnyTypeOfOp);
245             m_ui.messageModeChBox->setEnabled(m_isAnyTypeOfOp);
246             m_ui.userLimitChBox->setEnabled(m_isAnyTypeOfOp);
247             m_ui.userLimitEdit->setEnabled(m_isAnyTypeOfOp);
248             m_ui.inviteModeChBox->setEnabled(m_isAnyTypeOfOp);
249             m_ui.moderatedModeChBox->setEnabled(m_isAnyTypeOfOp);
250             m_ui.secretModeChBox->setEnabled(m_isAnyTypeOfOp);
251             m_ui.keyModeChBox->setEnabled(m_isAnyTypeOfOp);
252             m_ui.keyModeEdit->setEnabled(m_isAnyTypeOfOp);
253
254             QStandardItemModel* model = qobject_cast<QStandardItemModel*>(m_ui.otherModesList->model());
255
256             if (model)
257             {
258                 QList<QStandardItem*> items = model->findItems("*", Qt::MatchWildcard, 0);
259                 items += model->findItems("*", Qt::MatchWildcard, 1);
260
261                 foreach (QStandardItem* item, items)
262                     item->setEnabled(m_isAnyTypeOfOp);
263             }
264
265             m_ui.addBan->setEnabled(m_isAnyTypeOfOp);
266             m_ui.updateBan->setEnabled(m_isAnyTypeOfOp);
267             m_ui.removeBan->setEnabled(m_isAnyTypeOfOp);
268             banSelectionChanged();
269
270             m_ui.hostmask->setEnabled(m_isAnyTypeOfOp);
271             hostmaskChanged(m_ui.hostmask->text());
272         }
273     }
274
275     void ChannelOptionsDialog::refreshAllowedChannelModes()
276     {
277         QString modeString = m_channel->getServer()->allowedChannelModes();
278         // These modes are handled in a special way: ntimslkbeI
279         modeString.remove('t');
280         modeString.remove('n');
281         modeString.remove('l');
282         modeString.remove('i');
283         modeString.remove('m');
284         modeString.remove('s');
285         modeString.remove('k');
286         modeString.remove('b');
287         modeString.remove('e');
288         modeString.remove('I');
289         modeString.remove('O');
290         modeString.remove('o');
291         modeString.remove('v');
292
293         QStandardItemModel *modesModel = qobject_cast<QStandardItemModel *>(m_ui.otherModesList->model());
294
295         modesModel->clear();
296         modesModel->setHorizontalHeaderLabels(QStringList() << i18n("Mode") << i18n("Parameter"));
297
298         for(int i = 0; i < modeString.length(); i++)
299         {
300             QList<QStandardItem *> newRow;
301             QStandardItem *item = 0;
302
303             if(!Preferences::self()->useLiteralModes() && getChannelModesHash().contains(modeString[i]))
304                 item = new QStandardItem(i18nc("<mode character> (<mode description>)","%1 (%2)", modeString[i], getChannelModesHash().value(modeString[i])));
305             else
306                 item = new QStandardItem(QString(modeString[i]));
307
308             item->setData(QString(modeString[i]));
309             item->setCheckable(true);
310             item->setEditable(false);
311             newRow.append(item);
312             item = new QStandardItem();
313             item->setEditable(true);
314             newRow.append(item);
315             modesModel->invisibleRootItem()->appendRow(newRow);
316         }
317     }
318
319     void ChannelOptionsDialog::refreshModes()
320     {
321         QStringList modes = m_channel->getModeList();
322
323         m_ui.topicModeChBox->setChecked(false);
324         m_ui.messageModeChBox->setChecked(false);
325         m_ui.userLimitChBox->setChecked(false);
326         m_ui.userLimitEdit->setValue(0);
327         m_ui.inviteModeChBox->setChecked(false);
328         m_ui.moderatedModeChBox->setChecked(false);
329         m_ui.secretModeChBox->setChecked(false);
330         m_ui.keyModeChBox->setChecked(false);
331         m_ui.keyModeEdit->setText("");
332
333         QStandardItemModel *modesModel = qobject_cast<QStandardItemModel *>(m_ui.otherModesList->model());
334         for (int i = 0; i < modesModel->rowCount(); ++i)
335         {
336             modesModel->item(i, 0)->setCheckState(Qt::Unchecked);
337         }
338
339         char mode;
340
341         foreach (const QString &currentMode, modes)
342         {
343             mode = currentMode[0].toLatin1();
344             switch(mode)
345             {
346                 case 't':
347                     m_ui.topicModeChBox->setChecked(true);
348                     break;
349                 case 'n':
350                     m_ui.messageModeChBox->setChecked(true);
351                     break;
352                 case 'l':
353                     m_ui.userLimitChBox->setChecked(true);
354                     m_ui.userLimitEdit->setValue(currentMode.mid(1).toInt());
355                     break;
356                 case 'i':
357                     m_ui.inviteModeChBox->setChecked(true);
358                     break;
359                 case 'm':
360                     m_ui.moderatedModeChBox->setChecked(true);
361                     break;
362                 case 's':
363                     m_ui.secretModeChBox->setChecked(true);
364                     break;
365                 case 'k':
366                     m_ui.keyModeChBox->setChecked(true);
367                     m_ui.keyModeEdit->setText(currentMode.mid(1));
368                     break;
369                 default:
370                 {
371                     bool found = false;
372                     QString modeString;
373                     modeString = mode;
374
375                     for (int i = 0; !found && i < modesModel->rowCount(); ++i)
376                     {
377                         QStandardItem *item = modesModel->item(i, 0);
378                         if (item->data().toString() == modeString)
379                         {
380                             found = true;
381                             item->setCheckState(Qt::Checked);
382                             modesModel->item(i, 1)->setText(currentMode.mid(1));
383                         }
384                     }
385
386                     break;
387                 }
388             }
389         }
390
391         refreshEnableModes(true);
392     }
393
394     QStringList ChannelOptionsDialog::modes()
395     {
396         QStringList modes;
397         QString mode;
398
399         mode = (m_ui.topicModeChBox->isChecked() ? "+" : "-");
400         mode += 't';
401         modes.append(mode);
402         mode = (m_ui.messageModeChBox->isChecked() ? "+" : "-");
403         mode += 'n';
404         modes.append(mode);
405         mode = (m_ui.userLimitChBox->isChecked() ? "+" : "-");
406         mode += 'l' + QString::number( m_ui.userLimitEdit->value() );
407         modes.append(mode);
408         mode = (m_ui.inviteModeChBox->isChecked() ? "+" : "-");
409         mode += 'i';
410         modes.append(mode);
411         mode = (m_ui.moderatedModeChBox->isChecked() ? "+" : "-");
412         mode += 'm';
413         modes.append(mode);
414         mode = (m_ui.secretModeChBox->isChecked() ? "+" : "-");
415         mode += 's';
416         modes.append(mode);
417
418         if (m_ui.keyModeChBox->isChecked() && !m_ui.keyModeEdit->text().isEmpty())
419         {
420             mode = '+';
421             mode += 'k' + m_ui.keyModeEdit->text();
422             modes.append(mode);
423         }
424         else if (!m_ui.keyModeChBox->isChecked())
425         {
426             mode = '-';
427             mode += 'k' + m_ui.keyModeEdit->text();
428             modes.append(mode);
429         }
430
431         QStandardItemModel *modesModel = qobject_cast<QStandardItemModel *>(m_ui.otherModesList->model());
432         for (int i = 0; i < modesModel->rowCount(); ++i)
433         {
434             mode = (modesModel->item(i, 0)->checkState() == Qt::Checked ? "+" : "-");
435             mode += modesModel->item(i, 0)->data().toString() + modesModel->item(i, 1)->text();
436             modes.append(mode);
437         }
438
439         return modes;
440     }
441
442     // Ban List tab related functions
443
444     void ChannelOptionsDialog::refreshBanList()
445     {
446         QStringList banlist = m_channel->getBanList();
447         m_ui.banList->clear();
448
449         for (QStringList::const_iterator it = --banlist.constEnd(); it != --banlist.constBegin(); --it)
450             addBan((*it));
451     }
452
453     void ChannelOptionsDialog::addBan(const QString& newban)
454     {
455         BanListViewItem *item = new BanListViewItem(m_ui.banList, newban.section(' ', 0, 0), newban.section(' ', 1, 1).section('!', 0, 0), newban.section(' ', 2 ,2).toUInt());
456         // set item as current item
457         m_ui.banList->setCurrentItem(item);
458         // update button states
459         hostmaskChanged(m_ui.hostmask->text());
460     }
461
462     void ChannelOptionsDialog::removeBan(const QString& ban)
463     {
464         QList<QTreeWidgetItem *> items = m_ui.banList->findItems(ban, Qt::MatchCaseSensitive | Qt::MatchExactly, 0);
465         if (items.count() > 0)
466           delete items.at(0);
467     }
468
469     void ChannelOptionsDialog::addBanClicked()
470     {
471       QString newHostmask = m_ui.hostmask->text();
472       if (!newHostmask.isEmpty())
473         m_channel->getServer()->requestBan(QStringList(newHostmask), m_channel->getName(), QString());
474     }
475
476     void ChannelOptionsDialog::removeBanClicked()
477     {
478       QString oldHostmask = m_ui.banList->currentItem()->text(0);
479       // We delete the existing item because it's possible the server may
480       // Modify the ban causing us not to catch it. If that happens we'll be
481       // stuck with a stale item and a new item with the modified hostmask.
482       delete m_ui.banList->currentItem();
483       // request unban
484       m_channel->getServer()->requestUnban(oldHostmask, m_channel->getName());
485     }
486
487     void ChannelOptionsDialog::updateBanClicked()
488     {
489       QString oldHostmask = m_ui.banList->currentItem()->text(0);
490       QString newHostmask = m_ui.hostmask->text();
491       if (!newHostmask.isEmpty() && newHostmask.compare(oldHostmask))
492       {
493         // We delete the existing item because it's possible the server may
494         // Modify the ban causing us not to catch it. If that happens we'll be
495         // stuck with a stale item and a new item with the modified hostmask.
496         delete m_ui.banList->currentItem();
497         // request unban for the of the old hostmask
498         m_channel->getServer()->requestUnban(oldHostmask, m_channel->getName());
499         // request ban for the of the old hostmask
500         m_channel->getServer()->requestBan(QStringList(newHostmask), m_channel->getName(), QString());
501       }
502     }
503     /// Enables/disables updateBan and removeBan buttons depending on the currentItem of the banList
504     void ChannelOptionsDialog::banSelectionChanged()
505     {
506       if (m_ui.banList->currentItem())
507       {
508         m_ui.updateBan->setEnabled(m_isAnyTypeOfOp);
509         m_ui.removeBan->setEnabled(m_isAnyTypeOfOp);
510         // update line edit content
511         m_ui.hostmask->setText(m_ui.banList->currentItem()->text(0));
512       }
513       else
514       {
515         m_ui.updateBan->setEnabled(false);
516         m_ui.removeBan->setEnabled(false);
517       }
518     }
519     /// Enables/disables addBan and updateBan buttons depending on the value of @p text
520     void ChannelOptionsDialog::hostmaskChanged(QString text)
521     {
522       if (text.trimmed().length() != 0)
523       {
524         if (m_isAnyTypeOfOp)
525         {
526           QList<QTreeWidgetItem*> items = m_ui.banList->findItems(text, Qt::MatchExactly | Qt::MatchCaseSensitive, 0);
527           m_ui.addBan->setEnabled(items.count() == 0);
528           m_ui.updateBan->setEnabled(items.count() == 0 && m_ui.banList->currentItem());
529         }
530       }
531       else
532       {
533         m_ui.addBan->setEnabled(false);
534         m_ui.updateBan->setEnabled(false);
535       }
536     }
537     // This is our implementation of BanListViewItem
538
539     BanListViewItem::BanListViewItem(QTreeWidget *parent)
540       : QTreeWidgetItem()
541     {
542         parent->addTopLevelItem(this);
543     }
544
545     BanListViewItem::BanListViewItem (QTreeWidget *parent, const QString& label1, const QString& label2,
546         uint timestamp) : QTreeWidgetItem()
547     {
548         setText(0, label1);
549         setText(1, label2);
550         m_timestamp.setTime_t(timestamp);
551         setText(2, KGlobal::locale()->formatDateTime(m_timestamp, KLocale::ShortDate, true));
552         setData(2, Qt::UserRole, m_timestamp);
553         parent->addTopLevelItem(this);
554     }
555
556     bool BanListViewItem::operator<(const QTreeWidgetItem &item) const
557     {
558         if (treeWidget()->sortColumn() == 2)
559         {
560             QVariant userdata = item.data(2, Qt::UserRole);
561             if (userdata.isValid() && userdata.type() == QVariant::DateTime)
562             {
563               return m_timestamp < userdata.toDateTime();
564             }
565         }
566
567         return text(treeWidget()->sortColumn()) < item.text(treeWidget()->sortColumn());
568     }
569
570     TopicListModel::TopicListModel(QObject* parent)
571         : QAbstractListModel(parent)
572     {
573     }
574
575     QList<TopicItem> TopicListModel::topicList() const
576     {
577         return m_topicList;
578     }
579
580     void TopicListModel::setTopicList(const QList<TopicItem>& list)
581     {
582         m_topicList = list;
583         reset();
584     }
585
586     int TopicListModel::columnCount(const QModelIndex& /*parent*/) const
587     {
588         return 2;
589     }
590
591     int TopicListModel::rowCount(const QModelIndex& /*parent*/) const
592     {
593         return m_topicList.count();
594     }
595
596     QVariant TopicListModel::data(const QModelIndex& index, int role) const
597     {
598         if(!index.isValid() || index.row() >= m_topicList.count ())
599             return QVariant();
600
601         const TopicItem& item = m_topicList[index.row()];
602
603         if(role == Qt::DisplayRole)
604         {
605             switch(index.column())
606             {
607                 case 0:
608                     return KGlobal::locale()->formatDateTime(item.timestamp, KLocale::ShortDate, true);
609                 case 1:
610                     return item.author;
611                 default:
612                     return QVariant();
613             }
614         }
615         else if(role == Qt::UserRole)
616         {
617             return item.topic;
618         }
619
620         return QVariant();
621     }
622
623     QVariant TopicListModel::headerData (int section, Qt::Orientation orientation, int role) const
624     {
625         if(orientation == Qt::Vertical || role != Qt::DisplayRole)
626             return QVariant();
627
628         switch(section)
629         {
630             case 0:
631                 return i18n("Timestamp");
632             case 1:
633                 return i18n("Author");
634             default:
635                 return QVariant();
636         }
637     }
638
639     bool lessThanTimestamp(const TopicItem& item1, const TopicItem& item2)
640     {
641         return item1.timestamp < item2.timestamp;
642     }
643
644     bool moreThanTimestamp(const TopicItem& item1, const TopicItem& item2)
645     {
646         return item1.timestamp > item2.timestamp;
647     }
648
649     bool lessThanAuthor(const TopicItem& item1, const TopicItem& item2)
650     {
651         return item1.author.toLower() < item2.author.toLower();
652     }
653
654     bool moreThanAuthor(const TopicItem& item1, const TopicItem& item2)
655     {
656         return item1.author.toLower() > item2.author.toLower();
657     }
658
659     void TopicListModel::sort(int column, Qt::SortOrder order)
660     {
661         if(order == Qt::AscendingOrder)
662         {
663             switch(column)
664             {
665                 case 0:
666                     qStableSort(m_topicList.begin(), m_topicList.end(), lessThanTimestamp);
667                     break;
668                 case 1:
669                     qStableSort(m_topicList.begin(), m_topicList.end(), lessThanAuthor);
670                     break;
671             }
672         }
673         else
674         {
675             switch(column)
676             {
677                 case 0:
678                     qStableSort(m_topicList.begin(), m_topicList.end(), moreThanTimestamp);
679                     break;
680                 case 1:
681                     qStableSort(m_topicList.begin(), m_topicList.end(), moreThanAuthor);
682                     break;
683             }
684         }
685
686         reset();
687     }
688 }
689
690 QString Konversation::ChannelOptionsDialog::whatsThisForMode(char mode)
691 {
692     switch (mode) {
693     case 'T':
694         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>The <b>T</b>opic mode means that only the channel operator can change the topic for the channel.</p></qt>");
695     case 'N':
696         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p><b>N</b>o messages from outside means users who are not in the channel cannot send messages for everybody in the channel to see.  Almost all channels have this set to prevent nuisance messages.</p></qt>");
697     case 'S':
698         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>A <b>S</b>ecret channel will not show up in the channel list, nor will any user be able to see that you are in the channel with the <em>WHOIS</em> command or anything similar.  Only the people that are in the same channel will know that you are in this channel, if this mode is set.</p></qt>");
699     case 'I':
700         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>An <b>I</b>nvite only channel means that people can only join the channel if they are invited.  To invite someone, a channel operator needs to issue the command <em>/invite nick</em> from within the channel.</p></qt>");
701     case 'P':
702         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>A <b>P</b>rivate channel is shown in a listing of all channels, but the topic is not shown.  A user's <em>WHOIS</em> may or may not show them as being in a private channel depending on the IRC server.</p></qt>");
703     case 'M':
704         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>A <b>M</b>oderated channel is one where only operators, half-operators and those with voice can talk.</p></qt>");
705     case 'K':
706         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>A protected channel requires users to enter a password in order to join.</p></qt>");
707     case 'L':
708         return i18n("<qt><p>These control the <em>mode</em> of the channel.  Only an operator can change these.</p><p>A channel that has a user <b>L</b>imit means that only that many users can be in the channel at any one time.  Some channels have a bot that sits in the channel and changes this automatically depending on how busy the channel is.</p></qt>");
709     default:
710         kWarning() << "called for unknown mode" << mode;
711         return QString();
712     }
713 }
714
715 #include "channeloptionsdialog.moc"