serverlistview.cpp
1 //------------------------------------------------------------------------------
2 // serverlistview.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; 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 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 
24 #include "gui/widgets/serverlistview.h"
25 
26 #include "configuration/doomseekerconfig.h"
27 #include "gui/models/serverlistcolumn.h"
28 #include "refresher/refresher.h"
29 #include <QDebug>
30 #include <QHeaderView>
31 #include <QItemDelegate>
32 #include <QMouseEvent>
33 #include <QPainter>
34 #include <QSortFilterProxyModel>
35 #include <QTextDocument>
36 
41 class CustomItemDelegate : public QItemDelegate
42 {
43 public:
44  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
45  {
46  // First we're going to check for our new right aligned image
47  // option.
48  bool rightAligned = false;
49  QStyleOptionViewItem opt = option;
50 
51  QVariant userRole = index.data(Qt::UserRole);
52  if (userRole.isValid() && userRole.type() == QVariant::Int && userRole.toInt() == USERROLE_RIGHTALIGNDECORATION)
53  {
54  opt.decorationAlignment = Qt::AlignRight | Qt::AlignVCenter;
55  rightAligned = true;
56  }
57 
58  // Hide the focus rectangle in picture cells.
59  if (ServerListColumns::isPictureColumn(index.column()))
60  opt.state &= ~QStyle::State_HasFocus;
61 
62  // Now we draw the table as usual.
63  QItemDelegate::paint(painter, opt, index);
64 
65  // If the row is selected and we are using the right aligned feature
66  // we must now redraw the decoration. The rectangle that was used
67  // in the previous function will cause the image to clip.
68  //
69  // The only other way I can think of for fixing that problem would
70  // be to completely rewrite this class, which I really don't want
71  // to do.
72  if (rightAligned && (opt.state & QStyle::State_Selected))
73  {
74  QVariant decorationRole = index.data(Qt::DecorationRole);
75  if (decorationRole.isValid())
76  {
77  painter->save();
78  painter->setClipRect(opt.rect);
79 
80  QPixmap pixmap = decoration(opt, decorationRole);
81  drawDecoration(painter, opt, opt.rect, pixmap);
82 
83  painter->restore();
84  }
85  }
86  }
87 
88 protected:
89  void drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const override
90  {
91  if (pixmap.isNull() || !rect.isValid())
92  return;
93 
94  if (option.decorationAlignment == (Qt::AlignRight | Qt::AlignVCenter)) // Special handling.
95  {
96  QPoint p = QStyle::alignedRect(option.direction, option.decorationAlignment, pixmap.size(), option.rect).topLeft();
97  painter->drawPixmap(p, pixmap);
98  }
99  else
100  QItemDelegate::drawDecoration(painter, option, rect, pixmap);
101  }
102 };
103 
105 
106 ServerListView::ServerListView(QWidget *parent) : QTableView(parent)
107 {
108  // Prevent the fat rows problem.
109  verticalHeader()->setDefaultSectionSize(fontMetrics().height() + 6);
110  verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
111  setShowGrid(gConfig.doomseeker.bDrawGridInServerTable);
112 
113  setItemDelegate(new CustomItemDelegate());
114 }
115 
116 void ServerListView::mouseReleaseEvent(QMouseEvent *event)
117 {
118  QModelIndex index = indexAt(event->pos());
119  switch (event->button())
120  {
121  case Qt::MidButton:
122  if (index.isValid())
123  emit middleMouseClicked(index, event->pos());
124  break;
125 
126  case Qt::RightButton:
127  if (index.isValid())
128  emit rightMouseClicked(index, event->pos());
129  break;
130 
131  default:
132  QTableView::mouseReleaseEvent(event);
133  break;
134  }
135 }
136 
137 void ServerListView::mouseDoubleClickEvent(QMouseEvent *event)
138 {
139  if (event->button() != Qt::LeftButton)
140  QTableView::mouseDoubleClickEvent(event);
141  else
142  {
143  QModelIndex index = indexAt(event->pos());
144  if (index.isValid())
145  emit leftMouseDoubleClicked(index, event->pos());
146  }
147 }
148 
149 void ServerListView::setupTableProperties()
150 {
151  setIconSize(QSize(26, 15));
152  // Some flags that can't be set from the Designer.
153  horizontalHeader()->setSortIndicatorShown(true);
154  horizontalHeader()->setHighlightSections(false);
155 
156  setMouseTracking(true);
157 
158  setupTableColumnWidths();
159 }
160 
161 void ServerListView::setupTableColumnWidths()
162 {
163  const ServerListColumn *columns = ServerListColumns::columns;
164 
165  // Initialize the defaults.
166  for (int colIdx = 0; colIdx < ServerListColumnId::NUM_SERVERLIST_COLUMNS; ++colIdx)
167  setColumnWidth(colIdx, columns[colIdx].width);
168 
169  // Reload state from config, potentially overriding the defaults.
170  QString &headerState = gConfig.doomseeker.serverListColumnState;
171  if (!headerState.isEmpty())
172  horizontalHeader()->restoreState(QByteArray::fromBase64(headerState.toUtf8()));
173 
174  // Enforce certain settings on columns, regardless of the state loaded from the config.
175  int smallestWidth = horizontalHeader()->minimumSectionSize();
176  for (int colIdx = 0; colIdx < ServerListColumnId::NUM_SERVERLIST_COLUMNS; ++colIdx)
177  {
178  if (!columns[colIdx].bResizable && columns[colIdx].width < smallestWidth)
179  {
180  smallestWidth = columns[colIdx].width;
181  horizontalHeader()->setMinimumSectionSize(smallestWidth);
182  }
183  QHeaderView::ResizeMode resizeMode = columns[colIdx].bResizable ?
184  QHeaderView::Interactive : QHeaderView::ResizeToContents;
185  horizontalHeader()->setSectionResizeMode(colIdx, resizeMode);
186  }
187 
188  // General settings.
189  horizontalHeader()->setSectionsMovable(true);
190 }