dockBuddiesList.cpp
1 //------------------------------------------------------------------------------
2 // dockBuddiesList.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
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.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2009 "Blzut3" <admin@maniacsvault.net>
22 //------------------------------------------------------------------------------
23 #include "dockBuddiesList.h"
24 #include "ui_addBuddyDlg.h"
25 #include "ui_dockBuddiesList.h"
26 #include "configuration/doomseekerconfig.h"
27 #include "serverapi/mastermanager.h"
28 #include "serverapi/playerslist.h"
29 #include "serverapi/server.h"
30 #include "patternlist.h"
31 #include "strings.h"
32 #include <QMenu>
33 #include <QMessageBox>
34 #include <QRegExp>
35 #include <QStandardItemModel>
36 
37 class BuddyLocationInfo
38 {
39 public:
40  BuddyLocationInfo(const Player &buddy, ServerPtr location);
41  ~BuddyLocationInfo();
42 
43  const Player &buddy() const;
44  ServerPtr location() const;
45 
46  bool operator==(const BuddyLocationInfo &other) const;
47 
48 private:
50 };
51 
52 // [BL] This was moved earlier in the file in order to prevent double specialization
53 // with some compilers
54 DClass<BuddyLocationInfo>
55 {
56 public:
57  Player buddy;
58  ServerPtr server;
59 };
60 
61 DPointered(BuddyLocationInfo)
62 
63 DClass<DockBuddiesList> : public Ui::DockBuddiesList
64 {
65 public:
66  QList<BuddyLocationInfo> buddies;
67  QStandardItemModel *buddiesTableModel;
68  PatternList pBuddies;
69 };
70 
71 DPointered(DockBuddiesList)
72 
73 DockBuddiesList::DockBuddiesList(QWidget *parent)
74 : QDockWidget(parent), masterClient(NULL), save(false)
75 {
76  d->setupUi(this);
77  this->toggleViewAction()->setIcon(QIcon(":/icons/buddies.png"));
78 
79  // Set up the model
80  d->buddiesTableModel = new QStandardItemModel();
81 
82  // Not working yet.
83  QStringList columns;
84  columns << tr("ID");
85  columns << tr("Buddy");
86  columns << tr("Location");
87  d->buddiesTableModel->setHorizontalHeaderLabels(columns);
88 
89  d->buddiesTable->setModel(d->buddiesTableModel);
90  d->buddiesTable->setColumnHidden(0, true); // Hide the ID
91 
92  // Read config
93  const QVector<BuddyInfo>& buddies = gConfig.doomseeker.buddiesList;
94 
95  foreach (const BuddyInfo& buddy, buddies)
96  {
97  d->pBuddies << buddy.pattern;
98  d->patternsList->addItem(buddy.pattern.pattern());
99  }
100 
101  connect(d->addButton, SIGNAL( clicked() ), this, SLOT( addBuddy() ));
102  connect(d->buddiesTable, SIGNAL( doubleClicked(const QModelIndex &) ), this, SLOT( followBuddy(const QModelIndex &) ));
103  connect(d->deleteButton, SIGNAL( clicked() ), this, SLOT( deleteBuddy() ));
104  connect(d->patternsList, SIGNAL( customContextMenuRequested(const QPoint &) ), this, SLOT( patternsListContextMenu(const QPoint &) ));
105 }
106 
107 DockBuddiesList::~DockBuddiesList()
108 {
109  // See if we made any modification since modifying the setting will cause a
110  // write cycle.
111  if(!save)
112  return;
113 
114  gConfig.doomseeker.buddiesList.clear();
115  foreach (QRegExp pattern, d->pBuddies)
116  {
117  BuddyInfo buddyInfo;
118 
119  buddyInfo.pattern = pattern;
120  buddyInfo.patternType = pattern.patternSyntax() == QRegExp::Wildcard ? BuddyInfo::PT_BASIC : BuddyInfo::PT_ADVANCED;
121 
122  gConfig.doomseeker.buddiesList << buddyInfo;
123  }
124 }
125 
126 void DockBuddiesList::addBuddy()
127 {
128  AddBuddyDlg dlg;
129  int result = dlg.exec();
130  if(result != QDialog::Accepted)
131  return;
132 
133  QRegExp pattern(dlg.pattern(), Qt::CaseInsensitive, dlg.patternType() == BuddyInfo::PT_BASIC ? QRegExp::Wildcard : QRegExp::RegExp);
134 
135  if(pattern.isValid())
136  {
137  d->pBuddies << pattern;
138  scan(masterClient);
139  }
140 
141  d->patternsList->addItem(dlg.pattern());
142 
143  save = true;
144 }
145 
146 void DockBuddiesList::deleteBuddy()
147 {
148  // Do nothing if nothing is selected.
149  if(d->patternsList->selectionModel()->selectedIndexes().size() <= 0)
150  return;
151 
152  if(QMessageBox::warning(this, tr("Delete Buddy"), tr("Are you sure you want to delete this pattern?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)
153  != QMessageBox::Yes)
154  return;
155 
156  QModelIndexList selection = d->patternsList->selectionModel()->selectedIndexes();
157  // We have to remove the bottom most row until they are all gone.
158  while(selection.size() > 0)
159  {
160  int largestIndex = 0;
161  for(int i = 1;i < selection.size();i++)
162  {
163  if(selection[i].row() > selection[largestIndex].row())
164  largestIndex = i;
165  }
166 
167  d->pBuddies.removeAt(selection[largestIndex].row());
168  delete d->patternsList->item(selection[largestIndex].row());
169  selection.removeAt(largestIndex); // remove index
170  }
171 
172  scan(masterClient);
173 
174  save = true;
175 }
176 
177 void DockBuddiesList::followBuddy(const QModelIndex &index)
178 {
179  // Folow the buddy into the server.
180  QString error;
181 
182  ServerPtr server = d->buddies[d->buddiesTableModel->item(index.row(), BLCID_ID)->data().toInt()].location();
183  emit joinServer(server);
184 }
185 
186 bool DockBuddiesList::hasBuddy(const ServerPtr &server)
187 {
188  foreach (const BuddyLocationInfo &location, d->buddies)
189  {
190  if (location.location() == server)
191  {
192  return true;
193  }
194  }
195  return false;
196 }
197 
198 void DockBuddiesList::patternsListContextMenu(const QPoint &pos) const
199 {
200  // First lets get the selection since that will determine the menu.
201  QModelIndexList selection = d->patternsList->selectionModel()->selectedIndexes();
202 
203  QMenu context;
204 
205  // Always have the add function.
206  QAction *addAction = context.addAction(tr("Add"));
207  connect(addAction, SIGNAL( triggered() ), this, SLOT( addBuddy() ));
208 
209  // if anything is selected allow the user to delete them.
210  if(selection.size() > 0)
211  {
212  QAction *deleteAction = context.addAction(tr("Delete"));
213  connect(deleteAction, SIGNAL( triggered() ), this, SLOT( deleteBuddy() ));
214  }
215 
216  // Finally show our menu.
217  context.exec(d->patternsList->mapToGlobal(pos));
218 }
219 
220 void DockBuddiesList::scan(const MasterManager *master)
221 {
222  if(master == NULL && masterClient == NULL)
223  return;
224  else if(master != masterClient && master != NULL)
225  { // If the master is new
226  masterClient = master;
227  }
228 
229  d->buddies.clear(); //empty list
230  foreach(ServerPtr server, masterClient->allServers())
231  {
232  if (!server->isKnown())
233  {
234  continue;
235  }
236  for(int i = 0; i < server->players().numClients(); ++i)
237  {
238  const Player player = server->player(i);
239  if (d->pBuddies.isExactMatchAny(player.nameColorTagsStripped()))
240  {
241  BuddyLocationInfo candidate(player, server);
242  if (!d->buddies.contains(candidate))
243  {
244  d->buddies << BuddyLocationInfo(player, server);
245  }
246  }
247  }
248  }
249 
250  // Populate list
251  d->buddiesTableModel->removeRows(0, d->buddiesTableModel->rowCount());
252  for(int i = 0;i < d->buddies.size();i++)
253  {
254  const BuddyLocationInfo &info = d->buddies[i];
255  QList<QStandardItem *> columns;
256 
257  for(int j = 0;j < HOW_MANY_BUDDIESLIST_COLUMNS;j++)
258  {
259  switch(j)
260  {
261  case BLCID_ID:
262  {
263  QStandardItem *item = new QStandardItem();
264  item->setData(i);
265  columns << item;
266  break;
267  }
268  case BLCID_BUDDY:
269  columns << new QStandardItem(info.buddy().nameColorTagsStripped());
270  break;
271  case BLCID_LOCATION:
272  columns << new QStandardItem(info.location()->name());
273  break;
274  default:
275  columns << new QStandardItem();
276  break;
277  }
278  }
279 
280  d->buddiesTableModel->appendRow(columns);
281  }
282 
283  // Fits rows to contents
284  d->buddiesTable->resizeRowsToContents();
285  emit scanCompleted();
286 }
287 
289 
290 DClass<AddBuddyDlg> : public Ui::AddBuddyDlg
291 {
292 };
293 
294 DPointered(AddBuddyDlg)
295 
296 AddBuddyDlg::AddBuddyDlg(QWidget *parent) : QDialog(parent)
297 {
298  d->setupUi(this);
299 
300  connect(d->buttonBox, SIGNAL( clicked(QAbstractButton *) ), this, SLOT( buttonBoxClicked(QAbstractButton *) ));
301 }
302 
303 AddBuddyDlg::~AddBuddyDlg()
304 {
305 }
306 
307 void AddBuddyDlg::buttonBoxClicked(QAbstractButton *button)
308 {
309  if(d->buttonBox->standardButton(button) == QDialogButtonBox::Ok)
310  {
311  if(patternType() == BuddyInfo::PT_ADVANCED)
312  {
313  QRegExp test(pattern());
314  if(!test.isValid())
315  {
316  QMessageBox::information(this, tr("Invalid Pattern"), tr("The pattern you have specified is not a valid regular expression."));
317  return;
318  }
319  }
320  accept();
321  }
322  else
323  reject();
324 }
325 
326 QString AddBuddyDlg::pattern() const
327 {
328  return d->patternBox->text();
329 }
330 
331 BuddyInfo::PatternType AddBuddyDlg::patternType() const
332 {
333  return d->basicPattern->isChecked() ? BuddyInfo::PT_BASIC : BuddyInfo::PT_ADVANCED;
334 }
335 
337 
338 BuddyLocationInfo::BuddyLocationInfo(const Player &buddy, ServerPtr location)
339 {
340  d->buddy = buddy;
341  d->server = location;
342 }
343 
344 BuddyLocationInfo::~BuddyLocationInfo()
345 {
346 }
347 
348 const Player &BuddyLocationInfo::buddy() const
349 {
350  return d->buddy;
351 }
352 
353 ServerPtr BuddyLocationInfo::location() const
354 {
355  return d->server;
356 }
357 
358 bool BuddyLocationInfo::operator==(const BuddyLocationInfo &other) const
359 {
360  return d->buddy == other.d->buddy
361  && d->server->address() == other.d->server->address()
362  && d->server->port() == other.d->server->port()
363  && d->server->plugin() == other.d->server->plugin();
364 }
QString nameColorTagsStripped() const
Definition: player.cpp:94
Data structure that holds information about players in a server.
Definition: player.h:37
Manager class for a number of MasterClient instances.
Definition: mastermanager.h:38