7#include <QtDesigner/abstractformeditor.h>
8#include <QtDesigner/abstractwidgetdatabase.h>
10#include <QtXml/qdom.h>
12#include <QtGui/qicon.h>
13#include <QtGui/qvalidator.h>
14#include <QtWidgets/qlistview.h>
15#include <QtWidgets/qlineedit.h>
16#include <QtWidgets/qstyleditemdelegate.h>
17#include <QtCore/qsortfilterproxymodel.h>
19#include <QtCore/qabstractitemmodel.h>
20#include <QtCore/qiodevice.h>
21#include <QtCore/qlist.h>
22#include <QtCore/qtextstream.h>
23#include <QtCore/qregularexpression.h>
27using namespace Qt::StringLiterals;
39 QTextStream stream(&result, QIODevice::WriteOnly);
48 result.setContent(xml);
59 const QString &filter,
72 const QString &filterIn,
73 const QIcon &i,
bool e) :
82
83
91 int rowCount(
const QModelIndex &parent = QModelIndex())
const override;
92 bool setData(
const QModelIndex & index,
const QVariant & value,
int role =
Qt::
EditRole)
override;
94 bool removeRows(
int row,
int count,
const QModelIndex &parent = QModelIndex())
override;
100 void addWidget(
const QDesignerWidgetBoxInterface::Widget &widget,
const QIcon &icon,
bool editable);
111 QDesignerFormEditorInterface *m_core;
112 QList<WidgetBoxCategoryEntry> m_items;
113 QListView::ViewMode m_viewMode;
130 if (m_viewMode == vm)
132 const bool empty = m_items.isEmpty();
142 for (qsizetype i = 0, count = m_items.size(); i < count; ++i)
143 if (m_items.at(i).widget.name() == name)
150 QDesignerWidgetBoxInterface::Category rc;
151 for (
const auto &c : m_items)
152 rc.addWidget(c.widget);
160 bool changed =
false;
161 for (
auto it = m_items.begin(); it != m_items.end(); )
162 if (it->widget.type() == QDesignerWidgetBoxInterface::Widget::Custom) {
165 it = m_items.erase(it);
177 static const QRegularExpression classNameRegExp(QStringLiteral(
"<widget +class *= *\"([^\"]+)\""));
178 Q_ASSERT(classNameRegExp.isValid());
179 const auto match = classNameRegExp.match(widget.domXml());
180 const QString className = match.hasMatch() ? match.captured(1) : QString{};
183 QString filter = widget.name();
184 if (!className.isEmpty() && !filter.contains(
"Layout"_L1) && !filter.contains(className))
188 const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase();
189 int dbIndex = className.isEmpty() ? -1 : db->indexOfClassName(className);
191 dbIndex = db->indexOfClassName(widget.name());
193 const QDesignerWidgetDataBaseItemInterface *dbItem = db->item(dbIndex);
194 const QString toolTip = dbItem->toolTip();
195 if (!toolTip.isEmpty())
196 item.toolTip = toolTip;
197 const QString whatsThis = dbItem->whatsThis();
198 if (!whatsThis.isEmpty())
199 item.whatsThis = whatsThis;
202 const int row = m_items.size();
203 beginInsertRows(QModelIndex(), row, row);
204 m_items.push_back(item);
210 const int row = index.row();
211 if (row < 0 || row >= m_items.size())
216 case Qt::DisplayRole:
218 return QVariant(m_viewMode == QListView::ListMode ? item.widget.name() : QString());
219 case Qt::DecorationRole:
220 return QVariant(item.icon);
222 return QVariant(item.widget.name());
223 case Qt::ToolTipRole: {
224 if (m_viewMode == QListView::ListMode)
225 return QVariant(item.toolTip);
227 QString tt = item.widget.name();
228 if (!item.toolTip.isEmpty())
229 tt += u'\n' + item.toolTip;
233 case Qt::WhatsThisRole:
234 return QVariant(item.whatsThis);
243 const int row = index.row();
244 if (role != Qt::EditRole || row < 0 || row >= m_items.size()
245 || value.metaType().id() != QMetaType::QString) {
250 const QString newName = value.toString();
251 item.widget.setName(newName);
253 const QDomDocument doc = stringToDom(WidgetBoxCategoryListView::widgetDomXml(item.widget));
254 QDomElement widget_elt = doc.firstChildElement(widgetElementC);
255 if (!widget_elt.isNull()) {
256 widget_elt.setAttribute(nameAttributeC, newName);
257 item.widget.setDomXml(domToString(widget_elt));
259 emit dataChanged(index, index);
265 Qt::ItemFlags rc = Qt::ItemIsEnabled;
266 const int row = index.row();
267 if (row >= 0 && row < m_items.size())
268 if (m_items.at(row).editable) {
269 rc |= Qt::ItemIsSelectable;
271 if (m_viewMode == QListView::ListMode)
272 rc |= Qt::ItemIsEditable;
279 return m_items.size();
284 if (row < 0 || count < 1)
286 const int size = m_items.size();
287 const int last = row + count - 1;
288 if (row >= size || last >= size)
290 beginRemoveRows(parent, row, last);
291 for (
int r = last; r >= row; r--)
299 return widgetAt(index.row());
304 if (row < 0 || row >= m_items.size())
305 return QDesignerWidgetBoxInterface::Widget();
306 return m_items.at(row).widget;
316 const QStyleOptionViewItem &option,
317 const QModelIndex &index)
const override;
321 const QStyleOptionViewItem &option,
322 const QModelIndex &index)
const
324 QWidget *result = QStyledItemDelegate::createEditor(parent, option, index);
325 if (QLineEdit *line_edit = qobject_cast<QLineEdit*>(result)) {
326 static const QRegularExpression re(u"^[_a-zA-Z][_a-zA-Z0-9]*$"_s);
327 Q_ASSERT(re.isValid());
328 line_edit->setValidator(
new QRegularExpressionValidator(re, line_edit));
340 setFocusPolicy(Qt::NoFocus);
341 setFrameShape(QFrame::NoFrame);
342 setIconSize(QSize(22, 22));
344 setTextElideMode(Qt::ElideMiddle);
345 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
346 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
347 setResizeMode(QListView::Adjust);
348 setUniformItemSizes(
true);
350 setItemDelegate(
new WidgetBoxCategoryEntryDelegate(
this));
352 connect(
this, &QListView::pressed,
this,
353 &WidgetBoxCategoryListView::slotPressed);
354 setEditTriggers(QAbstractItemView::AnyKeyPressed);
356 m_proxyModel->setSourceModel(m_model);
358 setModel(m_proxyModel);
359 connect(m_model, &QAbstractItemModel::dataChanged,
360 this, &WidgetBoxCategoryListView::scratchPadChanged);
365 QListView::setViewMode(vm);
366 m_model->setViewMode(vm);
371 const QModelIndex index = am == FilteredAccess ?
372 m_proxyModel->index(row, 0) :
373 m_proxyModel->mapFromSource(m_model->index(row, 0));
376 setCurrentIndex(index);
381 const QDesignerWidgetBoxInterface::Widget wgt = m_model->widgetAt(m_proxyModel->mapToSource(index));
384 emit widgetBoxPressed(wgt.name(), widgetDomXml(wgt), QCursor::pos());
389 const QModelIndex index = currentIndex();
390 if (!index.isValid() || !m_proxyModel->removeRow(index.row()))
395 if (m_model->rowCount()) {
398 emit lastItemRemoved();
404 const QModelIndex index = currentIndex();
411 return am == FilteredAccess ? m_proxyModel->rowCount() : m_model->rowCount();
416 const QModelIndex filterIndex = m_proxyModel->index(filterRow, 0);
417 return m_proxyModel->mapToSource(filterIndex).row();
422 const QModelIndex unfilteredIndex = am == FilteredAccess ? m_proxyModel->mapToSource(index) : index;
423 return m_model->widgetAt(unfilteredIndex);
428 return m_model->widgetAt(am == UnfilteredAccess ? row : mapRowToSource(row));
433 m_model->removeRow(am == UnfilteredAccess ? row : mapRowToSource(row));
438 return m_model->indexOfWidget(name) != -1;
443 m_model->addWidget(widget, icon, editable);
448 QString domXml = widget.domXml();
450 if (domXml.isEmpty())
451 domXml = uiOpeningTagC +
"<widget class=\""_L1 + widget.name() +
"\"/>"_L1 + uiClosingTagC;
457 m_proxyModel->setFilterFixedString(needle);
458 m_proxyModel->setFilterCaseSensitivity(caseSensitivity);
463 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)