6#include <QtDesigner/abstractformeditor.h>
7#include <QtDesigner/abstractwidgetdatabase.h>
11#include <QtGui/qicon.h>
12#include <QtGui/qvalidator.h>
13#include <QtWidgets/qlistview.h>
14#include <QtWidgets/qlineedit.h>
15#include <QtWidgets/qitemdelegate.h>
16#include <QtCore/qsortfilterproxymodel.h>
18#include <QtCore/qabstractitemmodel.h>
19#include <QtCore/qiodevice.h>
20#include <QtCore/qlist.h>
21#include <QtCore/qtextstream.h>
22#include <QtCore/qregularexpression.h>
26using namespace Qt::StringLiterals;
38 QTextStream stream(&result, QIODevice::WriteOnly);
47 result.setContent(xml);
58 const QString &filter,
71 const QString &filterIn,
72 const QIcon &i,
bool e) :
81
82
90 int rowCount(
const QModelIndex &parent = QModelIndex())
const override;
91 bool setData(
const QModelIndex & index,
const QVariant & value,
int role =
Qt::
EditRole)
override;
93 bool removeRows(
int row,
int count,
const QModelIndex &parent = QModelIndex())
override;
99 void addWidget(
const QDesignerWidgetBoxInterface::Widget &widget,
const QIcon &icon,
bool editable);
110 QDesignerFormEditorInterface *m_core;
111 QList<WidgetBoxCategoryEntry> m_items;
112 QListView::ViewMode m_viewMode;
129 if (m_viewMode == vm)
131 const bool empty = m_items.isEmpty();
141 for (qsizetype i = 0, count = m_items.size(); i < count; ++i)
142 if (m_items.at(i).widget.name() == name)
149 QDesignerWidgetBoxInterface::Category rc;
150 for (
const auto &c : m_items)
151 rc.addWidget(c.widget);
159 bool changed =
false;
160 for (
auto it = m_items.begin(); it != m_items.end(); )
161 if (it->widget.type() == QDesignerWidgetBoxInterface::Widget::Custom) {
164 it = m_items.erase(it);
176 static const QRegularExpression classNameRegExp(QStringLiteral(
"<widget +class *= *\"([^\"]+)\""));
177 Q_ASSERT(classNameRegExp.isValid());
178 const auto match = classNameRegExp.match(widget.domXml());
179 const QString className = match.hasMatch() ? match.captured(1) : QString{};
182 QString filter = widget.name();
183 if (!className.isEmpty() && !filter.contains(
"Layout"_L1) && !filter.contains(className))
187 const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase();
188 int dbIndex = className.isEmpty() ? -1 : db->indexOfClassName(className);
190 dbIndex = db->indexOfClassName(widget.name());
192 const QDesignerWidgetDataBaseItemInterface *dbItem = db->item(dbIndex);
193 const QString toolTip = dbItem->toolTip();
194 if (!toolTip.isEmpty())
195 item.toolTip = toolTip;
196 const QString whatsThis = dbItem->whatsThis();
197 if (!whatsThis.isEmpty())
198 item.whatsThis = whatsThis;
201 const int row = m_items.size();
202 beginInsertRows(QModelIndex(), row, row);
203 m_items.push_back(item);
209 const int row = index.row();
210 if (row < 0 || row >= m_items.size())
215 case Qt::DisplayRole:
217 return QVariant(m_viewMode == QListView::ListMode ? item.widget.name() : QString());
218 case Qt::DecorationRole:
219 return QVariant(item.icon);
221 return QVariant(item.widget.name());
222 case Qt::ToolTipRole: {
223 if (m_viewMode == QListView::ListMode)
224 return QVariant(item.toolTip);
226 QString tt = item.widget.name();
227 if (!item.toolTip.isEmpty())
228 tt += u'\n' + item.toolTip;
232 case Qt::WhatsThisRole:
233 return QVariant(item.whatsThis);
242 const int row = index.row();
243 if (role != Qt::EditRole || row < 0 || row >= m_items.size()
244 || value.metaType().id() != QMetaType::QString) {
249 const QString newName = value.toString();
250 item.widget.setName(newName);
252 const QDomDocument doc = stringToDom(WidgetBoxCategoryListView::widgetDomXml(item.widget));
253 QDomElement widget_elt = doc.firstChildElement(widgetElementC);
254 if (!widget_elt.isNull()) {
255 widget_elt.setAttribute(nameAttributeC, newName);
256 item.widget.setDomXml(domToString(widget_elt));
258 emit dataChanged(index, index);
264 Qt::ItemFlags rc = Qt::ItemIsEnabled;
265 const int row = index.row();
266 if (row >= 0 && row < m_items.size())
267 if (m_items.at(row).editable) {
268 rc |= Qt::ItemIsSelectable;
270 if (m_viewMode == QListView::ListMode)
271 rc |= Qt::ItemIsEditable;
278 return m_items.size();
283 if (row < 0 || count < 1)
285 const int size = m_items.size();
286 const int last = row + count - 1;
287 if (row >= size || last >= size)
289 beginRemoveRows(parent, row, last);
290 for (
int r = last; r >= row; r--)
298 return widgetAt(index.row());
303 if (row < 0 || row >= m_items.size())
304 return QDesignerWidgetBoxInterface::Widget();
305 return m_items.at(row).widget;
315 const QStyleOptionViewItem &option,
316 const QModelIndex &index)
const override;
320 const QStyleOptionViewItem &option,
321 const QModelIndex &index)
const
323 QWidget *result = QItemDelegate::createEditor(parent, option, index);
324 if (QLineEdit *line_edit = qobject_cast<QLineEdit*>(result)) {
325 static const QRegularExpression re(u"^[_a-zA-Z][_a-zA-Z0-9]*$"_s);
326 Q_ASSERT(re.isValid());
327 line_edit->setValidator(
new QRegularExpressionValidator(re, line_edit));
339 setFocusPolicy(Qt::NoFocus);
340 setFrameShape(QFrame::NoFrame);
341 setIconSize(QSize(22, 22));
343 setTextElideMode(Qt::ElideMiddle);
344 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
345 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
346 setResizeMode(QListView::Adjust);
347 setUniformItemSizes(
true);
349 setItemDelegate(
new WidgetBoxCategoryEntryDelegate(
this));
351 connect(
this, &QListView::pressed,
this,
352 &WidgetBoxCategoryListView::slotPressed);
353 setEditTriggers(QAbstractItemView::AnyKeyPressed);
355 m_proxyModel->setSourceModel(m_model);
357 setModel(m_proxyModel);
358 connect(m_model, &QAbstractItemModel::dataChanged,
359 this, &WidgetBoxCategoryListView::scratchPadChanged);
364 QListView::setViewMode(vm);
365 m_model->setViewMode(vm);
370 const QModelIndex index = am == FilteredAccess ?
371 m_proxyModel->index(row, 0) :
372 m_proxyModel->mapFromSource(m_model->index(row, 0));
375 setCurrentIndex(index);
380 const QDesignerWidgetBoxInterface::Widget wgt = m_model->widgetAt(m_proxyModel->mapToSource(index));
383 emit widgetBoxPressed(wgt.name(), widgetDomXml(wgt), QCursor::pos());
388 const QModelIndex index = currentIndex();
389 if (!index.isValid() || !m_proxyModel->removeRow(index.row()))
394 if (m_model->rowCount()) {
397 emit lastItemRemoved();
403 const QModelIndex index = currentIndex();
410 return am == FilteredAccess ? m_proxyModel->rowCount() : m_model->rowCount();
415 const QModelIndex filterIndex = m_proxyModel->index(filterRow, 0);
416 return m_proxyModel->mapToSource(filterIndex).row();
421 const QModelIndex unfilteredIndex = am == FilteredAccess ? m_proxyModel->mapToSource(index) : index;
422 return m_model->widgetAt(unfilteredIndex);
427 return m_model->widgetAt(am == UnfilteredAccess ? row : mapRowToSource(row));
432 m_model->removeRow(am == UnfilteredAccess ? row : mapRowToSource(row));
437 return m_model->indexOfWidget(name) != -1;
442 m_model->addWidget(widget, icon, editable);
447 QString domXml = widget.domXml();
449 if (domXml.isEmpty())
450 domXml = uiOpeningTagC +
"<widget class=\""_L1 + widget.name() +
"\"/>"_L1 + uiClosingTagC;
456 m_proxyModel->setFilterFixedString(needle);
457 m_proxyModel->setFilterCaseSensitivity(caseSensitivity);
462 return m_model->category();
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Returns the widget used to edit the item specified by index for editing.
WidgetBoxCategoryEntryDelegate(QWidget *parent=nullptr)
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
QDesignerWidgetBoxInterface::Widget widget
WidgetBoxCategoryEntry()=default
WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, const QString &filter, const QIcon &icon, bool editable)