/* Firewall Builder Copyright (C) 2003-2009 NetCitadel, LLC Author: Illiya Yalovoy $Id$ 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 This module has been completely rewritten by yalovoy@gmail.com in 2009 */ #include "../../config.h" #include "global.h" #include "utils.h" #include "platforms.h" #include "RuleSetView.h" #include "RuleSetModel.h" #include "ColDesc.h" #include "FWObjectSelectionModel.h" #include "RuleSetViewDelegate.h" #include "FWBSettings.h" #include "FWObjectClipboard.h" #include "FWObjectPropertiesFactory.h" #include "FWObjectDrag.h" #include "FWWindow.h" #include "FWBTree.h" #include "FWCmdRule.h" #include "ProjectPanel.h" #include "FindObjectWidget.h" #include "events.h" #include "DialogFactory.h" #include "fwbuilder/Firewall.h" #include "fwbuilder/Resources.h" #include "fwbuilder/Policy.h" #include "fwbuilder/NAT.h" #include "fwbuilder/Routing.h" #include "fwbuilder/RuleElement.h" #include "fwbuilder/Interface.h" #include "fwbuilder/Cluster.h" #include "fwbuilder/Network.h" #include #include #include #include #include #include #include #include using namespace libfwbuilder; using namespace std; RuleSetView::RuleSetView(ProjectPanel *project, QWidget *parent):QTreeView(parent) { if (fwbdebug) qDebug("RuleSetView::RuleSetView"); this->project = project; fwosm = new FWObjectSelectionModel(); setContextMenuPolicy(Qt::CustomContextMenu); setSelectionMode(QAbstractItemView::ContiguousSelection); setSelectionBehavior(QAbstractItemView::SelectRows); setAllColumnsShowFocus(false); setDragEnabled(true); setAcceptDrops(true); setDragDropMode(QAbstractItemView::DragDrop); header()->setResizeMode(QHeaderView::Interactive); header()->setMovable(false); connect (this, SIGNAL (customContextMenuRequested(const QPoint&)), this, SLOT (showContextMenu(const QPoint&))); connect (this, SIGNAL( doubleClicked(const QModelIndex&) ), this, SLOT( itemDoubleClicked(const QModelIndex&) ) ); connect (this, SIGNAL (collapsed(QModelIndex)), this, SLOT (saveCollapsedGroups())); connect (this, SIGNAL (expanded(QModelIndex)), this, SLOT (saveCollapsedGroups())); connect (this, SIGNAL (collapsed(QModelIndex)), this, SLOT (updateAllColumnsSize())); connect (this, SIGNAL (expanded(QModelIndex)), this, SLOT (updateAllColumnsSize())); initActions(); popup_menu = new QMenu(this); this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); this->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); this->header()->setStretchLastSection(false); } RuleSetView::~RuleSetView() { if (fwbdebug) qDebug("RuleSetView::~RuleSetView"); delete fwosm; delete compileRuleAction; delete moveRuleUpAction; delete moveRuleDownAction; delete removeFromGroupAction; delete newGroupAction; delete insertRuleAction; delete addRuleAfterCurrentAction; delete addToGroupAboveAction; delete addToGroupBelowAction; delete removeRuleAction; delete copyRuleAction; delete cutRuleAction; delete pasteRuleAboveAction; delete pasteRuleBelowAction; delete disableRuleAction; delete enableRuleAction; delete setColorEmptyAction; delete setColorRedAction; delete setColorBlueAction; delete setColorOrangeAction; delete setColorPurpleAction; delete setColorGrayAction; delete setColorYellowAction; delete setColorGreenAction; } void RuleSetView::init() { if (fwbdebug) qDebug("RuleSetView::init"); /* * #2474 : I want standard Qt classes to paint column 0 and area * to the left of the clumn 0 because that is where [+] and [-] * appear when we have rule groups. However I want to avoid using * the same standard color used to highlight currently selected * object in rules. To do that, I reset QPalette::Highlight color * in the palette used to draw everything in the rules. I am going * to have to reset palette back to the standard color in * RuleSetViewDelegate when I paint individual cells. */ QPalette updated_palette = palette(); updated_palette.setColor(QPalette::Highlight, QColor("silver")); setPalette(updated_palette); setUpdatesEnabled(false); QTime t; t.start(); configureGroups(); if (fwbdebug) qDebug("RuleSetView configureGroups: %d ms", t.restart()); restoreCollapsedGroups(); if (fwbdebug) qDebug("RuleSetView restoreCollapsedGroups: %d ms", t.restart()); resizeColumns(); if (fwbdebug) qDebug("RuleSetView resizeColumns: %d ms", t.restart()); setUpdatesEnabled(true); } void RuleSetView::configureGroups() { RuleSetModel* md = ((RuleSetModel*)model()); QList list; md->getGroups(list); QModelIndex parent; foreach(QModelIndex index, list) { setFirstColumnSpanned(index.row(), parent, true); } } void RuleSetView::initActions() { // Compile rule compileRuleAction = createAction(tr("Compile Rule"), SLOT(compileCurrentRule()), QKeySequence(Qt::Key_X)); addAction(compileRuleAction ); compileRuleAction->setVisible(true); compileRuleAction->setEnabled(true); // Move rule up moveRuleUpAction = createAction(tr("Move Rule Up"), SLOT( moveRuleUp()), QKeySequence(Qt::CTRL + Qt::Key_PageUp)); addAction(moveRuleUpAction ); // Move rule down moveRuleDownAction = createAction(tr("Move Rule Down"), SLOT( moveRuleDown()), QKeySequence(Qt::CTRL + Qt::Key_PageDown)); addAction(moveRuleDownAction ); // Remove rules from group removeFromGroupAction = createAction(tr("Remove From the Group"), SLOT( removeFromGroup())); // New group newGroupAction = createAction(tr("New Group"), SLOT( newGroup())); // Insert Rule insertRuleAction = createAction( tr("Insert New Rule"), SLOT( insertRule() ) ); addRuleAfterCurrentAction = createAction(tr("Add New Rule Below"), SLOT( addRuleAfterCurrent() )); addToGroupAboveAction = createAction("addToGroupAboveAction", SLOT( addToGroupAbove() )); addToGroupBelowAction = createAction("addToGroupBelowAction", SLOT( addToGroupBelow() )); // Remove rule removeRuleAction = createAction(tr("Remove Rule"), SLOT( removeRule())); // Clipboard operations copyRuleAction = createAction(tr("Copy Rule"), SLOT( copyRule() )); cutRuleAction = createAction(tr("Cut Rule"), SLOT( cutRule() )); pasteRuleAboveAction = createAction(tr("Paste Rule Above"), SLOT( pasteRuleAbove() )); pasteRuleBelowAction = createAction(tr("Paste Rule Below"), SLOT( pasteRuleBelow() )); //Disable or Enable rules disableRuleAction = createAction(tr("Enable Rule"), SLOT( disableRule() )); enableRuleAction = createAction(tr("Disable Rule"), SLOT( enableRule() )); //Change color actions QPixmap pcolor(16,16); setColorEmptyAction = createAction(tr("No Color"), SLOT( setColorEmpty() )); pcolor.fill(QColor(255,255,255)); setColorEmptyAction->setIcon(QIcon(pcolor)); setColorEmptyAction->setVisible(true); setColorRedAction = createAction(st->getLabelText(FWBSettings::RED), SLOT( setColorRed() )); pcolor.fill(st->getLabelColor(FWBSettings::RED)); setColorRedAction->setIcon(QIcon(pcolor)); setColorRedAction->setVisible(true); setColorBlueAction = createAction(st->getLabelText(FWBSettings::BLUE), SLOT( setColorBlue() )); pcolor.fill(st->getLabelColor(FWBSettings::BLUE)); setColorBlueAction->setIcon(QIcon(pcolor)); setColorBlueAction->setVisible(true); setColorOrangeAction = createAction(st->getLabelText(FWBSettings::ORANGE), SLOT( setColorOrange() )); pcolor.fill(st->getLabelColor(FWBSettings::ORANGE)); setColorOrangeAction->setIcon(QIcon(pcolor)); setColorOrangeAction->setVisible(true); setColorPurpleAction = createAction(st->getLabelText(FWBSettings::PURPLE), SLOT( setColorPurple() )); pcolor.fill(st->getLabelColor(FWBSettings::PURPLE)); setColorPurpleAction->setIcon(QIcon(pcolor)); setColorPurpleAction->setVisible(true); setColorGrayAction = createAction(st->getLabelText(FWBSettings::GRAY), SLOT( setColorGray() )); pcolor.fill(st->getLabelColor(FWBSettings::GRAY)); setColorGrayAction->setIcon(QIcon(pcolor)); setColorGrayAction->setVisible(true); setColorYellowAction = createAction(st->getLabelText(FWBSettings::YELLOW), SLOT( setColorYellow() )); pcolor.fill(st->getLabelColor(FWBSettings::YELLOW)); setColorYellowAction->setIcon(QIcon(pcolor)); setColorYellowAction->setVisible(true); setColorGreenAction = createAction(st->getLabelText(FWBSettings::GREEN), SLOT( setColorGreen() )); pcolor.fill(st->getLabelColor(FWBSettings::GREEN)); setColorGreenAction->setIcon(QIcon(pcolor)); setColorGreenAction->setVisible(true); } QAction* RuleSetView::createAction(QString label, const char* member, const QKeySequence &shortcut) { QAction* action = new QAction(label, this); action->setShortcut(shortcut); connect (action, SIGNAL(triggered()), this, member); action->setEnabled(false); action->setVisible(false); return action; } RuleSetView* RuleSetView::getRuleSetViewByType(ProjectPanel *project, RuleSet *ruleset, QWidget *parent) { if (fwbdebug) qDebug("RuleSetView::getRuleSetViewByType"); if (Policy::isA(ruleset)) return new PolicyView(project, Policy::cast(ruleset), parent); if (NAT::isA(ruleset)) return new NATView(project, NAT::cast(ruleset), parent); if (Routing::isA(ruleset)) return new RoutingView(project, Routing::cast(ruleset), parent); return NULL; } void RuleSetView::makeCurrentRuleVisible() { scrollTo( currentIndex(), QAbstractItemView::PositionAtCenter); } void RuleSetView::selectRE(QModelIndex index) { if (fwbdebug) qDebug() << "RuleSetView::selectRE(QModelIndex index)" << index; if (fwosm->index != index) { fwosm->selectedObject = NULL; fwosm->index = index; setCurrentIndex(index); scrollTo( index, QAbstractItemView::PositionAtCenter); } } void RuleSetView::selectRE(libfwbuilder::FWReference *ref) { if (fwbdebug) qDebug() << "RuleSetView::selectRE(libfwbuilder::FWReference *ref)"; /* need to find row and column this object is in and show it */ RuleElement *re = RuleElement::cast(ref->getParent()); assert(re); selectRE(re, ref->getPointer()); } void RuleSetView::selectRE(libfwbuilder::Rule *rule, int col) { if (fwbdebug) qDebug() << "RuleSetView::selectRE(libfwbuilder::Rule *rule, int col)"; RuleSetModel* md = ((RuleSetModel*)model()); selectRE(md->index(rule, col)); } void RuleSetView::selectRE(libfwbuilder::Rule *rule, ColDesc::ColumnType type) { if (fwbdebug) qDebug() << "RuleSetView::selectRE(libfwbuilder::Rule *rule, ColDesc::ColumnType type)"; RuleSetModel* md = ((RuleSetModel*)model()); int col = md->columnByType(type); selectRE(rule, col); } void RuleSetView::selectRE(libfwbuilder::RuleElement *re, libfwbuilder::FWObject *obj) { if (fwbdebug) qDebug() << "RuleSetView::selectRE(libfwbuilder::RuleElement *re, libfwbuilder::FWObject *obj)"; Rule *rule = Rule::cast(re->getParent()); assert(rule!=NULL); RuleSetModel* md = ((RuleSetModel*)model()); QModelIndex index = md->index(rule, re); selectRE(index); setCurrentIndex(index); fwosm->setSelected(obj, index); } int RuleSetView::getColByType(ColDesc::ColumnType type) const { RuleSetModel* md = ((RuleSetModel*)model()); return md->columnByType(type); } void RuleSetView::mousePressEvent( QMouseEvent* ev ) { //TODO: provide custom implementation of QTreeView::mousePressEvent( ev ); for column != 0 QTreeView::mousePressEvent( ev ); const QModelIndex index = currentIndex();//indexAt (ev->pos()); if (index.column() == 0) { fwosm->setSelected(NULL, index); return; } FWObject *object = getObject(ev->pos(), index); // if (fwbdebug) qDebug("RuleSetView::contentsMousePressEvent " // "obj=%s row=%d col=%d", // (object)?object->getName().c_str():"NULL", index.row(), index.column()); if (object) { selectObject(object, index); startingDrag = (fwosm->index.row()==index.row() && fwosm->index.column()==index.column() && fwosm->selectedObject==object); } else { fwosm->setSelected(NULL, index); } } void RuleSetView::mouseReleaseEvent( QMouseEvent* ev ) { //if (fwbdebug) qDebug() << "RuleSetView::mouseReleaseEvent"; QTreeView::mouseReleaseEvent(ev); const QModelIndex index = indexAt (ev->pos()); if (index.column() == 0) return; RuleSetModel* md = ((RuleSetModel*)model()); if (md->getRuleSet()->size()!=0) { ev->accept(); }; // if (md->getRuleSet()->size()!=0 && // mw->isEditorVisible() && !switchObjectInEditor( currentIndex()) ) // { // ev->accept(); // }; } /* * Why using persistent QMenu object for the popup menu: * * If user hits Cmd-Q on Mac while popup menu is open, we get a * crash. The problem is that when close event propagates and * eventually closes the popup menu, RuleSetView::showContextMenu() * tries to delete QMenu object and we get the following error and * crash: "QObject: Do not delete object, 'qt_scrollarea_viewport', * during its event handler!". Instead of making sure we do not delete * the object in some circumstances, or find a way to delete it * safely, it is much easier to just avoid having to delete it at all. */ void RuleSetView::showContextMenu(const QPoint& pos) { popup_menu->clear(); const QModelIndex index = indexAt ( pos); if (index.isValid()) { int column = index.column(); RuleNode* node = static_cast(index.internalPointer()); if (node->type == RuleNode::Group) { addGroupMenuItemsToContextMenu(popup_menu); } else { compileRuleAction->setEnabled(!node->rule->isDisabled()); if (column < 1) { addRowMenuItemsToMenu(popup_menu); } else { addColumnRelatedMenu(popup_menu, index, node, pos); } addCommonRowItemsToContextMenu(popup_menu); } } else { addGenericMenuItemsToContextMenu(popup_menu); } popup_menu->exec(mapToGlobal(pos)); // delete menu; } void RuleSetView::addCommonRowItemsToContextMenu(QMenu *menu) const { menu->addSeparator(); menu->addAction(compileRuleAction); } void RuleSetView::mouseMoveEvent( QMouseEvent* ev ) { if (startingDrag) { QDrag* drag = dragObject(); if (drag) drag->start(Qt::CopyAction | Qt::MoveAction); //just start dragging startingDrag = false; return; } QTreeView::mouseMoveEvent(ev); } QDrag* RuleSetView::dragObject() { FWObject *obj = fwosm->selectedObject; if (obj==NULL) return NULL; // TODO: use FWBTree::setObjectIcon() QString icn = (":/Icons/" + obj->getTypeName() + "/icon").c_str(); list dragobj; dragobj.push_back(obj); FWObjectDrag *drag = new FWObjectDrag(dragobj, this, NULL); QPixmap pm = LoadPixmap(icn); drag->setPixmap( pm ); return drag; } void RuleSetView::addColumnRelatedMenu(QMenu *menu, const QModelIndex &index, RuleNode* node, const QPoint& pos) { RuleSetModel* md = ((RuleSetModel*)model()); ColDesc colDesc = index.data(Qt::UserRole).value(); switch (colDesc.type) { case ColDesc::Action: { Firewall *f = md->getFirewall(); if (f == NULL) break; string platform = f->getStr("platform"); QString action_name; if (NATRule::isA(node->rule)) { if (Resources::isTargetActionSupported(platform,"Translate")) { action_name = getActionNameForPlatform( f, NATRule::getActionAsString(NATRule::Translate)); menu->addAction( QIcon(LoadPixmap(":/Icons/Continue/icon")), action_name, this, SLOT( changeActionToTranslate() )); } if (Resources::isTargetActionSupported(platform,"Branch")) { action_name = getActionNameForPlatform( f, NATRule::getActionAsString(NATRule::Branch)); menu->addAction( QIcon(LoadPixmap(":/Icons/NATBranch/icon")), action_name, this, SLOT( changeActionToNATBranch() )); } } else { if (Resources::isTargetActionSupported(platform,"Accept")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Accept)); menu->addAction( QIcon(LoadPixmap(":/Icons/Accept/icon")), action_name, this, SLOT( changeActionToAccept() )); } if (Resources::isTargetActionSupported(platform,"Deny")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Deny)); menu->addAction( QIcon(LoadPixmap(":/Icons/Deny/icon")), action_name, this, SLOT( changeActionToDeny() )); } if (Resources::isTargetActionSupported(platform,"Reject")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Reject)); menu->addAction( QIcon(LoadPixmap(":/Icons/Reject/icon")), action_name, this, SLOT( changeActionToReject() )); } if (Resources::isTargetActionSupported(platform,"Accounting")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Accounting)); menu->addAction( QIcon(LoadPixmap(":/Icons/Accounting/icon")), action_name, this, SLOT( changeActionToAccounting() )); } if (Resources::isTargetActionSupported(platform,"Pipe")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Pipe)); menu->addAction( QIcon(LoadPixmap(":/Icons/Pipe/icon")), action_name, this, SLOT( changeActionToPipe() )); } /* * #2367 if (Resources::isTargetActionSupported(platform,"Tag")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Tag)); menu->addAction( QIcon(LoadPixmap(":/Icons/Tag/icon")), action_name, this, SLOT( changeActionToTag() )); } if (Resources::isTargetActionSupported(platform,"Classify")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Classify)); menu->addAction( QIcon(LoadPixmap(":/Icons/Classify/icon")), action_name, this, SLOT( changeActionToClassify() )); } if (Resources::isTargetActionSupported(platform,"Route")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Route)); menu->addAction( QIcon(LoadPixmap(":/Icons/Route/icon")), action_name, this, SLOT( changeActionToRoute() )); } */ if (Resources::isTargetActionSupported(platform,"Custom")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Custom)); menu->addAction( QIcon(LoadPixmap(":/Icons/Custom/icon")), action_name, this, SLOT( changeActionToCustom() )); } if (Resources::isTargetActionSupported(platform,"Branch")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Branch)); menu->addAction( QIcon(LoadPixmap(":/Icons/Branch/icon")), action_name, this, SLOT( changeActionToBranch() )); } if (Resources::isTargetActionSupported(platform,"Continue")) { action_name = getActionNameForPlatform( f, PolicyRule::getActionAsString(PolicyRule::Continue)); menu->addAction( QIcon(LoadPixmap(":/Icons/Continue/icon")), action_name, this, SLOT( changeActionToContinue() )); } } menu->addSeparator (); QAction *paramID; paramID = menu->addAction( tr("Parameters"), this, SLOT( editSelected() )); PolicyRule *rule = PolicyRule::cast( node->rule ); if (rule!=NULL) { string act = rule->getActionAsString(); if (Resources::getActionEditor(platform,act)=="None") paramID->setEnabled(false); } break; } case ColDesc::Direction: menu->addAction( QIcon(LoadPixmap(":/Icons/Inbound/icon")), tr("Inbound"), this, SLOT( changeDirectionToIn() )); menu->addAction( QIcon(LoadPixmap(":/Icons/Outbound/icon")), tr("Outbound"), this, SLOT( changeDirectionToOut() )); menu->addAction( QIcon(LoadPixmap(":/Icons/Both/icon")), tr("Both"), this, SLOT( changeDirectionToBoth() )); break; case ColDesc::Comment: menu->addAction( tr("Edit") , this , SLOT( editSelected() ) ); break; case ColDesc::Metric: menu->addAction( tr("Edit") , this , SLOT( editSelected() ) ); break; case ColDesc::Options: menu->addAction( QIcon(LoadPixmap(":/Icons/Options/icon")), tr("Rule Options"), this, SLOT( editSelected() )); if (md->getRuleSet()->getTypeName() == Policy::TYPENAME) { menu->addAction( QIcon(LoadPixmap(":/Icons/Log/icon")), tr("Logging On"), this, SLOT( changeLogToOn() )); menu->addAction( QIcon(LoadPixmap(":/Icons/Blank/icon")), tr("Logging Off"), this, SLOT( changeLogToOff() )); } break; case ColDesc::Object: case ColDesc::Time: { RuleElement *re = getRE(index); if (re==NULL) return; FWObject *object = getObject(pos, index); QAction *editID = menu->addAction( tr("Edit") , this , SLOT( editSelected() ) ); menu->addSeparator(); QAction *copyID = menu->addAction( tr("Copy") , this , SLOT( copySelectedObject() ) ); QAction *cutID = menu->addAction( tr("Cut") , this , SLOT( cutSelectedObject() ) ); QAction *pasteID = menu->addAction( tr("Paste") , this , SLOT( pasteObject() ) ); QAction *delID =menu->addAction( tr("Delete") , this , SLOT( deleteSelectedObject() ) ); menu->addSeparator(); QAction *fndID = menu->addAction( tr("Where used") , this , SLOT( findWhereUsedSlot())); QAction *revID = menu->addAction( tr("Reveal in tree") ,this , SLOT( revealObjectInTree() ) ); menu->addSeparator(); QAction *negID = menu->addAction( tr("Negate") , this , SLOT( negateRE() ) ); if (object == NULL || re->isAny()) editID->setEnabled(false); copyID->setEnabled(!re->isAny()); cutID->setEnabled(!re->isAny()); delID->setEnabled(!re->isAny()); // see #1976 do not allow pasting object that has been deleted FWObject *obj_in_clipboard = FWObjectClipboard::obj_clipboard->getObject(); bool obj_deleted = (obj_in_clipboard && obj_in_clipboard->getLibrary()->getId() == FWObjectDatabase::DELETED_OBJECTS_ID); pasteID->setEnabled(obj_in_clipboard!=NULL && !obj_deleted); string cap_name; if (Policy::cast(md->getRuleSet())!=NULL) cap_name="negation_in_policy"; if (NAT::cast(md->getRuleSet())!=NULL) cap_name="negation_in_nat"; Firewall *f = md->getFirewall(); if (f == NULL) break; bool supports_neg=false; try { supports_neg = Resources::getTargetCapabilityBool( f->getStr("platform"), cap_name); } catch (FWException &ex) { QMessageBox::critical( NULL , "Firewall Builder", ex.toString().c_str(), QString::null,QString::null); } negID->setEnabled(supports_neg && !re->isAny()); fndID->setEnabled(!re->isAny()); revID->setEnabled(!re->isAny()); break; } default : menu->addAction( tr("Edit") , this , SLOT( editRE() ) ); } } void RuleSetView::addGenericMenuItemsToContextMenu(QMenu *menu) const { if (((RuleSetModel*)model())->isEmpty()) menu->addAction(tr("Insert New Rule"), this, SLOT( insertRule() )); else { menu->addAction(tr("Add New Rule on Top"), this, SLOT( insertNewRuleOnTop())); menu->addAction(tr("Add New Rule at the Bottom"), this, SLOT( insertNewRuleAtBottom())); } menu->addSeparator(); menu->addAction(tr("Paste Rule"), this, SLOT( pasteRuleBelow())); } void RuleSetView::addGroupMenuItemsToContextMenu(QMenu *menu) const { menu->addAction( tr("Rename group"), this, SLOT( renameGroup() )); menu->addSeparator(); addChangeColorSubmenu(menu); } void RuleSetView::addChangeColorSubmenu(QMenu *menu) const { QMenu *subcolor = menu->addMenu(tr("Change color") ); subcolor->addAction(setColorEmptyAction); subcolor->addAction(setColorRedAction); subcolor->addAction(setColorOrangeAction); subcolor->addAction(setColorYellowAction); subcolor->addAction(setColorGreenAction); subcolor->addAction(setColorBlueAction); subcolor->addAction(setColorPurpleAction); subcolor->addAction(setColorGrayAction); } void RuleSetView::addRowMenuItemsToMenu(QMenu *menu) const { if (fwbdebug) qDebug() << "RuleSetView::addRowMenuItemsToMenu menu=" << menu; menu->addAction(removeFromGroupAction); menu->addAction(newGroupAction); menu->addAction(addToGroupAboveAction); menu->addAction(addToGroupBelowAction); menu->addSeparator(); addChangeColorSubmenu(menu); menu->addSeparator(); menu->addAction( insertRuleAction ); menu->addAction( addRuleAfterCurrentAction ); menu->addAction( removeRuleAction ); menu->addSeparator(); menu->addAction( moveRuleUpAction); menu->addAction( moveRuleDownAction); menu->addSeparator(); menu->addAction(copyRuleAction); menu->addAction(cutRuleAction); menu->addAction(pasteRuleAboveAction); menu->addAction(pasteRuleBelowAction); menu->addSeparator(); menu->addAction(enableRuleAction); menu->addAction(disableRuleAction); } void RuleSetView::itemDoubleClicked(const QModelIndex& index) { if (!index.isValid()) return; if (index.row() < 0) return; if (index.column() == 0) return; // double click on rule number does nothing // ColDesc colDesc = index.data(Qt::UserRole).value(); // if (fwosm->selectedObject!=NULL) // { // QCoreApplication::postEvent( // mw, // new showObjectInTreeEvent( // project->getFileName(), fwosm->selectedObject->getId())); // } editSelected(index); } void RuleSetView::editSelected(const QModelIndex& index) { ColDesc colDesc = index.data(Qt::UserRole).value(); FWObject *obj = fwosm->selectedObject; // see #2454 -- we do not want to switch object tree view to the standard // objects library when user double clicks on object "any" if (obj != NULL && (obj->getId() != FWObjectDatabase::ANY_ADDRESS_ID && obj->getId() != FWObjectDatabase::ANY_SERVICE_ID && obj->getId() != FWObjectDatabase::ANY_INTERVAL_ID)) { QCoreApplication::postEvent( mw, new showObjectInTreeEvent( project->getFileName(), fwosm->selectedObject->getId())); } if (!mw->isEditorVisible()) mw->showEditor(); switchObjectInEditor(index); } void RuleSetView::editSelected() { editSelected(currentIndex()); } bool RuleSetView::switchObjectInEditor(const QModelIndex& index, bool validate) { RuleSetModel* md = ((RuleSetModel*)model()); if (!isTreeReadWrite(this,md->getRuleSet())) return false; if ( index.column()<=0 || index.row()==-1 ) return false; FWObject *object = NULL; ObjectEditor::OptType operation = ObjectEditor::optNone; /* * We need to know WHAT we are going to edit 1. Object 2. OptType * Object == null, OptType = optNone => blank * Object == Rule, OptType = optNone => Rule Options * Object == Rule, OptType != optNone => Virtual Object (Action, Comment ...) * Object != Rule, OptType = optNone => Regular Object Editor Then we compare our object 'obj' and OptType with what we already have in ObjectEditor/ If they are the same, then we do nothing, otherwise we open obj in the Object Editor */ ColDesc colDesc = index.data(Qt::UserRole).value(); RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return false; Rule *rule = node->rule; switch (colDesc.type) { case ColDesc::Comment: object = rule; operation = ObjectEditor::optComment; break; case ColDesc::Metric: object = rule; operation = ObjectEditor::optMetric; break; case ColDesc::Direction: break; case ColDesc::Action: { //PolicyRule *prule = PolicyRule::cast( rule ); object = rule; operation = ObjectEditor::optAction; break; } case ColDesc::Options: { /* both policy and routing rules have options. so cast to * Rule here. */ assert(rule); object = rule; operation = ObjectEditor::optNone; break; } default: { if ( fwosm->selectedObject!=NULL) { object = fwosm->selectedObject; break; } } } if (!mw->isEditorVisible()) mw->showEditor(); if (!mw->requestEditorOwnership(this, object, operation, validate)) return false; if (object==mw->getOpenedEditor() && operation==mw->getOpenedOptEditor()) { if (fwbdebug) qDebug("RuleSetView::switchObjectInEditor same object is already opened in the editor"); return true; } if (object == NULL) { QCoreApplication::postEvent(mw, new clearEditorPanelEvent()); //mw->blankEditor(); } else if (operation==ObjectEditor::optNone) { QCoreApplication::postEvent( mw, new openObjectInEditorEvent( mw->activeProject()->getFileName(), object->getId())); //mw->openEditor(object); } else if(Rule::cast(object)!=NULL) { QCoreApplication::postEvent( mw, new openOptObjectInEditorEvent(project->getFileName(), object->getId(), operation)); //mw->openOptEditor(object, operation); } return true; } QModelIndexList RuleSetView::getSelectedRows() const { QModelIndexList selection = selectedIndexes(); QModelIndexList res; for (QList::iterator i = selection.begin(); i != selection.end(); ++i) { if(!(*i).column()) { res.append(*i); } } return res; } void RuleSetView::setSelectedRows(const QModelIndex firstIndex, const QModelIndex lastIndex) { fwosm->reset(); selectionModel()->clear(); setCurrentIndex(firstIndex); selectionModel()->select(QItemSelection(firstIndex, lastIndex), QItemSelectionModel::Rows | QItemSelectionModel::Select); fwosm->setSelected(0, firstIndex); } void RuleSetView::removeRule() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; mw->findObjectWidget->reset(); QModelIndexList selection = getSelectedRows(); if (!selection.isEmpty()) { QMap > itemsInGroups; QList rulesToDelete; // Sort rules to the corresponding groups foreach (QModelIndex index, selection) { if (!index.isValid() || !md->isIndexRule(index)) continue; if (mw->isEditorVisible() && mw->getOpenedEditor()==md->nodeFromIndex(index)->rule) mw->closeEditor(); QModelIndex parent = index.parent(); if (parent.isValid()) { itemsInGroups[parent] << index.row(); } RuleNode* node = md->nodeFromIndex(index); if (node->type == RuleNode::Rule) rulesToDelete << node->rule; } //Special case - all rows are inside one group (excluding the //first item of the group) if (itemsInGroups.size() == 1 && itemsInGroups[itemsInGroups.keys().first()].size() == rulesToDelete.size()) { bool containsFirstRow = false; foreach(int row, itemsInGroups[itemsInGroups.keys().first()]) { if (0 == row) { containsFirstRow = true; break; } } if (!containsFirstRow) { FWCmdRuleDeleteFromGroup* cmd = new FWCmdRuleDeleteFromGroup(project, md->getRuleSet(), rulesToDelete); project->undoStack->push(cmd); return; } } FWCmdMacro* macro = new FWCmdMacro("delete rules"); // Remove items from groups QList groups = itemsInGroups.keys(); if (!groups.isEmpty()) { foreach(QModelIndex group, groups) { qSort(itemsInGroups[group]); Rule* first = md->nodeFromIndex(md->index(itemsInGroups[group].at(0), 0, group))->rule; Rule* last = md->nodeFromIndex(md->index(itemsInGroups[group].at(itemsInGroups[group].size() - 1), 0, group))->rule; QString groupName = md->nodeFromIndex(group)->name; FWCmdRuleRemoveFromGroup* cmd = new FWCmdRuleRemoveFromGroup(project, md->getRuleSet(), first, last, groupName, macro); } } // Remove rows if (!rulesToDelete.isEmpty()) { FWCmdRuleDelete* cmd = new FWCmdRuleDelete(project, md->getRuleSet(), rulesToDelete, macro); } project->undoStack->push(macro); } } void RuleSetView::renameGroup() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); foreach(QModelIndex index, selection) { if (!index.isValid()) continue; RuleNode *group = md->nodeFromIndex(index); // Process only groups. Skip all rules. if(group->type != RuleNode::Group) continue; QString oldGroupName = group->name; bool ok = false; QString newGroupName = QInputDialog::getText( this, "Rename group", tr("Enter group name:"), QLineEdit::Normal, oldGroupName, &ok); if (ok && !newGroupName.isEmpty() && newGroupName != oldGroupName) { project->undoStack->push(new FWCmdRuleRenameGroup(project, md->getRuleSet(), oldGroupName, newGroupName)); } } } void RuleSetView::setRuleColor(const QString &c) { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndexList selection = getSelectedRows(); // Current behaviour is following: // if we have only groups selected then recolor groups // if there are rules in selection then selected groups will be ignored and only selected rules will be recolored QList rules; QList groups; foreach (QModelIndex index, selection) { if (md->isIndexRule(index)) { rules << index; } else { groups << index; } } QList ruleList; if (rules.isEmpty()) { // Let's recolor groups - there are no rules in the selection foreach(QModelIndex grpIndex, groups) { foreach(RuleNode* node, md->nodeFromIndex(grpIndex)->children) { ruleList.append(node->rule); } } } else { // There are rules in selection, so recolor them foreach (QModelIndex index, rules) { ruleList.append(md->nodeFromIndex(index)->rule); } } project->undoStack->push(new FWCmdRuleColor(project, md->getRuleSet(), ruleList, c)); } void RuleSetView::setColorEmpty() { setRuleColor(""); } void RuleSetView::setColorRed() { setRuleColor(st->getLabelColor(FWBSettings::RED)); } void RuleSetView::setColorBlue() { setRuleColor(st->getLabelColor(FWBSettings::BLUE)); } void RuleSetView::setColorOrange() { setRuleColor(st->getLabelColor(FWBSettings::ORANGE)); } void RuleSetView::setColorPurple() { setRuleColor(st->getLabelColor(FWBSettings::PURPLE)); } void RuleSetView::setColorGray() { setRuleColor(st->getLabelColor(FWBSettings::GRAY)); } void RuleSetView::setColorYellow() { setRuleColor(st->getLabelColor(FWBSettings::YELLOW)); } void RuleSetView::setColorGreen() { setRuleColor(st->getLabelColor(FWBSettings::GREEN)); } void RuleSetView::enableRule() { setEnabledRow(true); } void RuleSetView::disableRule() { setEnabledRow(false); } void RuleSetView::setEnabledRow(bool flag) { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); if (!selection.isEmpty()) { foreach (QModelIndex index, selection) { if (!index.isValid()) continue; RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) continue; Rule* rule = node->rule; if (!rule->isDisabled() == flag) continue; FWCmdRuleChange* cmd = new FWCmdRuleChange( project, md->getRuleSet(), rule, (flag)?tr("Enable rule"):tr("Disable rule")); Rule* newState = Rule::cast(cmd->getNewState()); if (flag) newState->enable(); else newState->disable(); project->undoStack->push(cmd); } } updateSelectionSensitiveActions(); } void RuleSetView::newGroup() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); // we cannot perform this action if the selection contains groups or rules assigned to groups if (!selection.isEmpty() && isOnlyTopLevelRules(selection)) { bool ok; QString newGroupName = QInputDialog::getText( this, "Rename group", tr("Enter group name:"), QLineEdit::Normal, tr("New Group"), &ok); if (ok && !newGroupName.isEmpty()) { FWCmdRuleNewGroup* cmd = new FWCmdRuleNewGroup( project, md->getRuleSet(), md->nodeFromIndex(selection.first())->rule, md->nodeFromIndex(selection.last())->rule, newGroupName); project->undoStack->push(cmd); } } } void RuleSetView::addToGroupAbove() { addToGroup(true); } void RuleSetView::addToGroupBelow() { addToGroup(false); } void RuleSetView::addToGroup(bool isAbove) { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); // we cannot perform this action if the selection contains groups or rules assigned to groups if (!selection.isEmpty() && isOnlyTopLevelRules(selection)) { FWCmdRuleAddToGroup* cmd = new FWCmdRuleAddToGroup( project, md->getRuleSet(), md->nodeFromIndex(selection.first())->rule, md->nodeFromIndex(selection.last())->rule, isAbove); project->undoStack->push(cmd); } } void RuleSetView::moveRuleUp() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); // we cannot perform this action if the selection contains groups or rules assigned to groups if (!selection.isEmpty() && isOneLevelRules(selection)) { RuleSetModelIterator it = md->begin(); QModelIndex top = it.index(); if (top.parent() == selection.first().parent() && top.row() == selection.first().row()) return; FWCmdRuleMove* cmd = new FWCmdRuleMove(project, md->getRuleSet(), md->nodeFromIndex(selection.first())->rule->getId(), md->nodeFromIndex(selection.last())->rule->getId()); project->undoStack->push(cmd); } } void RuleSetView::moveRuleDown() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; QModelIndexList selection = getSelectedRows(); // we cannot perform this action if the selection contains groups or rules assigned to groups if (!selection.isEmpty() && isOneLevelRules(selection)) { RuleSetModelIterator it = md->end(); --it; QModelIndex bottom = it.index(); if (bottom.parent() == selection.last().parent() && bottom.row() == selection.last().row()) return; FWCmdRuleMove* cmd = new FWCmdRuleMove(project, md->getRuleSet(), md->nodeFromIndex(selection.first())->rule->getId(), md->nodeFromIndex(selection.last())->rule->getId(), false); project->undoStack->push(cmd); } } bool RuleSetView::isOnlyTopLevelRules(const QModelIndexList &list) const { foreach (QModelIndex index, list) { if (!index.isValid()) return false; RuleNode* node = static_cast(index.internalPointer()); if (node==0 || node->type != RuleNode::Rule || node->parent->type != RuleNode::Root) return false; } return true; } bool RuleSetView::isOneLevelRules(const QModelIndexList &list) { RuleNode *parent = 0; foreach (QModelIndex index, list) { if (!index.isValid()) return false; RuleNode* node = static_cast(index.internalPointer()); if (node==0 || node->type != RuleNode::Rule) return false; if (parent == 0) parent = node->parent; else if (parent != node->parent) return false; } return true; } void RuleSetView::copyRule() { RuleSetModel* md = ((RuleSetModel*)model()); QModelIndexList selection = getSelectedRows(); if ( !selection.isEmpty() ) { FWObjectClipboard::obj_clipboard->clear(); foreach (QModelIndex index, selection) { RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) continue; FWObject *rule = node->rule; if (rule) FWObjectClipboard::obj_clipboard->add( rule, project ); } } } void RuleSetView::cutRule() { copyRule(); removeRule(); } void RuleSetView::pasteRuleAbove() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndexList selection = getSelectedRows(); QModelIndex index = currentIndex(); vector >::iterator i; for (i= FWObjectClipboard::obj_clipboard->begin(); i!=FWObjectClipboard::obj_clipboard->end(); ++i) { Rule *rule = Rule::cast(createInsertTemplate(i->second, i->first)); if (!rule || !md->checkRuleType(rule)) continue; project->undoStack->push( new FWCmdRuleInsert( project, md->getRuleSet(), md->getRulePosition(index), false, rule)); } } void RuleSetView::pasteRuleBelow() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndex index = currentIndex(); vector >::reverse_iterator i; for (i= FWObjectClipboard::obj_clipboard->rbegin(); i!=FWObjectClipboard::obj_clipboard->rend(); ++i) { Rule *rule = Rule::cast(createInsertTemplate(i->second, i->first)); if (!rule || !md->checkRuleType(rule)) continue; project->undoStack->push( new FWCmdRuleInsert( project, md->getRuleSet(), md->getRulePosition(index), true, rule)); } } FWObject* RuleSetView::createInsertTemplate(ProjectPanel* proj_p, int id) { RuleSetModel* md = ((RuleSetModel*)model()); FWObject* co = proj_p->db()->findInIndex(id); FWObject* t = 0; if (!Rule::cast(co)) return 0; if (proj_p!=project) { // rule is being copied from another project file map map_ids; t = project->db()->recursivelyCopySubtree(md->getRuleSet(), co, map_ids); // Note that FWObjectDatabase::recursivelyCopySubtree adds // a copy it creates to the end of the list of children of // the object passed as its first arg., which is in this // case ruleset. This works only if we paste rule at the // bottom of ruleset, otherwise need to move them to the // proper location. t->ref(); md->getRuleSet()->remove(t); project->m_panel->om->reload(); } else { t = proj_p->db()->create(co->getTypeName()); t->duplicate(co); } return t; } bool RuleSetView::canChange(RuleSetModel* md) { if(!isTreeReadWrite(this,md->getRuleSet())) return false; if (md->getFirewall()==NULL) return false; return true; } void RuleSetView::insertRule(QModelIndex index, bool isAfter) { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; project->undoStack->push( new FWCmdRuleInsert( project, md->getRuleSet(), md->getRulePosition(index), isAfter)); } void RuleSetView::insertRule() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndexList selection = getSelectedRows(); QModelIndex index; if (!selection.isEmpty()) { index = selection.first(); } insertRule(index); } void RuleSetView::addRuleAfterCurrent() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndexList selection = getSelectedRows(); if (selection.isEmpty()) { insertRule(QModelIndex()); } else { QModelIndex lastSelectedIndex = selection.last(); insertRule(lastSelectedIndex, true); } } void RuleSetView::insertNewRuleOnTop() { insertRule(QModelIndex()); } void RuleSetView::insertNewRuleAtBottom() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; RuleSetModelIterator it = md->end(); --it; Rule* posRule = md->nodeFromIndex(it.index())->rule; project->undoStack->push( new FWCmdRuleInsert( project, md->getRuleSet(), posRule->getPosition(), true)); } void RuleSetView::removeFromGroup() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; if (md->getFirewall()==NULL) return; QModelIndexList selection = getSelectedRows(); QMap > itemsInGroups; // Get all rules sorted by groups foreach (QModelIndex index, selection) { if (!index.isValid() || !md->isIndexRule(index)) continue; QModelIndex parent = index.parent(); if (parent.isValid()) { itemsInGroups[parent] << index.row(); } } // Remove groups from the end to the begin QList groups = itemsInGroups.keys(); qSort(groups); QListIterator i(groups); i.toBack(); while (i.hasPrevious()) { QModelIndex group = i.previous(); qSort(itemsInGroups[group]); QModelIndex first = md->index(itemsInGroups[group].first(), 0, group); QModelIndex last = md->index(itemsInGroups[group].last(), 0, group); FWCmdRuleRemoveFromGroup *cmd = new FWCmdRuleRemoveFromGroup(project, md->getRuleSet(), md->nodeFromIndex(first)->rule, md->nodeFromIndex(last)->rule, md->nodeFromIndex(group)->name); project->undoStack->push(cmd); // md->removeFromGroup(group, itemsInGroups[group].first(), itemsInGroups[group].last()); } // QCoreApplication::postEvent( // mw, new dataModifiedEvent(project->getFileName(), md->getRuleSet()->getId())); } FWObject *RuleSetView::getObject(const QPoint &pos, const QModelIndex &index) { if (!index.isValid() || index.column() == 0) return 0; RuleNode* node = static_cast(index.internalPointer()); if (node->type == RuleNode::Group) return 0; QRect vrect = visualRect(index); if (!vrect.isValid()) return 0; const int relativeY = pos.y() - vrect.top(); if (relativeY < 0 || relativeY > vrect.height()) return 0; const int itemHeight = RuleSetViewDelegate::getItemHeight(); RuleElement *re = getRE(index); if (re==NULL) return 0; int oy=0; FWObject *o1=NULL; FWObject *obj=NULL; FWObject *prev=NULL; for (FWObject::iterator i=re->begin(); i!=re->end(); i++) { o1= *i; if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer(); if (relativeY>oy && relativeY(index.internalPointer()); if (node->type == RuleNode::Group) return 0; RuleElement *re = getRE(index); if (re==NULL) return 0; int n=1; FWObject *o1=NULL; FWObject *obj=NULL; FWObject *prev=NULL; for (FWObject::iterator i=re->begin(); i!=re->end(); i++) { o1= *i; if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer(); if (n == number) { obj=o1; break; } n++; prev=o1; } if (obj==NULL) obj=prev; return obj; } int RuleSetView::getObjectNumber(FWObject *object, const QModelIndex &index) { if (!index.isValid() || index.column() == 0) return 0; RuleNode* node = static_cast(index.internalPointer()); if (node->type == RuleNode::Group) return 0; RuleElement *re = getRE(index); if (re==NULL) return 0; int n=1; FWObject *o1=NULL; for (FWObject::iterator i=re->begin(); i!=re->end(); i++) { o1= *i; if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer(); if (object == o1) break; n++; } return n; } void RuleSetView::selectObject(int position, int column, int number) { RuleSetModel* md = ((RuleSetModel*)model()); QModelIndex index = md->indexForPosition(position); if (index.isValid()) { index = md->index(index.row(), column, index.parent()); FWObject* obj = getObject(number, index); selectObject(obj, index); } else { unselect(); } } void RuleSetView::selectObject(FWObject *object, const QModelIndex &index) { fwosm->setSelected(object, index); setCurrentIndex(index); viewport()->update((viewport()->rect())); } void RuleSetView::changeDirectionToIn() { changeDitection( PolicyRule::Inbound ); } void RuleSetView::changeDirectionToOut() { changeDitection( PolicyRule::Outbound ); } void RuleSetView::changeDirectionToBoth() { changeDitection( PolicyRule::Both ); } void RuleSetView::changeDitection(PolicyRule::Direction dir) { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; if (md->getFirewall()==NULL) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return; PolicyRule *rule = PolicyRule::cast( node->rule ); PolicyRule::Direction old_dir=rule->getDirection(); if (dir!=old_dir) { FWCmdRuleChange* cmd = new FWCmdRuleChange( project, md->getRuleSet(), rule, tr("Change direction")); PolicyRule* newState = PolicyRule::cast(cmd->getNewState()); newState->setDirection( dir ); project->undoStack->push(cmd); } } void RuleSetView::changeAction(int act) { if (fwbdebug) qDebug() << "RuleSetView::changeAction act=" << act; RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; if (md->getFirewall()==NULL) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return; std::auto_ptr cmd( new FWCmdRuleChange(project, md->getRuleSet(), node->rule, tr("Change action"))); Rule* newRule = dynamic_cast(cmd->getNewState()); if (PolicyRule::isA(newRule)) { PolicyRule *rule = PolicyRule::cast( newRule ); FWOptions *ruleopt = rule->getOptionsObject(); PolicyRule::Action old_act=rule->getAction(); if (fwbdebug) qDebug() << "PolicyRule old_action=" << old_act; if (act!=old_act) { rule->setAction(PolicyRule::Action(act)); ruleopt->setBool("stateless", getStatelessFlagForAction(rule)); project->undoStack->push(cmd.release()); } } else if (NATRule::isA(newRule)) { NATRule *rule = NATRule::cast( newRule ); NATRule::NATAction old_act = rule->getAction(); if (fwbdebug) qDebug() << "NATRule old_action=" << old_act << "NATRule::Translate=" << NATRule::Translate << "NATRule::Branch=" << NATRule::Branch; if (act!=old_act) { rule->setAction(NATRule::NATAction(act)); project->undoStack->push(cmd.release()); } } // See #957. It makes sense to open action in the edtor only // if this action has some parameters to edit. FWObject *fw = node->rule; while (fw && Firewall::cast(fw)==NULL) fw = fw->getParent(); if (fw) { QString editor = DialogFactory::getActionDialogPageName( Firewall::cast(fw), node->rule).c_str(); editor = editor.toLower(); // open action in the editor if the editor is already visible // or if it is not, only if there is something to edit in this // action if (mw->isEditorVisible() || (!editor.isEmpty() && editor != "none")) QCoreApplication::postEvent( mw, new openOptObjectInEditorEvent( project->getFileName(), node->rule->getId(), ObjectEditor::optAction)); } } void RuleSetView::changeActionToAccept() { changeAction( PolicyRule::Accept ); } void RuleSetView::changeActionToDeny() { changeAction( PolicyRule::Deny ); } void RuleSetView::changeActionToReject() { changeAction( PolicyRule::Reject ); } void RuleSetView::changeActionToAccounting() { changeAction( PolicyRule::Accounting ); } void RuleSetView::changeActionToPipe() { changeAction( PolicyRule::Pipe ); } void RuleSetView::changeActionToCustom() { changeAction( PolicyRule::Custom ); } void RuleSetView::changeActionToContinue() { changeAction( PolicyRule::Continue ); } void RuleSetView::changeActionToBranch() { changeAction( PolicyRule::Branch ); } void RuleSetView::changeActionToTranslate() { changeAction( NATRule::Translate ); } void RuleSetView::changeActionToNATBranch() { changeAction( NATRule::Branch ); } void RuleSetView::changeLogToOn() { changeLogging(true); } void RuleSetView::changeLogToOff() { changeLogging(false); } void RuleSetView::changeLogging(bool flag) { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return; PolicyRule *rule = PolicyRule::cast( node->rule ); if (rule->getLogging() == flag) return; FWCmdRuleChange* cmd = new FWCmdRuleChange( project, md->getRuleSet(), rule, tr("Change logging")); PolicyRule* newState = PolicyRule::cast(cmd->getNewState()); newState->setLogging( flag ); project->undoStack->push(cmd); } void RuleSetView::negateRE() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return; RuleElement *re = getRE(index); if (re==NULL) return; int position = Rule::cast(re->getParent())->getPosition(); int column = index.column(); project->undoStack->push( new FWCmdRuleNegateRE(project, md->getRuleSet(), re, position, column)); } void RuleSetView::revealObjectInTree() { FWObject* selectedObject = fwosm->selectedObject; if (selectedObject!=NULL) QCoreApplication::postEvent( mw, new showObjectInTreeEvent(selectedObject->getRoot()->getFileName().c_str(), selectedObject->getId())); } void RuleSetView::findWhereUsedSlot() { if ( fwosm->selectedObject!=NULL) mw->findWhereUsed(fwosm->selectedObject, project); } void RuleSetView::deleteSelectedObject() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; if ( fwosm->selectedObject!=NULL) { deleteObject(index, fwosm->selectedObject, tr("delete ")+QString::fromUtf8(fwosm->selectedObject->getName().c_str())); } } void RuleSetView::copySelectedObject() { if ( fwosm->selectedObject!=NULL) { FWObjectClipboard::obj_clipboard->clear(); FWObject *obj = fwosm->selectedObject; FWObjectClipboard::obj_clipboard->add(obj, project ); mw->showStatusBarMessage( tr("Copy object '%1' to clipboard'").arg( QString::fromUtf8(obj->getName().c_str()))); } } void RuleSetView::cutSelectedObject() { RuleSetModel* md = ((RuleSetModel*)model()); if(!isTreeReadWrite(this,md->getRuleSet())) return; if ( fwosm->selectedObject!=NULL) { QModelIndex index = currentIndex(); FWObjectClipboard::obj_clipboard->clear(); FWObjectClipboard::obj_clipboard->add( fwosm->selectedObject, project ); deleteObject(index, fwosm->selectedObject, tr("cut ") + QString::fromUtf8(fwosm->selectedObject->getName().c_str())); } } void RuleSetView::pasteObject() { RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; vector >::iterator i; for (i= FWObjectClipboard::obj_clipboard->begin(); i!=FWObjectClipboard::obj_clipboard->end(); ++i) { ProjectPanel *proj_p = i->second; FWObject *co= proj_p->db()->findInIndex(i->first); if (Rule::cast(co)!=NULL) pasteRuleAbove(); else { // object in the clipboard is not a rule QModelIndex index = currentIndex(); if (index.isValid()) { RuleNode *node = md->nodeFromIndex(index); if (node->type != RuleNode::Rule) return; copyAndInsertObject(index, co); } } } } void RuleSetView::dragEnterEvent( QDragEnterEvent *ev) { ev->setAccepted( ev->mimeData()->hasFormat(FWObjectDrag::FWB_MIME_TYPE) ); } void RuleSetView::dropEvent(QDropEvent *ev) { // only accept drops from the same instance of fwbuilder if (ev->source() == NULL) return; RuleSetModel* md = ((RuleSetModel*)model()); if (!canChange(md)) return; QModelIndex index = indexAt (ev->pos()); if (!index.isValid()) return; list dragol; if (!FWObjectDrag::decode(ev, dragol)) return; for (list::iterator i=dragol.begin(); i!=dragol.end(); ++i) { FWObject *dragobj = *i; assert(dragobj!=NULL); if (fwbdebug) qDebug("RuleSetView::dropEvent dragobj=%s", dragobj->getName().c_str()); if (!validateForInsertion(index, dragobj)) continue; if (ev->source()!=this) { // since ev->source()!=this, this is d&d of an object from // the tree into rule or from another file. copyAndInsertObject(index, dragobj); } else { // since ev->source()==this, this is d&d of an object from // one rule to another. clearSelection(); if (ev->keyboardModifiers() & Qt::ControlModifier) { insertObject( index, dragobj, "copy-drop "+QString::fromUtf8(dragobj->getName().c_str())); } else //move { QModelIndex srcIndex = fwosm->index; // When object is dragged (moved) from one RE to // another, this should appear as single undo // command. Also, we should delete it first and insert // later so that we leave rule set view with the row // where it was inserted selected. FWCmdMacro* macro = new FWCmdMacro(tr("Move object")); deleteObject( srcIndex, dragobj, "move-delete "+QString::fromUtf8(dragobj->getName().c_str()), macro); insertObject( index, dragobj, "move-drop "+QString::fromUtf8(dragobj->getName().c_str()), macro); project->undoStack->push(macro); } } } QCoreApplication::postEvent( mw, new dataModifiedEvent(project->getFileName(), md->getRuleSet()->getId())); setCurrentIndex(index); ev->accept(); } void RuleSetView::deleteObject(QModelIndex index, libfwbuilder::FWObject *obj, QString text, QUndoCommand* macro) { RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value(); if (re==NULL || re->isAny()) return; int position = Rule::cast(re->getParent())->getPosition(); int column = index.column(); int number = getObjectNumber(obj, index); FWCmdRuleChangeRe* cmd = new FWCmdRuleChangeRe( project, ((RuleSetModel*)model())->getRuleSet(), re, position, column, number, text, macro); RuleElement *newRe = RuleElement::cast(cmd->getNewState()); newRe->removeRef(obj); if (newRe->isAny()) newRe->setNeg(false); if (macro == 0) project->undoStack->push(cmd); } bool RuleSetView::insertObject(QModelIndex index, FWObject *obj, QString text, QUndoCommand* macro) { RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value(); assert (re!=NULL); int position = Rule::cast(re->getParent())->getPosition(); int column = index.column(); int number = getObjectNumber(obj, index); FWCmdRuleChangeRe* cmd = new FWCmdRuleChangeRe( project, ((RuleSetModel*)model())->getRuleSet(), re, position, column, number, text, macro); RuleElement *newRe = RuleElement::cast(cmd->getNewState()); newRe->addRef(obj); if (macro == 0) project->undoStack->push(cmd); return true; } /* RuleElementItd::validateChild() accepts any Interface object. We * should apply additional restriction though: only interface of the * same firewall should be allowed. It turns out to be very hard to * implement this restriction in RuleElementItd::validateChild() * because when the operation is performed via redo(), the * RuleElementItf object we have to use is not part of the tree and * therefore does not have any parent firewall to compare with. */ bool RuleSetView::validateForInsertionToInterfaceRE(RuleElementItf *re, FWObject *obj) { return re->validateChild(obj) && re->checkItfChildOfThisFw(obj); } bool RuleSetView::validateForInsertion(QModelIndex index, FWObject *obj) { ColDesc colDesc = index.data(Qt::UserRole).value(); if (colDesc.type != ColDesc::Object && colDesc.type != ColDesc::Time) return false; RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value(); assert (re!=NULL); return validateForInsertion(re, obj); } bool RuleSetView::validateForInsertion(RuleElement *re, FWObject *obj, bool quiet) { if (RuleSet::cast(obj)!=NULL) return false; // see #1976 do not allow pasting object that has been deleted if (obj && obj->getLibrary()->getId() == FWObjectDatabase::DELETED_OBJECTS_ID) return false; if (! re->validateChild(obj) ) { if (!quiet) { if (RuleElementRItf::cast(re)) { QMessageBox::information( NULL , "Firewall Builder", QObject::tr( "A single interface belonging to this firewall is " "expected in this field."), QString::null,QString::null); } else if (RuleElementRGtw::cast(re)) { QMessageBox::information( NULL , "Firewall Builder", QObject::tr( "A single ip adress is expected here. You may also " "insert a host or a network adapter leading to a single " "ip adress."), QString::null,QString::null); } } return false; } if (re->getAnyElementId()==obj->getId()) return false; if ( !re->isAny()) { /* avoid duplicates */ int cp_id = obj->getId(); list::iterator j; for(j=re->begin(); j!=re->end(); ++j) { FWObject *o=*j; if(cp_id==o->getId()) return false; FWReference *ref; if( (ref=FWReference::cast(o))!=NULL && cp_id==ref->getPointerId()) return false; } } // This includes RuleElementItfInb and RuleElementItfOutb of nat rules if (RuleElementItf::cast(re) || RuleElementRItf::cast(re)) return validateForInsertionToInterfaceRE(RuleElementItf::cast(re), obj); return true; } /* Call validateForInsertion() before calling this function to make * sure @object can be inserted in the RE the @index points to. */ void RuleSetView::copyAndInsertObject(QModelIndex &index, FWObject *object) { if (!validateForInsertion(index, object)) return; RuleSetModel* md = ((RuleSetModel*)model()); bool need_to_reload_tree = false; if (md->getRuleSet()->getRoot()!=object->getRoot()) { // object is being copied from another project file FWObject *target = FWBTree().getStandardSlotForObject( md->getRuleSet()->getLibrary(), object->getTypeName().c_str()); map map_ids; object = project->db()->recursivelyCopySubtree(target, object, map_ids); need_to_reload_tree = true; } insertObject( index, object, "insert "+QString::fromUtf8(object->getName().c_str())); if (need_to_reload_tree) { project->m_panel->om->reload(); project->m_panel->om->openObjectInTree(object); // but still need to reopen this ruleset project->m_panel->om->openObjectInTree(md->getRuleSet()); } } void RuleSetView::dragMoveEvent( QDragMoveEvent *ev) { RuleSetModel* md = ((RuleSetModel*)model()); QWidget *fromWidget = ev->source(); // The source of DnD object must be the same instance of fwbuilder if (fromWidget) { if (ev->mimeData()->hasFormat(FWObjectDrag::FWB_MIME_TYPE) && !md->getRuleSet()->isReadOnly()) { if (ev->keyboardModifiers() & Qt::ControlModifier) ev->setDropAction(Qt::CopyAction); else ev->setDropAction(Qt::MoveAction); QModelIndex index = indexAt (ev->pos()); ColDesc colDesc = index.data(Qt::UserRole).value(); if (index.column()<0 || ( colDesc.type != ColDesc::Object && colDesc.type != ColDesc::Time) ) { ev->setAccepted(false); return; } RuleElement *re = getRE(index); if (re==NULL) { ev->setAccepted(false); return; } bool acceptE = true; list dragol; if (FWObjectDrag::decode(ev, dragol)) { for (list::iterator i=dragol.begin(); i!=dragol.end(); ++i) { FWObject *dragobj = NULL; dragobj = dynamic_cast(*i); if(dragobj!=NULL) { acceptE &= validateForInsertion(re, dragobj, true); } } ev->setAccepted( acceptE ); return; } } } ev->setAccepted(false); } void RuleSetView::unselect() { clearSelection(); setCurrentIndex(QModelIndex()); fwosm->setSelected(NULL, QModelIndex()); } FWObject* RuleSetView::getSelectedObject() { return fwosm->selectedObject; } void RuleSetView::saveCurrentRowColumn(SelectionMemento &memento) { RuleSetModel* md = ((RuleSetModel*)model()); QModelIndex index = fwosm->index; if (index.isValid()) { RuleNode* node = md->nodeFromIndex(index); if (node && node->rule) { memento.column = index.column(); FWObject *rule = node->rule; if (rule) memento.rule_id = node->rule->getId(); else memento.rule_id = -1; return; } } memento.column = -1; memento.rule_id = -1; } void RuleSetView::restoreCurrentRowColumn(SelectionMemento &memento) { if (memento.rule_id != -1) { RuleSetModel* md = ((RuleSetModel*)model()); Rule *rule = Rule::cast(project->db()->findInIndex(memento.rule_id)); QModelIndex index = md->index(rule, memento.column); selectRE(index); } } void RuleSetView::updateCurrentCell() { RuleSetModel* md = ((RuleSetModel*)model()); md->rowChanged(fwosm->index); updateColumnSizeForIndex(fwosm->index); } /* * looks like this method can be called when we print from the command * line. Variable project==NULL at that time. */ void RuleSetView::saveCollapsedGroups() { if (project) { QStringList collapsed_groups; QString filename = project->getRCS()->getFileName(); RuleSetModel* md = ((RuleSetModel*)model()); QList groups; md->getGroups(groups); foreach (QModelIndex index, groups) { if (!isExpanded(index)) { RuleNode* node = static_cast(index.internalPointer()); collapsed_groups.push_back(node->name); } } Firewall *f = md->getFirewall(); if (f) st->setCollapsedRuleGroups( filename, f->getName().c_str(), md->getRuleSet()->getName().c_str(), collapsed_groups); } } /* * looks like this method can be called when we print from the command * line. Variable project==NULL at that time. */ void RuleSetView::restoreCollapsedGroups() { if (project) { QTime t; t.start(); RuleSetModel* md = ((RuleSetModel*)model()); QStringList collapsed_groups; QString filename; filename = project->getRCS()->getFileName(); if (fwbdebug) qDebug("restoreCollapsedGroups begin: %d ms", t.restart()); Firewall *f = md->getFirewall(); if (f) st->getCollapsedRuleGroups( filename, f->getName().c_str(), md->getRuleSet()->getName().c_str(), collapsed_groups); if (fwbdebug) qDebug("restoreCollapsedGroups getCollapsedRuleGroups: %d ms", t.restart()); QList groups; md->getGroups(groups); if (fwbdebug) { qDebug("restoreCollapsedGroups getGroups: %d ms", t.restart()); qDebug() << "Groups:" << groups.size(); } foreach (QModelIndex index, groups) { RuleNode* node = static_cast(index.internalPointer()); setExpanded(index, !collapsed_groups.contains(node->name) ); } if (fwbdebug) qDebug("restoreCollapsedGroups foreach setExpanded: %d ms", t.restart()); } } int RuleSetView::rowHeight(const QModelIndex& index) const { return QTreeView::rowHeight(index); } void RuleSetView::updateWidget() { updateGeometries(); } bool RuleSetView::showToolTip(QEvent *event) { if (!st->getObjTooltips()) return true; QHelpEvent *he = (QHelpEvent*) event; QPoint pos = viewport()->mapFromGlobal(he->globalPos()); QString toolTip=""; QModelIndex index = indexAt(pos); if (!index.isValid()) { if (st->getBool("UI/AdvancedTooltips")) return false; toolTip = QObject::tr( "" "Policy, NAT and routing rules are shown here. " "
  • Rules use objects, if you want " "to use an object like IP address in a rule, " "you need to first create it in the object tree
  • " "
  • Drag and drop objects from the tree to " "the desired field (source, destination, etc.) in " "the rule.
  • " "
  • To add a rule, click the '+' button at " "the top of the window
  • " "
  • To open menu of operations such as " "'add rule', 'remove rule' etc, click right mouse button
  • " "
