/* Firewall Builder Copyright (C) 2011 NetCitadel, LLC Author: Theron Tock This program is free software which we release under the GNU General Public License. You may redistribute and/or modify this program under the terms of that license as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. To get a copy of the GNU General Public License, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "DynamicGroupDialog.h" #include "events.h" #include "FWBTree.h" #include "FWCmdChange.h" #include "FWObjectPropertiesFactory.h" #include "FWWindow.h" #include "fwbuilder/DynamicGroup.h" #include #include #include using namespace std; using namespace libfwbuilder; DynamicItemDelegate::DynamicItemDelegate(DynamicGroupDialog *dialog, QObject *parent) : QItemDelegate(parent), m_dialog(dialog) { } QWidget *DynamicItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (index.column() == 0) { QToolButton *button = new QToolButton(parent); QPixmap pixmap; if (!QPixmapCache::find(":/Icons/neg", pixmap)) { pixmap.load(":/Icons/neg"); QPixmapCache::insert(":/Icons/neg", pixmap); } button->setIcon(QIcon(pixmap)); button->setProperty("row", QVariant(index.row())); connect(button, SIGNAL(clicked()), m_dialog, SLOT(deleteFilterClicked())); return button; } else { QComboBox *combo = new QComboBox(parent); connect(combo, SIGNAL(activated(int)), this, SLOT(comboActivated(int))); return combo; } } void DynamicItemDelegate::comboActivated(int abc) { /* Don't wait until we lose focus on the combobox */ emit commitData(dynamic_cast(sender())); } void DynamicItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.column() == 0) return; QString value = index.model()->data(index, Qt::EditRole).toString(); QComboBox *combo = static_cast(editor); combo->clear(); if (index.column() == 1) { if (value == DynamicGroup::TYPE_NONE) { combo->addItem("None selected", DynamicGroup::TYPE_NONE); combo->setCurrentIndex(0); } combo->addItem("Any type", DynamicGroup::TYPE_ANY); if (value == DynamicGroup::TYPE_ANY) { combo->setCurrentIndex(combo->count() - 1); } combo->insertSeparator(2); QList types = FWBTree::getObjectTypes(); foreach (const char *type, types) { combo->addItem(FWBTree().getTranslatableObjectTypeName(type), type); if (value == type) { combo->setCurrentIndex(combo->count() - 1); } } } else if (index.column() == 2) { if (value == DynamicGroup::KEYWORD_NONE) { combo->addItem("None selected", DynamicGroup::KEYWORD_NONE); combo->setCurrentIndex(0); } combo->addItem("Any keyword", DynamicGroup::KEYWORD_ANY); if (value == DynamicGroup::KEYWORD_ANY) { combo->setCurrentIndex(combo->count() - 1); } combo->insertSeparator(2); QStringList list; const set &keywords = m_dialog->getCurrentObj()->getAllKeywords(); set::const_iterator iter; for (iter = keywords.begin(); iter != keywords.end(); ++iter) { list.append(QString::fromUtf8((*iter).c_str())); } foreach (QString item, sortStrings(list)) { combo->addItem(item, item); if (item == value) { combo->setCurrentIndex(combo->count() - 1); } } } } void DynamicItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if (index.column() == 0) return; QComboBox *combo = static_cast(editor); QString value = combo->itemData(combo->currentIndex()).toString(); model->setData(index, value, Qt::EditRole); } /*****************************************************************/ DynamicGroupDialog::DynamicGroupDialog(QWidget *parent) : BaseObjectDialog(parent), m_reloadObjFilter(false) { m_ui.setupUi(this); connectSignalsOfAllWidgetsToSlotChange(); m_model = new QStandardItemModel; connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(changed())); DynamicItemDelegate *delegate = new DynamicItemDelegate(this, m_ui.criteriaView); m_ui.criteriaView->setItemDelegate(delegate); m_ui.criteriaView->setModel(m_model); m_ui.criteriaView->resizeColumnsToContents(); m_ui.criteriaView->verticalHeader()->hide(); QStringList headers; headers << "Name" << "Properties"; m_ui.matchedView->setHeaderLabels(headers); connect(m_ui.matchedView, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(gotItemDoubleClicked(QTreeWidgetItem *, int))); } void DynamicGroupDialog::applyChanges() { if (obj->isReadOnly()) return; FWCmdChange *change = new FWCmdChange(m_project, obj); DynamicGroup *newState = DynamicGroup::cast(change->getNewState()); newState->setName(m_ui.nameEdit->text().toUtf8().constData()); m_ui.commentKeywords->applyChanges(newState); list filters; int rows = m_model->rowCount(); for (int ii = 0; ii < rows; ii++) { QString type = m_model->data(m_model->index(ii, 1)).toString(); QString keyword = m_model->data(m_model->index(ii, 2)).toString(); string filter; DynamicGroup::makeFilter(filter, type.toUtf8().constData(), keyword.toUtf8().constData()); filters.push_back(filter); } newState->setFilter(filters); if (obj->cmp(newState, true)) { delete change; } else { m_project->undoStack->push(change); } m_loadedObjFilter = filters; } void DynamicGroupDialog::loadObjFilter() { DynamicGroup *objGroup = dynamic_cast(obj); /* We remove the rows instead of calling clear so the headers don't flicker. */ //m_model->clear(); while (m_model->rowCount() > 0) { m_model->removeRow(0); } QStringList headers; headers << "Del" << "Type" << "Keyword"; m_model->setHorizontalHeaderLabels(headers); const list &filter = objGroup->getFilter(); list::const_iterator iter; for (iter = filter.begin(); iter != filter.end(); ++iter) { string type, keyword; objGroup->splitFilter(*iter, type, keyword); QList items; items << new QStandardItem(QString()); items << new QStandardItem(QString::fromUtf8(type.c_str())); items << new QStandardItem(QString::fromUtf8(keyword.c_str())); m_model->appendRow(items); int row = m_model->rowCount() - 1; m_ui.criteriaView->openPersistentEditor(m_model->index(row, 0)); m_ui.criteriaView->openPersistentEditor(m_model->index(row, 1)); m_ui.criteriaView->openPersistentEditor(m_model->index(row, 2)); } QHeaderView *header = m_ui.criteriaView->horizontalHeader(); /* Try to force at least some minimum size, as the ResizeToContents doesn't always seem to work */ header->resizeSection(0, 35); header->resizeSection(1, 120); header->setStretchLastSection(true); header->setResizeMode(0, QHeaderView::ResizeToContents); header->setResizeMode(1, QHeaderView::ResizeToContents); m_reloadObjFilter = false; m_loadedObjFilter = filter; m_loadedAllKeywords = obj->getAllKeywords(); } void DynamicGroupDialog::loadFWObject(FWObject *o) { DynamicGroup *objGroup = dynamic_cast(o); const list &filter = objGroup->getFilter(); if (obj != o || m_reloadObjFilter || m_loadedObjFilter != filter || m_loadedAllKeywords != o->getAllKeywords()) { obj = o; loadObjFilter(); } m_ui.nameEdit->setText(QString::fromUtf8(o->getName().c_str())); m_ui.commentKeywords->loadFWObject(o); FWObjectDatabase *root = obj->getRoot(); m_ui.matchedView->clear(); m_ui.matchedView->setDB(root); FWObject::tree_iterator tree_iter; for (tree_iter = root->tree_begin(); tree_iter != root->tree_end(); ++tree_iter) { FWObject *elem = (*tree_iter); if (elem == root) continue; if (!objGroup->isMemberOfGroup(elem)) continue; QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.matchedView); item->setText(0, QString::fromUtf8(elem->getName().c_str())); item->setText(1, FWObjectPropertiesFactory::getObjectProperties(elem)); item->setData(0, Qt::UserRole, QVariant(elem->getId())); QString icon = ":/Icons/"; icon += elem->getTypeName().c_str(); icon += "/icon-ref"; QPixmap pixmap; if (!QPixmapCache::find(icon, pixmap)) { pixmap.load(icon); QPixmapCache::insert(icon, pixmap); } item->setIcon(0, QIcon(pixmap)); m_ui.matchedView->addTopLevelItem(item); } } void DynamicGroupDialog::validate(bool *result) { } void DynamicGroupDialog::addMatchClicked() { int newRow = m_model->rowCount(); QList items; items << new QStandardItem("") << new QStandardItem(DynamicGroup::TYPE_NONE) << new QStandardItem(DynamicGroup::KEYWORD_NONE); m_model->insertRow(newRow, items); m_ui.criteriaView->openPersistentEditor(m_model->index(newRow, 0)); m_ui.criteriaView->openPersistentEditor(m_model->index(newRow, 1)); m_ui.criteriaView->openPersistentEditor(m_model->index(newRow, 2)); m_ui.criteriaView->scrollToBottom(); /* How come insertRow() doesn't do this for us? */ emit changed(); } void DynamicGroupDialog::deleteFilterClicked() { QToolButton *button = dynamic_cast(sender()); int row = button->property("row").toInt(); m_model->removeRow(row); m_reloadObjFilter = true; emit changed(); } void DynamicGroupDialog::gotItemDoubleClicked(QTreeWidgetItem *item, int) { int objId = item->data(0, Qt::UserRole).toInt(); FWObject *o = m_project->db()->findInIndex(objId); if (o == 0) return; QCoreApplication::postEvent(m_project, new showObjectInTreeEvent(o->getRoot()->getFileName().c_str(), objId)); QCoreApplication::postEvent(mw, new openObjectInEditorEvent(o->getRoot()->getFileName().c_str(), objId)); }