navigationwidget.cc 4.53 KB
Newer Older
1
2
#include "radixwidgets/navigationwidget.hh"
#include "radixwidgets/navigationitem.hh"
3
4
5
#include "radixwidgets/navigationmodel.hh"

#include "radixbug/bug.hh"
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#include <QClipboard>
#include <QEvent>
#include <QFileDialog>
#include <QFileInfo>
#include <QHeaderView>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMessageBox>
#include <QShortcut>
#include <QStandardItemModel>
#include <QTextDocument>
#include <QToolTip>
#include <QTreeView>
#include <QVBoxLayout>
#include <QtDebug>

namespace radix
{
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class NavigationItemSortFilterProxyModel::PImpl
{
 public:
  QHash<QModelIndex, bool> seen;
};

NavigationItemSortFilterProxyModel::NavigationItemSortFilterProxyModel(
    QObject* parent)
    : QSortFilterProxyModel(parent)
    , p(new PImpl(), [](PImpl* impl) { delete impl; })
{
}

bool NavigationItemSortFilterProxyModel::accepts(const QModelIndex& index) const
{
  const QString& text  = index.data().toString();
  const QRegExp& regex = filterRegExp();

  bool accept = text.contains(regex);

  for (int i = 0, ie = sourceModel()->rowCount(index); i < ie; i++)
  {
    if (accepts(sourceModel()->index(i, 0, index)))
    {
      accept = true;
      break;
    }
  }

  p->seen[index] = accept;
  return accept;
}

void NavigationItemSortFilterProxyModel::clearCache() { p->seen.clear(); }

bool NavigationItemSortFilterProxyModel::filterAcceptsRow(
    int source_row, const QModelIndex& source_parent) const
{
  const QModelIndex& index = sourceModel()->index(source_row, 0, source_parent);

  if (p->seen.contains(index))
  {
    return p->seen.value(index);
  }

  return accepts(index);
}

75
76
77
78
class NavigationWidget::PImpl
{
 public:
  QLineEdit* filter;
79
  NavigationModel* model;
80
  NavigationItemSortFilterProxyModel* proxy;
81
  QTreeView* view;
82
83
84
85
86
87
88
89
90
91
};

NavigationWidget::NavigationWidget(QWidget* parent)
    : QWidget(parent)
    , p(new PImpl(), [](PImpl* impl) { delete impl; })
{
  initMembers();
  initLayout();
}

92
93
94
95
96
97
98
99
100
101
NavigationModel* NavigationWidget::navigationModel() { return p->model; }

void NavigationWidget::contextMenuRequested(QPoint point)
{
  radix_tagged_line("contextMenuRequested()");
  QModelIndex index = p->view->indexAt(point);
  QMenu m;
  m.exec(p->view->viewport()->mapToGlobal(point));
}

102
103
104
105
106
void NavigationWidget::initLayout()
{
  auto vlayout = new QVBoxLayout(this);

  vlayout->addWidget(p->filter);
107
  vlayout->addWidget(p->view);
108
109
110
111
112
}

void NavigationWidget::initMembers()
{
  // allocate
113
114
  p->filter = new QLineEdit();
  p->model  = new NavigationModel();
115
  p->proxy  = new NavigationItemSortFilterProxyModel();
116
  p->view   = new QTreeView();
117
118
119
  // init properties
  p->filter->setPlaceholderText("Filter");

120
121
122
  p->view->installEventFilter(this);
  p->view->setContextMenuPolicy(Qt::CustomContextMenu);
  p->view->setEditTriggers(QAbstractItemView::NoEditTriggers);
123
  p->view->setModel(p->proxy);
124
125
126
  p->view->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
  p->view->header()->setStretchLastSection(false);
  p->view->header()->setVisible(false);
127

128
129
  p->proxy->setSourceModel(p->model);

130
  // shortcuts
131
132
133
  auto activateEnter  = new QShortcut(p->view);
  auto activateReturn = new QShortcut(p->view);
  auto collapseBranch = new QShortcut(p->view);
134
135
136
137
138
139
140
141
142

  activateEnter->setContext(Qt::WidgetShortcut);
  activateEnter->setKey(Qt::Key_Enter);

  activateReturn->setContext(Qt::WidgetShortcut);
  activateReturn->setKey(Qt::Key_Return);

  collapseBranch->setContext(Qt::WidgetShortcut);
  collapseBranch->setKey(Qt::Key_Left);
143
144
145
146
147
148
149

  //
  // connect signals/slots
  connect(p->filter, SIGNAL(textChanged(QString)), this,
          SLOT(filterModel(QString)));
  connect(p->view, SIGNAL(doubleClicked(QModelIndex)), this,
          SLOT(itemDoubleClicked(QModelIndex)));
150
151
  connect(p->view, SIGNAL(customContextMenuRequested(QPoint)), this,
          SLOT(contextMenuRequested(QPoint)));
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
}
void NavigationWidget::filterModel(const QString& pattern)
{
  // regex used to filter the model
  QRegExp regex(pattern, Qt::CaseInsensitive, QRegExp::RegExp2);

  // update the model
  p->proxy->clearCache();
  p->proxy->setFilterRegExp(regex);

  // update the tree
  if (pattern.isEmpty())
  {
    p->view->collapseAll();

    for (int i = 0, ie = p->model->rowCount(); i < ie; i++)
    {
      p->view->expand(p->proxy->mapFromSource(p->model->index(i, 0)));
    }
  }
  else
  {
    p->view->expandAll();
  }
}

void NavigationWidget::itemDoubleClicked(QModelIndex index)
{
  radix_tagged_line("itemDoubleClicked()");
  const auto& mapped = p->proxy->mapToSource(index);
  radix_tagged_line("\t[" << mapped.row() << "," << mapped.column() << "]");
183
184
}
}  // namespace radix