1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-19 01:37:17 +01:00
fwbuilder/src/libgui/RuleSetView.cpp
Vadim Kurland ddd45fb426 fixes #2566, #2618 Fix for the regression introduced when I worked on
empty editor pane".  Double click on the rule number should not do
anything, but double click on rule options, comment and other fields
should open the editor. Change done for #2566 broke this.
2011-07-20 23:39:11 -07:00

3196 lines
98 KiB
C++

/*
Firewall Builder
Copyright (C) 2003-2009 NetCitadel, LLC
Author: Illiya Yalovoy <yalovoy@gmail.com>
$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 <memory>
#include <QtDebug>
#include <QMouseEvent>
#include <QtAlgorithms>
#include <QInputDialog>
#include <QMessageBox>
#include <QHeaderView>
#include <QTime>
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<QModelIndex> 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<RuleNode *>(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<FWObject*> 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<ColDesc>();
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<ColDesc>();
// 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<ColDesc>();
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<ColDesc>();
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<QModelIndex>::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<QModelIndex,QList<int> > itemsInGroups;
QList<Rule*> 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<QModelIndex> 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<QModelIndex> rules;
QList<QModelIndex> groups;
foreach (QModelIndex index, selection)
{
if (md->isIndexRule(index))
{
rules << index;
}
else
{
groups << index;
}
}
QList<Rule*> 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<RuleNode *>(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<RuleNode *>(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<std::pair<int,ProjectPanel*> >::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<std::pair<int,ProjectPanel*> >::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<int,int> 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<QModelIndex,QList<int> > 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<QModelIndex> groups = itemsInGroups.keys();
qSort(groups);
QListIterator<QModelIndex> 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<RuleNode *>(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<oy+itemHeight)
{
obj=o1;
break;
}
oy+=itemHeight;
prev=o1;
}
if (obj==NULL) obj=prev;
return obj;
}
FWObject *RuleSetView::getObject(int number, const QModelIndex &index)
{
if (!index.isValid() || index.column() == 0) return 0;
RuleNode* node = static_cast<RuleNode *>(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<RuleNode *>(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<FWCmdRuleChange> cmd(
new FWCmdRuleChange(project,
md->getRuleSet(), node->rule, tr("Change action")));
Rule* newRule = dynamic_cast<Rule*>(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<std::pair<int,ProjectPanel*> >::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<FWObject*> dragol;
if (!FWObjectDrag::decode(ev, dragol)) return;
for (list<FWObject*>::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<void *>();
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<void *>();
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<ColDesc>();
if (colDesc.type != ColDesc::Object && colDesc.type != ColDesc::Time)
return false;
RuleElement *re = (RuleElement *)index.data(Qt::DisplayRole).value<void *>();
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<FWObject*>::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<int,int> 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<ColDesc>();
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<FWObject*> dragol;
if (FWObjectDrag::decode(ev, dragol))
{
for (list<FWObject*>::iterator i=dragol.begin();
i!=dragol.end(); ++i)
{
FWObject *dragobj = NULL;
dragobj = dynamic_cast<FWObject*>(*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<QModelIndex> groups;
md->getGroups(groups);
foreach (QModelIndex index, groups)
{
if (!isExpanded(index))
{
RuleNode* node = static_cast<RuleNode *>(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<QModelIndex> 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<RuleNode *>(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(
"<html>"
"Policy, NAT and routing rules are shown here. "
"<ul><li><b>Rules use objects</b>, if you want "
"to use an object like IP address in a rule, "
"you need to first create it in the object tree</li>"
"<li><b>Drag and drop</b> objects from the tree to "
"the desired field (source, destination, etc.) in "
"the rule.</li>"
"<li><b>To add a rule</b>, click the '+' button at "
"the top of the window</li>"
"<li><b>To open menu of operations</b> such as "
"'add rule', 'remove rule' etc, click right mouse button</li>"
"</ul></html>");
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<ColDesc>();
if (column == 0)
{
if (st->getBool("UI/AdvancedTooltips")) return false;
// rule number column
toolTip = QObject::tr(
"<html>"
"<b>To open menu of operations</b> such as 'add rule', "
"'remove rule' etc, click right mouse button.<br> "
"<b>To compile the rule</b> 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<QString>();
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("<b>Direction:</b> %1 <br>")
.arg(v.value<QString>());
} else
{
toolTip = QObject::tr("<b>Direction:</b> %1 <br>"
"<b>To change the direction</b>, "
"click right mouse button to open "
"the list of possible settings")
.arg(v.value<QString>());
}
break;
case ColDesc::Action:
if (st->getBool("UI/AdvancedTooltips"))
{
toolTip = v.value<ActionDesc>().tooltip;
} else
{
toolTip = QObject::tr("%1 <b>To change the action</b>, "
"click right mouse button to open "
"the list of possible settings")
.arg(v.value<ActionDesc>().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 *>();
}
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<RuleNode *>(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();
}