1 /***************************************************************************
2 * Copyright (C) 2005-09 by the Quassel Project *
3 * devel@quassel-irc.org *
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) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "inputwidget.h"
24 #include "actioncollection.h"
25 #include "bufferview.h"
27 #include "iconloader.h"
29 #include "jumpkeyhandler.h"
30 #include "networkmodel.h"
32 #include "qtuisettings.h"
33 #include "tabcompleter.h"
35 InputWidget::InputWidget(QWidget *parent)
36 : AbstractItemView(parent),
40 connect(ui.inputEdit, SIGNAL(textEntered(QString)), this, SLOT(sendText(QString)));
41 connect(ui.ownNick, SIGNAL(activated(QString)), this, SLOT(changeNick(QString)));
43 layout()->setAlignment(ui.ownNick, Qt::AlignBottom);
44 layout()->setAlignment(ui.inputEdit, Qt::AlignBottom);
46 setFocusProxy(ui.inputEdit);
47 ui.ownNick->setFocusProxy(ui.inputEdit);
49 ui.ownNick->setSizeAdjustPolicy(QComboBox::AdjustToContents);
50 ui.ownNick->installEventFilter(new MouseWheelFilter(this));
51 ui.inputEdit->installEventFilter(new JumpKeyHandler(this));
53 ui.inputEdit->setMinHeight(1);
54 ui.inputEdit->setMaxHeight(5);
55 ui.inputEdit->setMode(MultiLineEdit::MultiLine);
57 new TabCompleter(ui.inputEdit);
59 QtUiStyleSettings s("Fonts");
60 s.notify("InputLine", this, SLOT(setCustomFont(QVariant)));
61 setCustomFont(s.value("InputLine", QFont()));
63 ActionCollection *coll = QtUi::actionCollection();
65 Action *activateInputline = coll->add<Action>("FocusInputLine");
66 connect(activateInputline, SIGNAL(triggered()), SLOT(setFocus()));
67 activateInputline->setText(tr("Focus Input Line"));
68 activateInputline->setShortcut(tr("Ctrl+L"));
71 InputWidget::~InputWidget() {
74 void InputWidget::setCustomFont(const QVariant &v) {
75 QFont font = v.value<QFont>();
76 if(font.family().isEmpty())
77 font = QApplication::font();
78 ui.inputEdit->setCustomFont(font);
81 bool InputWidget::eventFilter(QObject *watched, QEvent *event) {
82 if(event->type() != QEvent::KeyPress)
85 // keys from BufferView should be sent to (and focus) the input line
86 BufferView *view = qobject_cast<BufferView *>(watched);
88 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
89 if(keyEvent->text().length() == 1 && !(keyEvent->modifiers() & (Qt::ControlModifier ^ Qt::AltModifier)) ) { // normal key press
90 QChar c = keyEvent->text().at(0);
91 if(c.isLetterOrNumber() || c.isSpace() || c.isPunct() || c.isSymbol()) {
93 QCoreApplication::sendEvent(inputLine(), keyEvent);
102 void InputWidget::keyPressEvent(QKeyEvent * event) {
103 if(event->matches(QKeySequence::Find)) {
104 QAction *act = GraphicalUi::actionCollection()->action("ToggleSearchBar");
110 AbstractItemView::keyPressEvent(event);
113 void InputWidget::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
115 NetworkId networkId = current.data(NetworkModel::NetworkIdRole).value<NetworkId>();
116 if(networkId == _networkId)
119 setNetwork(networkId);
120 updateNickSelector();
121 updateEnabledState();
124 void InputWidget::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) {
125 QItemSelectionRange changedArea(topLeft, bottomRight);
126 if(changedArea.contains(selectionModel()->currentIndex())) {
127 updateEnabledState();
131 void InputWidget::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) {
134 for(int row = start; row <= end; row++) {
135 child = model()->index(row, 0, parent);
136 if(NetworkModel::NetworkItemType != child.data(NetworkModel::ItemTypeRole).toInt())
138 networkId = child.data(NetworkModel::NetworkIdRole).value<NetworkId>();
139 if(networkId == _networkId) {
141 updateNickSelector();
147 void InputWidget::updateEnabledState() {
148 QModelIndex currentIndex = selectionModel()->currentIndex();
150 const Network *net = Client::networkModel()->networkByIndex(currentIndex);
151 bool enabled = false;
153 // disable inputline if it's a channelbuffer we parted from or...
154 enabled = (currentIndex.data(NetworkModel::ItemActiveRole).value<bool>() || (currentIndex.data(NetworkModel::BufferTypeRole).toInt() != BufferInfo::ChannelBuffer));
155 // ... if we're not connected to the network at all
156 enabled &= net->isConnected();
158 ui.inputEdit->setEnabled(enabled);
161 const Network *InputWidget::currentNetwork() const {
162 return Client::network(_networkId);
165 BufferInfo InputWidget::currentBufferInfo() const {
166 return selectionModel()->currentIndex().data(NetworkModel::BufferInfoRole).value<BufferInfo>();
169 void InputWidget::setNetwork(NetworkId networkId) {
170 if(_networkId == networkId)
173 const Network *previousNet = Client::network(_networkId);
175 disconnect(previousNet, 0, this, 0);
176 if(previousNet->me())
177 disconnect(previousNet->me(), 0, this, 0);
180 _networkId = networkId;
182 const Network *network = Client::network(networkId);
184 connect(network, SIGNAL(identitySet(IdentityId)), this, SLOT(setIdentity(IdentityId)));
186 setIdentity(network->identity());
193 void InputWidget::connectMyIrcUser() {
194 const Network *network = currentNetwork();
196 connect(network->me(), SIGNAL(nickSet(const QString &)), this, SLOT(updateNickSelector()));
197 connect(network->me(), SIGNAL(userModesSet(QString)), this, SLOT(updateNickSelector()));
198 connect(network->me(), SIGNAL(userModesAdded(QString)), this, SLOT(updateNickSelector()));
199 connect(network->me(), SIGNAL(userModesRemoved(QString)), this, SLOT(updateNickSelector()));
200 connect(network->me(), SIGNAL(awaySet(bool)), this, SLOT(updateNickSelector()));
201 disconnect(network, SIGNAL(myNickSet(const QString &)), this, SLOT(connectMyIrcUser()));
202 updateNickSelector();
204 connect(network, SIGNAL(myNickSet(const QString &)), this, SLOT(connectMyIrcUser()));
208 void InputWidget::setIdentity(IdentityId identityId) {
209 if(_identityId == identityId)
212 const Identity *previousIdentity = Client::identity(_identityId);
214 disconnect(previousIdentity, 0, this, 0);
216 _identityId = identityId;
218 const Identity *identity = Client::identity(identityId);
220 connect(identity, SIGNAL(nicksSet(QStringList)), this, SLOT(updateNickSelector()));
224 updateNickSelector();
227 void InputWidget::updateNickSelector() const {
230 const Network *net = currentNetwork();
234 const Identity *identity = Client::identity(net->identity());
236 qWarning() << "InputWidget::updateNickSelector(): can't find Identity for Network" << net->networkId() << "IdentityId:" << net->identity();
241 QStringList nicks = identity->nicks();
242 if((nickIdx = nicks.indexOf(net->myNick())) == -1) {
243 nicks.prepend(net->myNick());
250 IrcUser *me = net->me();
252 nicks[nickIdx] = net->myNick();
253 if(!me->userModes().isEmpty())
254 nicks[nickIdx] += QString(" (+%1)").arg(me->userModes());
257 ui.ownNick->addItems(nicks);
259 if(me && me->isAway())
260 ui.ownNick->setItemData(nickIdx, SmallIcon("user-away"), Qt::DecorationRole);
262 ui.ownNick->setCurrentIndex(nickIdx);
265 void InputWidget::changeNick(const QString &newNick) const {
266 const Network *net = currentNetwork();
267 if(!net || net->isMyNick(newNick))
270 // we reset the nick selecter as we have no confirmation yet, that this will succeed.
271 // if the action succeeds it will be properly updated anyways.
272 updateNickSelector();
273 Client::userInput(BufferInfo::fakeStatusBuffer(net->networkId()), QString("/NICK %1").arg(newNick));
276 void InputWidget::sendText(const QString &text) const {
277 Client::userInput(currentBufferInfo(), text);
281 // MOUSE WHEEL FILTER
282 MouseWheelFilter::MouseWheelFilter(QObject *parent)
287 bool MouseWheelFilter::eventFilter(QObject *obj, QEvent *event) {
288 if(event->type() != QEvent::Wheel)
289 return QObject::eventFilter(obj, event);