root/trunk/qt4-gui/src/views/userviewbase.cpp

Revision 6483, 11.2 kB (checked in by flynd, 4 months ago)

Always move user if shift key is pressed. Always just add to new group if ctrl is pressed.

Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of Licq, an instant messaging client for UNIX.
4 * Copyright (C) 1999-2006 Licq developers
5 *
6 * Licq is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Licq is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Licq; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21#include "userviewbase.h"
22
23#include <QUrl>
24
25#include <licq_icqd.h>
26
27#include "contactlist/contactlist.h"
28
29#include "userevents/usersendcontactevent.h"
30#include "userevents/usersendfileevent.h"
31#include "userevents/usersendmsgevent.h"
32#include "userevents/usersendurlevent.h"
33
34#include "config/contactlist.h"
35#include "config/skin.h"
36
37#include "core/groupmenu.h"
38#include "core/licqgui.h"
39#include "core/mainwin.h"
40#include "core/usermenu.h"
41
42#include "contactdelegate.h"
43
44using namespace LicqQtGui;
45
46UserViewBase::UserViewBase(ContactListModel* contactList, QWidget* parent)
47  : QTreeView(parent),
48    myContactList(contactList),
49    myAllowScrollTo(false)
50{
51  setItemDelegate(new ContactDelegate(this, this));
52  setEditTriggers(EditKeyPressed);
53
54  // Look'n'Feel
55  setIndentation(0);
56  setVerticalScrollMode(ScrollPerPixel);
57  setAcceptDrops(true);
58  setRootIsDecorated(false);
59  setAllColumnsShowFocus(true);
60  applySkin();
61
62  connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
63      SLOT(slotDoubleClicked(const QModelIndex&)));
64
65  connect(Config::Skin::active(), SIGNAL(frameChanged()), SLOT(applySkin()));
66}
67
68UserViewBase::~UserViewBase()
69{
70  // Empty
71}
72
73void UserViewBase::setColors(QColor back)
74{
75  if (!Config::ContactList::instance()->useSystemBackground())
76  {
77    QPalette pal = palette();
78
79    if (back.isValid())
80      pal.setColor(QPalette::Base, back);
81    else
82      pal.setColor(QPalette::Base, QColor("silver"));
83
84    setPalette(pal);
85  }
86}
87
88void UserViewBase::applySkin()
89{
90  setPalette(Config::Skin::active()->palette(gMainWindow));
91  setColors(Config::Skin::active()->backgroundColor);
92}
93
94void UserViewBase::mousePressEvent(QMouseEvent* event)
95{
96  QTreeView::mousePressEvent(event);
97
98  if (event->button() == Qt::LeftButton)
99  {
100    // Save position for later, needed by dragging and moving floaties
101    myMousePressPos = event->pos();
102  }
103  else if (event->button() == Qt::MidButton)
104  {
105    QModelIndex clickedItem = indexAt(event->pos());
106    if (clickedItem.isValid())
107    {
108      // Needed to distinguish double click origination
109      if (static_cast<ContactListModel::ItemType>
110          (clickedItem.data(ContactListModel::ItemTypeRole).toInt()) == ContactListModel::GroupItem)
111        midEvent = true;
112      emit doubleClicked(clickedItem);
113    }
114  }
115}
116
117void UserViewBase::mouseReleaseEvent(QMouseEvent* event)
118{
119  QTreeView::mouseReleaseEvent(event);
120
121  myMousePressPos.setX(0);
122  myMousePressPos.setY(0);
123}
124
125void UserViewBase::contextMenuEvent(QContextMenuEvent* event)
126{
127  QModelIndex clickedItem = indexAt(event->pos());
128  if (clickedItem.isValid())
129  {
130    setCurrentIndex(clickedItem);
131
132    popupMenu(viewport()->mapToGlobal(event->pos()), clickedItem);
133  }
134}
135
136void UserViewBase::popupMenu(QPoint point, QModelIndex item)
137{
138  ContactListModel::ItemType itemType = static_cast<ContactListModel::ItemType>
139    (item.data(ContactListModel::ItemTypeRole).toInt());
140
141  if (itemType == ContactListModel::UserItem)
142  {
143    QString id = item.data(ContactListModel::UserIdRole).toString();
144    unsigned long ppid = item.data(ContactListModel::PpidRole).toUInt();
145
146    LicqGui::instance()->userMenu()->popup(point, id, ppid);
147  }
148  else if (itemType == ContactListModel::GroupItem)
149  {
150    unsigned int id = item.data(ContactListModel::GroupIdRole).toUInt();
151
152    LicqGui::instance()->groupMenu()->popup(point, id);
153  }
154}
155
156void UserViewBase::dragEnterEvent(QDragEnterEvent* event)
157{
158  if (event->mimeData()->hasText() ||
159      event->mimeData()->hasUrls())
160    event->acceptProposedAction();
161}
162
163void UserViewBase::dropEvent(QDropEvent* event)
164{
165  // We ignore the event per default and then accept it if we
166  // get to the end of this function.
167  event->ignore();
168
169  QModelIndex dropIndex = indexAt(event->pos());
170  if (!dropIndex.isValid())
171    return;
172
173  ContactListModel::ItemType itemType = static_cast<ContactListModel::ItemType>
174    (dropIndex.data(ContactListModel::ItemTypeRole).toInt());
175
176  switch (itemType)
177  {
178    case ContactListModel::UserItem:
179    {
180      QString id = dropIndex.data(ContactListModel::UserIdRole).toString();
181      unsigned long ppid = dropIndex.data(ContactListModel::PpidRole).toUInt();
182
183      if (event->mimeData()->hasUrls())
184      {
185        QList<QUrl> urlList = event->mimeData()->urls();
186        QListIterator<QUrl> urlIter(urlList);
187        QString text;
188        QUrl firstUrl = urlIter.next();
189
190        if (!(text = firstUrl.toLocalFile()).isEmpty())
191        {
192          UserSendFileEvent* sendFile = dynamic_cast<UserSendFileEvent*>(
193              LicqGui::instance()->showEventDialog(FileEvent, id, ppid));
194          if (!sendFile)
195            return;
196
197          sendFile->setFile(text, QString::null);
198
199          // Add all the files
200          while (urlIter.hasNext())
201          {
202            if (!(text = urlIter.next().toLocalFile()).isEmpty())
203              sendFile->addFile(text);
204          }
205
206          sendFile->show();
207        }
208        else
209        {
210          UserSendUrlEvent* sendUrl = dynamic_cast<UserSendUrlEvent*>(
211              LicqGui::instance()->showEventDialog(UrlEvent, id, ppid));
212          if (!sendUrl)
213            return;
214
215          sendUrl->setUrl(firstUrl.toString(), QString::null);
216          sendUrl->show();
217        }
218      }
219      else if (event->mimeData()->hasText())
220      {
221        QString text = event->mimeData()->text();
222
223        unsigned long dropPpid = 0;
224        FOR_EACH_PROTO_PLUGIN_START(gLicqDaemon)
225        {
226          if (text.startsWith(PPIDSTRING((*_ppit)->PPID())))
227          {
228            dropPpid = (*_ppit)->PPID();
229            break;
230          }
231        }
232        FOR_EACH_PROTO_PLUGIN_END
233
234        if (dropPpid != 0 && text.length() > 4)
235        {
236          QString dropId = text.mid(4);
237          if (id == dropId && ppid == dropPpid)
238            return;
239
240          UserSendContactEvent* sendContact = dynamic_cast<UserSendContactEvent*>(
241              LicqGui::instance()->showEventDialog(ContactEvent, id, ppid));
242          if (!sendContact)
243            return;
244
245          sendContact->setContact(dropId, dropPpid);
246          sendContact->show();
247        }
248        else
249        {
250          UserSendMsgEvent* sendMsg = dynamic_cast<UserSendMsgEvent*>(
251              LicqGui::instance()->showEventDialog(MessageEvent, id, ppid));
252          if (!sendMsg)
253            return;
254
255          sendMsg->setText(text);
256          sendMsg->show();
257        }
258      }
259      break;
260    }
261    case ContactListModel::GroupItem:
262    {
263      unsigned short gid = dropIndex.data(ContactListModel::GroupIdRole).toUInt();
264
265      if (event->mimeData()->hasText() && event->mimeData()->text().length() > 4)
266      {
267        QString text = event->mimeData()->text();
268
269        unsigned long dropPpid = 0;
270        FOR_EACH_PROTO_PLUGIN_START(gLicqDaemon)
271        {
272          if (text.startsWith(PPIDSTRING((*_ppit)->PPID())))
273          {
274            dropPpid = (*_ppit)->PPID();
275            break;
276          }
277        }
278        FOR_EACH_PROTO_PLUGIN_END;
279
280        if (dropPpid == 0)
281          return;
282
283        QString dropId = text.mid(4);
284
285        if (!dropId.isEmpty())
286        {
287          // Should user be moved or just added to the new group?
288          bool moveUser;
289          if ((event->keyboardModifiers() & Qt::ShiftModifier) != 0)
290            moveUser = true;
291          else if ((event->keyboardModifiers() & Qt::ControlModifier) != 0)
292            moveUser = false;
293          else
294            moveUser = Config::ContactList::instance()->dragMovesUser();
295
296          gUserManager.SetUserInGroup(dropId.toLatin1(), dropPpid, GROUPS_USER, gid, true, moveUser);
297
298          // If we are moving user we now need to remove it from the old group.
299          // However, since the drop event doesn't contain the originating
300          // group, we don't know which group that is so we'll just have to
301          // remove the user from all other groups.
302          if (moveUser)
303          {
304            const ICQUser* u = gUserManager.FetchUser(dropId.toLatin1(), dropPpid, LOCK_R);
305            if (u != NULL)
306            {
307              UserGroupList userGroups = u->GetGroups();
308              gUserManager.DropUser(u);
309
310              UserGroupList::const_iterator i;
311              for (i = userGroups.begin(); i != userGroups.end(); ++i)
312                if (*i != gid)
313                  gUserManager.SetUserInGroup(dropId.toLatin1(), dropPpid, GROUPS_USER, *i, false, false);
314            }
315          }
316        }
317      }
318      else
319        return; // Not accepted
320      break;
321    }
322    default:
323      break;
324  }
325
326  event->acceptProposedAction();
327}
328
329void UserViewBase::dragMoveEvent(QDragMoveEvent* /* event */)
330{
331  // Do nothing, just overload the function so base class won't interfere
332}
333
334void UserViewBase::slotDoubleClicked(const QModelIndex& index)
335{
336  if (static_cast<ContactListModel::ItemType>
337      (index.data(ContactListModel::ItemTypeRole).toInt()) == ContactListModel::UserItem)
338  {
339    QString id = index.data(ContactListModel::UserIdRole).toString();
340    unsigned long ppid = index.data(ContactListModel::PpidRole).toUInt();
341
342    emit userDoubleClicked(id, ppid);
343  }
344  else
345  if (static_cast<ContactListModel::ItemType>
346      (index.data(ContactListModel::ItemTypeRole).toInt()) == ContactListModel::GroupItem &&
347      (index.column() != 0 || midEvent))
348  {
349    midEvent = false;
350    setExpanded(index, !isExpanded(index));
351  }
352}
353
354void UserViewBase::currentChanged(const QModelIndex &current, const QModelIndex &previous)
355{
356  // Workaround for annoying auto scrolling, see comment in scrollTo()
357  myAllowScrollTo = true;
358  QTreeView::currentChanged(current, previous);
359  myAllowScrollTo = false;
360}
361
362void UserViewBase::timerEvent(QTimerEvent* event)
363{
364  // Workaround for annoying auto scrolling, see comment in scrollTo()
365  myAllowScrollTo = true;
366  QTreeView::timerEvent(event);
367  myAllowScrollTo = false;
368}
369
370void UserViewBase::scrollTo(const QModelIndex& index, ScrollHint hint)
371{
372  // scrollTo is called from the following functions:
373  //   QAbstractItemView::setVerticalScrollMode
374  //   QAbstractItemView::timerEvent
375  //   QAbstractItemView::currentChanged
376  //   QAbstractItemViewPrivate::_q_layoutChanged
377  //
378  // Since layoutChanged is emitted by the sort proxy whenever anything item
379  // in the list is changed this causes the list to scroll back to current item
380  // which can be annoying when trying to scroll the list manually.
381  // Since we cannot override a private function this is a ugly workaround to
382  // block scrollTo as default but allow it for timerEvent and currentChanged
383  // instead. (setVerticalScrollMode isn't used so we don't care for that one.)
384  if (myAllowScrollTo)
385    QTreeView::scrollTo(index, hint);
386}
Note: See TracBrowser for help on using the browser.