"); QToolTip::showText(mapToGlobal( he->pos() ), toolTip, this); return true; } RuleSetModel* md = ((RuleSetModel*)model()); RuleNode *node = md->nodeFromIndex(index); int column = index.column(); if (node->type == RuleNode::Rule) { QVariant v = index.data(Qt::DisplayRole); ColDesc colDesc = index.data(Qt::UserRole).value(); if (column == 0) { if (st->getBool("UI/AdvancedTooltips")) return false; // rule number column toolTip = QObject::tr( "" "To open menu of operations such as 'add rule', " "'remove rule' etc, click right mouse button.
" "To compile the rule and see generated firewall " "configuration, first select it by clicking inside of it " "and then hit 'X' on keyboard html>"); QToolTip::showText(mapToGlobal( he->pos() ), toolTip, this); return true; } else { switch (colDesc.type) { case ColDesc::Comment: if (!st->getClipComment()) return false; toolTip = v.value(); break; case ColDesc::Options: { Rule* rule = node->rule; if (PolicyRule::cast(rule)!=NULL ) { // if (!isDefaultPolicyRuleOptions(rule->getOptionsObject())) toolTip = FWObjectPropertiesFactory::getPolicyRuleOptions(rule); } if (NATRule::cast(rule)!=NULL ) { // if (!isDefaultNATRuleOptions( rule->getOptionsObject())) toolTip = FWObjectPropertiesFactory::getNATRuleOptions(rule); } } break; case ColDesc::Direction: if (st->getBool("UI/AdvancedTooltips")) { toolTip = QObject::tr("Direction: %1
") .arg(v.value()); } else { toolTip = QObject::tr("Direction: %1
" "To change the direction, " "click right mouse button to open " "the list of possible settings") .arg(v.value()); } break; case ColDesc::Action: if (st->getBool("UI/AdvancedTooltips")) { toolTip = v.value().tooltip; } else { toolTip = QObject::tr("%1 To change the action, " "click right mouse button to open " "the list of possible settings") .arg(v.value().tooltip); } break; default: FWObject *object = getObject(pos, index); if (object == 0) return true; toolTip = FWObjectPropertiesFactory::getObjectPropertiesDetailed( object, true, true); if (st->getBool("UI/AdvancedTooltips")) { if (object->getId() == FWObjectDatabase::ANY_ADDRESS_ID || object->getId() == FWObjectDatabase::ANY_SERVICE_ID || object->getId() == FWObjectDatabase::ANY_INTERVAL_ID) return false; } } } } else { toolTip = node->name; } if (toolTip.isEmpty()) { QToolTip::hideText(); return true; } if (fwbdebug) qDebug() << "Toolip: " << toolTip; QRect cr = visualRect(index); cr = QRect(cr.left() - horizontalOffset() - 2, cr.top() - verticalOffset() - 2, cr.width() + 4, cr.height() + 4); QRect global = QRect( viewport()->mapToGlobal(cr.topLeft()), viewport()->mapToGlobal(cr.bottomRight())); QToolTip::showText(mapToGlobal( he->pos() ), toolTip, this, global); return true; } bool RuleSetView::event( QEvent * event ) { if (event->type() == QEvent::ToolTip) { return showToolTip(event); } return QTreeView::event(event); } void RuleSetView::resizeColumns() { header()->resizeSections(QHeaderView::ResizeToContents); } void RuleSetView::updateAllColumnsSize() { resizeColumns(); } void RuleSetView::updateColumnSizeForIndex(QModelIndex index) { ((RuleSetModel*)model())->nodeFromIndex(index)->resetSizes(); //TODO: update only corresponding column resizeColumns(); } void RuleSetView::setModel(QAbstractItemModel *model) { connect (model, SIGNAL (dataChanged(QModelIndex,QModelIndex)), this, SLOT (updateAllColumnsSize())); connect (model, SIGNAL (layoutChanged()), this, SLOT (updateAllColumnsSize())); QTreeView::setModel(model); connect (selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateSelectionSensitiveActions())); } void RuleSetView::repaintSelection() { QModelIndex index = currentIndex(); fwosm->setSelected(project->getSelectedObject(), index); viewport()->update((viewport()->rect())); } void RuleSetView::updateAll() { // May be it needs to invalidate all precalculated sizes. ((RuleSetModel*)model())->resetAllSizes(); viewport()->update((viewport()->rect())); updateAllColumnsSize(); } RuleElement* RuleSetView::getRE(QModelIndex index) { return (RuleElement *)index.data(Qt::DisplayRole).value(); } void RuleSetView::keyPressEvent( QKeyEvent* ev ) { RuleSetModel* md = ((RuleSetModel*)model()); if (md->getFirewall()==NULL) return; project->selectRules(); RuleElement *re; QModelIndex oldIndex = fwosm->index; int objno = getObjectNumber(fwosm->selectedObject, oldIndex); if (ev->key()==Qt::Key_Left || ev->key()==Qt::Key_Right) { int shift= (ev->key()==Qt::Key_Left) ? -1 : 1; int newColumn = oldIndex.column() + shift; if ((newColumn <= 0) || (newColumn > md->header.size())) return; /* keyboard 'Left' or 'Right', switch to the object with the same * number in the cell to the left or to the right */ QModelIndex newIndex = md->index(oldIndex.row(), newColumn, oldIndex.parent()); re = getRE(newIndex); if (re==NULL) { fwosm->setSelected(NULL, newIndex); setCurrentIndex(newIndex); return; } FWObject *newObj = getObject(objno, newIndex); selectObject(newObj, newIndex); return; } if (ev->key()==Qt::Key_PageDown || ev->key()==Qt::Key_PageUp || ev->key()==Qt::Key_End || ev->key()==Qt::Key_Home) { QTreeView::keyPressEvent(ev); QModelIndex newIndex = md->index(currentIndex().row(), oldIndex.column(), currentIndex().parent()); re = getRE(newIndex); FWObject *object = NULL; if (re != NULL) { object = FWReference::getObject(re->front()); selectObject(object, newIndex); } else { fwosm->setSelected(NULL, newIndex); setCurrentIndex(newIndex); } return; } if (ev->key()==Qt::Key_Down || ev->key()==Qt::Key_Up) { re = getRE(oldIndex); FWObject *object = md->getFirewall(); QModelIndex newIndex = oldIndex; FWObject::iterator i; if (re == NULL && !md->isGroup(oldIndex)) { // Non-object column. Just move focus up or down; QTreeView::keyPressEvent(ev); newIndex = md->index(currentIndex().row(), oldIndex.column(), currentIndex().parent()); if (!md->isGroup(newIndex)) { selectionModel()->select( newIndex, QItemSelectionModel::Rows | QItemSelectionModel::Select); setCurrentIndex(newIndex); fwosm->setSelected(NULL, newIndex); ev->accept(); } return; } else { if (md->isGroup(oldIndex)) { object = NULL; } else { FWObject *prev = NULL; for (i=re->begin(); i!=re->end(); ++i) { object = FWReference::getObject(*i); if (ev->key()==Qt::Key_Up && object==fwosm->selectedObject) break; if (ev->key()==Qt::Key_Down && prev==fwosm->selectedObject) break; prev = object; } if (ev->key()==Qt::Key_Up) object = prev; if (ev->key()==Qt::Key_Down && i == re->end()) object = NULL; } if (object == NULL) { // It needs to move to another row QTreeView::keyPressEvent(ev); newIndex = md->index(currentIndex().row(), oldIndex.column(), currentIndex().parent()); selectionModel()->select( newIndex, QItemSelectionModel::Rows | QItemSelectionModel::Select); if (oldIndex.row() == newIndex.row()) { // we are stuck! It's very first or last row. object = fwosm->selectedObject; } else { re = getRE(newIndex); if (re != NULL) { // NOT a group if (ev->key()==Qt::Key_Up) { i = re->end(); --i; } else { i = re->begin(); } object = FWReference::getObject(*i); } else { if (!md->isGroup(newIndex)) { setCurrentIndex(newIndex); fwosm->setSelected(NULL, newIndex); ev->accept(); return; } object = md->getFirewall(); } } } else { // select other object in current cell } } selectObject(object, newIndex); ev->accept(); return; } if (ev->key()==Qt::Key_Delete) { deleteSelectedObject(); } if (ev->key()==Qt::Key_Enter || ev->key()==Qt::Key_Return) { editSelected(); } QTreeView::keyPressEvent(ev); } void RuleSetView::compileCurrentRule() { RuleSetModel* md = ((RuleSetModel*)model()); //if (!isTreeReadWrite(this, md->getRuleSet())) return; if (md->getFirewall()==NULL) return; QModelIndex index = currentIndex(); if (!index.isValid()) return; RuleNode* node = static_cast(index.internalPointer()); if (node == 0 || node->type != RuleNode::Rule || node->rule == 0) return; mw->singleRuleCompile(node->rule); } void RuleSetView::updateSelectionSensitiveActions() { // qDebug() << "RuleSetView::updateSelectionSensitiveActions(QItemSelection selected,QItemSelection deselected)"; RuleSetModel* md = ((RuleSetModel*)model()); QModelIndexList selectedIndexes = getSelectedRows(); bool compileRuleActionEnabled = false; int selectionSize = selectedIndexes.size(); if (selectionSize==1) { QModelIndex index = selectedIndexes.at(0); if (index.isValid()) { RuleNode* node = md->nodeFromIndex(index); if (node!=0 && node->type == RuleNode::Rule && node->rule != 0) { compileRuleActionEnabled = !node->rule->isDisabled(); } } } compileRuleAction->setEnabled(compileRuleActionEnabled); if (selectionSize == 0) { setActionState(removeFromGroupAction, false); setActionState(newGroupAction, false); setActionState(moveRuleUpAction, false); setActionState(moveRuleDownAction, false); setActionState(addToGroupAboveAction, false); setActionState(addToGroupBelowAction, false); setActionState(insertRuleAction, false); setActionState(addRuleAfterCurrentAction, false); setActionState(removeRuleAction, false); setActionState(disableRuleAction, false); setActionState(enableRuleAction, false); setActionState(copyRuleAction, false); setActionState(cutRuleAction, false); setActionState(pasteRuleAboveAction, false); setActionState(pasteRuleBelowAction, false); setColorEmptyAction->setEnabled(false); setColorRedAction->setEnabled(false); setColorBlueAction->setEnabled(false); setColorOrangeAction->setEnabled(false); setColorPurpleAction->setEnabled(false); setColorGrayAction->setEnabled(false); setColorYellowAction->setEnabled(false); setColorGreenAction->setEnabled(false); } else { bool inGroup = true; bool outermost = false; bool topLevelOnly = true; int disabled = 0; int enabled = 0; foreach(QModelIndex index, selectedIndexes) { if (index.isValid()) { RuleNode* node = md->nodeFromIndex(index); topLevelOnly = topLevelOnly && (node->type == RuleNode::Rule); if (node!=0 && node->type == RuleNode::Rule && node->rule != 0) { bool isInGroup = node->isInGroup(); inGroup = inGroup && isInGroup; topLevelOnly = topLevelOnly && !isInGroup; outermost = outermost || (node->isOutermost() && isInGroup); Rule *r = node->rule; if (r->isDisabled()) disabled++; else enabled++; } } } setActionState(disableRuleAction, enabled > 0); setActionState(enableRuleAction, disabled > 0); enableRuleAction->setText( (disabled==1)?tr("Enable Rule"):tr("Enable Rules")); disableRuleAction->setText( (enabled==1)?tr("Disable Rule"):tr("Disable Rules")); if (selectionSize > 1) { copyRuleAction->setText(tr("Copy Rules")); cutRuleAction->setText(tr("Cut Rules")); moveRuleUpAction->setText(tr("Move Rules Up")); moveRuleDownAction->setText(tr("Move Rules Down")); removeRuleAction->setText(tr("Remove Rules")); } else { copyRuleAction->setText(tr("Copy Rule")); cutRuleAction->setText(tr("Cut Rule")); moveRuleUpAction->setText(tr("Move Rule Up")); moveRuleDownAction->setText(tr("Move Rule Down")); removeRuleAction->setText(tr("Remove Rule")); } if (topLevelOnly) { QString addToGroupLabel = tr("Add To the Group "); QString nn; nn = md->nodeFromIndex(selectedIndexes.first())->nameOfPredecessorGroup(); if (!nn.isEmpty()) { addToGroupAboveAction->setText(addToGroupLabel + nn); setActionState(addToGroupAboveAction, true); } else { setActionState(addToGroupAboveAction, false); } nn = md->nodeFromIndex(selectedIndexes.last())->nameOfSuccessorGroup(); if (!nn.isEmpty()) { addToGroupBelowAction->setText(addToGroupLabel + nn); setActionState(addToGroupBelowAction, true); } else { setActionState(addToGroupBelowAction, false); } } else { setActionState(addToGroupAboveAction, false); setActionState(addToGroupBelowAction, false); } setActionState(removeFromGroupAction, outermost); setActionState(newGroupAction, topLevelOnly); setActionState(moveRuleUpAction, true); setActionState(moveRuleDownAction, true); setActionState(insertRuleAction, true); setActionState(addRuleAfterCurrentAction, true); setActionState(removeRuleAction, true); setActionState(copyRuleAction, true); setActionState(cutRuleAction, true); setActionState(pasteRuleAboveAction, true); setActionState(pasteRuleBelowAction, true); setColorEmptyAction->setEnabled(true); setColorRedAction->setEnabled(true); setColorBlueAction->setEnabled(true); setColorOrangeAction->setEnabled(true); setColorPurpleAction->setEnabled(true); setColorGrayAction->setEnabled(true); setColorYellowAction->setEnabled(true); setColorGreenAction->setEnabled(true); } } void RuleSetView::updateObject(FWObject* object) { RuleSetModel* md = ((RuleSetModel*)model()); md->objectChanged(object); } void RuleSetView::setActionState(QAction *action, bool state) { action->setEnabled(state); action->setVisible(state); } //////////////////////////////////////////////////////////////////////////// // PolicyView //////////////////////////////////////////////////////////////////////////// PolicyView::PolicyView(ProjectPanel *project, Policy *p, QWidget *parent):RuleSetView(project, parent) { QItemSelectionModel *sm = QTreeView::selectionModel(); RuleSetModel* model = new PolicyModel(p,this); setModel(model); delete sm; RuleSetViewDelegate *dlgt = new RuleSetViewDelegate(this, fwosm); dlgt->setStandardHighlightColor(palette().color(QPalette::Highlight)); setItemDelegate(dlgt); init(); } //////////////////////////////////////////////////////////////////////////// // NATView //////////////////////////////////////////////////////////////////////////// NATView::NATView(ProjectPanel *project, NAT *p, QWidget *parent):RuleSetView(project, parent) { QItemSelectionModel *sm = QTreeView::selectionModel(); RuleSetModel* model = new NatModel(p,this); setModel(model); delete sm; RuleSetViewDelegate *dlgt = new RuleSetViewDelegate(this, fwosm); dlgt->setStandardHighlightColor(palette().color(QPalette::Highlight)); setItemDelegate(dlgt); init(); } //////////////////////////////////////////////////////////////////////////// // RoutingView //////////////////////////////////////////////////////////////////////////// RoutingView::RoutingView(ProjectPanel *project, Routing *p, QWidget *parent):RuleSetView(project, parent) { QItemSelectionModel *sm = QTreeView::selectionModel(); RuleSetModel* model = new RoutingModel(p,this); setModel(model); delete sm; RuleSetViewDelegate *dlgt = new RuleSetViewDelegate(this, fwosm); dlgt->setStandardHighlightColor(palette().color(QPalette::Highlight)); setItemDelegate(dlgt); init(); }