From 7527dc11232d3bbe9163f40ef72b4eeef04fe29a Mon Sep 17 00:00:00 2001 From: Sirius Bakke Date: Fri, 5 Jul 2013 16:03:14 +0200 Subject: [PATCH] Feature: Diff for rule sets and generated files A new GUI diff viewer displaying changes done in rule sets, and an external diff application may be configured to show difference between generated files. An autocompile option will compile firewalls when loading file. --- src/gui/main.cpp | 3 + src/libgui/BackgroundCompileInfoWidget.cpp | 61 +++ src/libgui/BackgroundCompileInfoWidget.h | 48 +++ src/libgui/FWBSettings.cpp | 60 +++ src/libgui/FWBSettings.h | 16 +- src/libgui/FWCmdBasic.cpp | 114 ++++++ src/libgui/FWCmdBasic.h | 13 + src/libgui/FWCmdMoveObject.cpp | 5 + src/libgui/FWCmdRule.cpp | 56 ++- src/libgui/FWCmdRule.h | 4 +- src/libgui/FWWindow.cpp | 31 +- src/libgui/FWWindow.h | 6 + src/libgui/FirewallCodeViewer.cpp | 112 +++++- src/libgui/FirewallCodeViewer.h | 18 +- src/libgui/FirewallCodeViewer.ui | 37 +- src/libgui/PrefsDialog.cpp | 81 +++- src/libgui/PrefsDialog.h | 7 + src/libgui/ProjectPanel.cpp | 39 +- src/libgui/ProjectPanel.h | 32 +- src/libgui/ProjectPanel_file_ops.cpp | 15 + src/libgui/RuleSetDiffDelegate.cpp | 75 ++++ src/libgui/RuleSetDiffDelegate.h | 44 ++ src/libgui/RuleSetDiffDialog.cpp | 350 ++++++++++++++++ src/libgui/RuleSetDiffDialog.h | 80 ++++ src/libgui/RuleSetDiffModel.cpp | 63 +++ src/libgui/RuleSetDiffModel.h | 48 +++ src/libgui/RuleSetViewDelegate.cpp | 9 +- src/libgui/RuleSetViewDelegate.h | 2 + src/libgui/instDialog.cpp | 34 +- src/libgui/instDialog.h | 6 + src/libgui/instDialog_compile.cpp | 16 +- src/libgui/libgui.pro | 13 +- src/libgui/prefsdialog_q.ui | 379 ++++++++++++++++-- src/libgui/projectpanel_q.ui | 90 ++++- src/libgui/rulesetdiffdialog_q.ui | 443 +++++++++++++++++++++ src/libgui/temporarydir.cpp | 307 ++++++++++++++ src/libgui/temporarydir.h | 74 ++++ 37 files changed, 2715 insertions(+), 76 deletions(-) create mode 100644 src/libgui/BackgroundCompileInfoWidget.cpp create mode 100644 src/libgui/BackgroundCompileInfoWidget.h create mode 100644 src/libgui/RuleSetDiffDelegate.cpp create mode 100644 src/libgui/RuleSetDiffDelegate.h create mode 100644 src/libgui/RuleSetDiffDialog.cpp create mode 100644 src/libgui/RuleSetDiffDialog.h create mode 100644 src/libgui/RuleSetDiffModel.cpp create mode 100644 src/libgui/RuleSetDiffModel.h create mode 100644 src/libgui/rulesetdiffdialog_q.ui create mode 100644 src/libgui/temporarydir.cpp create mode 100644 src/libgui/temporarydir.h diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 1e7e12248..f2460c47c 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -280,6 +280,9 @@ int main( int argc, char *argv[] ) res.clear(); XMLTools::close(); + + // We need to call FWWindow::~FWWindow() to remove temporary directory + delete mw; } diff --git a/src/libgui/BackgroundCompileInfoWidget.cpp b/src/libgui/BackgroundCompileInfoWidget.cpp new file mode 100644 index 000000000..a3dd42807 --- /dev/null +++ b/src/libgui/BackgroundCompileInfoWidget.cpp @@ -0,0 +1,61 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + This program is free software which we release under the GNU General Public + License. You may redistribute and/or modify this program under the terms + of that license as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + To get a copy of the GNU General Public License, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include +#include + +#include "instDialog.h" +#include "FWWindow.h" +#include "BackgroundCompileInfoWidget.h" + +BackgroundCompileInfoWidget::BackgroundCompileInfoWidget(QWidget *parent, instDialog *instDialog, FWWindow *fwwindow) : + QWidget(parent), m_fwwindow(fwwindow) +{ + connect(instDialog, SIGNAL(autoCompileDone()), this, SLOT(autoCompileIsDone())); + + m_label = new QLabel(tr("Compiling firewalls in background: ")); + m_label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + m_progressBar = new QProgressBar(); + m_progressBar->setMaximumWidth(100); + m_progressBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + QHBoxLayout *hboxlayout = new QHBoxLayout(); + hboxlayout->setSpacing(0); + hboxlayout->setMargin(0); + hboxlayout->addWidget(m_label); + hboxlayout->addWidget(m_progressBar); + setLayout(hboxlayout); + + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + + connect(instDialog, SIGNAL(currentFirewallsBarMaximumValueChanged(int)), m_progressBar, SLOT(setMaximum(int))); + connect(instDialog, SIGNAL(currentFirewallsBarvalueChanged(int)), m_progressBar, SLOT(setValue(int))); + + m_fwwindow->statusBar()->addPermanentWidget(this); +} + +void BackgroundCompileInfoWidget::autoCompileIsDone() +{ + m_fwwindow->statusBar()->removeWidget(this); + deleteLater(); +} diff --git a/src/libgui/BackgroundCompileInfoWidget.h b/src/libgui/BackgroundCompileInfoWidget.h new file mode 100644 index 000000000..414839c6f --- /dev/null +++ b/src/libgui/BackgroundCompileInfoWidget.h @@ -0,0 +1,48 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + 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 + +*/ + +#ifndef BACKGROUNDCOMPILEINFOWIDGET_H +#define BACKGROUNDCOMPILEINFOWIDGET_H + +#include + +class instDialog; +class FWWindow; +class QProgressBar; +class QLabel; + +class BackgroundCompileInfoWidget : public QWidget +{ + Q_OBJECT +public: + BackgroundCompileInfoWidget(QWidget *parent, instDialog *instDialog, FWWindow *fwwindow); +private: + FWWindow *m_fwwindow; + QProgressBar *m_progressBar; + QLabel *m_label; +public slots: + void autoCompileIsDone(); + +}; + +#endif // BACKGROUNDCOMPILEINFOWIDGET_H diff --git a/src/libgui/FWBSettings.cpp b/src/libgui/FWBSettings.cpp index bbc8a9670..c8f37ee28 100644 --- a/src/libgui/FWBSettings.cpp +++ b/src/libgui/FWBSettings.cpp @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -75,6 +80,7 @@ const char* startupActionSetpath = SETTINGS_PATH_PREFIX "/Environment/StartupAction"; const char* labelColorPath = SETTINGS_PATH_PREFIX "/ColorLabels/color_"; const char* labelTextPath = SETTINGS_PATH_PREFIX "/ColorLabels/text_"; +const char* diffColorPath = SETTINGS_PATH_PREFIX "/Diff/color_"; const char* lastEditedSetpath = SETTINGS_PATH_PREFIX "/Environment/LastEdited"; const char* autoSave = SETTINGS_PATH_PREFIX "/Environment/autoSave"; const char* expandTreeSetpath = SETTINGS_PATH_PREFIX "/UI/ExpandTree"; @@ -126,6 +132,7 @@ const char* startsCounter = SETTINGS_PATH_PREFIX "/startsCounter"; const char* targetStatus = SETTINGS_PATH_PREFIX "/TargetStatus/"; const char* SSHPath = SETTINGS_PATH_PREFIX "/SSH/SSHPath"; const char* SCPPath = SETTINGS_PATH_PREFIX "/SSH/SCPPath"; +const char* DiffPath = SETTINGS_PATH_PREFIX "/Diff/DiffPath"; const char* appGUID = "/fwbuilder_gui/ApplicationGUID"; const char* appGUID_4_0 = "/4.0/ApplicationGUID"; @@ -137,6 +144,8 @@ const char* SSHTimeout = "Sessions/fwb_session_with_keepalive/PingIntervalSecs"; const char* SSHTimeout = SETTINGS_PATH_PREFIX "/SSH/SSHTimeout"; #endif +const char * displayUnmodifiedRules = SETTINGS_PATH_PREFIX "/Diff/displayUnmodifiedRules"; + /** * Settings path defined here should match Windows registry paths used @@ -338,6 +347,15 @@ void FWBSettings::init(bool force_first_time_run) if (getLabelColor(GRAY ).isEmpty()) { setLabelColor(GRAY ,"#C0C0C0"); setLabelText(GRAY ,"Gray"); } + if (getDiffColor(ADD_COLOR).isEmpty()) + { setDiffColor(ADD_COLOR,"#8BC065"); } + if (getDiffColor(EDIT_COLOR).isEmpty()) + { setDiffColor(EDIT_COLOR,"#7694C0"); } + if (getDiffColor(MOVE_COLOR).isEmpty()) + { setDiffColor(MOVE_COLOR,"#C0C0C0"); } + if (getDiffColor(REMOVE_COLOR).isEmpty()) + { setDiffColor(REMOVE_COLOR,"#C86E6E"); } + ok = contains(showIconsInRules); if (!ok) setShowIconsInRules(true); @@ -779,6 +797,18 @@ QString FWBSettings::getLabelColorStr(enum LabelColors c) } } +QString FWBSettings::getDiffColorStr(enum LabelColors c) +{ + switch (c) + { + case ADD_COLOR: return "add"; + case EDIT_COLOR: return "edit"; + case MOVE_COLOR: return "move"; + case REMOVE_COLOR: return "remove"; + default: return "default"; + } +} + QString FWBSettings::getLabelColor(enum LabelColors c) { return value(QString(labelColorPath) + getLabelColorStr(c)).toString(); @@ -799,6 +829,16 @@ void FWBSettings::setLabelText(enum LabelColors c, const QString &s) setValue(QString(labelTextPath) + getLabelColorStr(c),s); } +QString FWBSettings::getDiffColor(FWBSettings::LabelColors c) +{ + return value(QString(diffColorPath) + getDiffColorStr(c)).toString(); +} + +void FWBSettings::setDiffColor(FWBSettings::LabelColors c, const QString &s) +{ + setValue(QString(diffColorPath) + getDiffColorStr(c), s); +} + QString FWBSettings::getSSHPath() { return value(SSHPath).toString(); @@ -819,6 +859,16 @@ void FWBSettings::setSCPPath(const QString &path) setValue(SCPPath,path); } +QString FWBSettings::getDiffPath() +{ + return value(DiffPath).toString(); +} + +void FWBSettings::setDiffPath(const QString &path) +{ + setValue(DiffPath,path); +} + // Putty uses different parameter name for the server alive interval // and keeps it as part of the session, stored in registry. Using // separate QSettings object on windows that controls putty session @@ -1237,3 +1287,13 @@ void FWBSettings::setCustomTemplatesEnabled(bool f) { setValue(customTemplatesEn, f); } + +bool FWBSettings::getDisplayUnmodifiedRules() +{ + return value(displayUnmodifiedRules).toBool(); +} + +void FWBSettings::setDisplayUnmodifiedRules(bool f) +{ + setValue(displayUnmodifiedRules, f); +} diff --git a/src/libgui/FWBSettings.h b/src/libgui/FWBSettings.h index 8b42932cf..518eb7e1a 100644 --- a/src/libgui/FWBSettings.h +++ b/src/libgui/FWBSettings.h @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -54,7 +59,7 @@ class FWBSettings : public QSettings { public: - enum LabelColors { RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, GRAY }; + enum LabelColors { RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, GRAY, ADD_COLOR, EDIT_COLOR, MOVE_COLOR, REMOVE_COLOR }; enum IconSize{ SIZE25X25, SIZE16X16}; private: @@ -63,6 +68,7 @@ class FWBSettings : public QSettings bool first_run; QString getLabelColorStr(enum LabelColors c); + QString getDiffColorStr(enum LabelColors c); public: @@ -164,6 +170,8 @@ class FWBSettings : public QSettings void setLabelColor(enum LabelColors c,const QString &s); QString getLabelText(enum LabelColors c); void setLabelText(enum LabelColors c, const QString &s); + QString getDiffColor(enum LabelColors c); + void setDiffColor(enum LabelColors c,const QString &s); QString getSSHPath(); void setSSHPath(const QString &path); @@ -171,6 +179,9 @@ class FWBSettings : public QSettings QString getSCPPath(); void setSCPPath(const QString &path); + QString getDiffPath(); + void setDiffPath(const QString &path); + bool haveSSHTimeout(); int getSSHTimeout(); void setSSHTimeout(int value_sec); @@ -280,6 +291,9 @@ class FWBSettings : public QSettings bool customTemplatesEnabled(); void setCustomTemplatesEnabled(bool f); + + bool getDisplayUnmodifiedRules(); + void setDisplayUnmodifiedRules(bool); private: QFont getFontByType(const char*type); diff --git a/src/libgui/FWCmdBasic.cpp b/src/libgui/FWCmdBasic.cpp index eadf576b6..31174b3ff 100644 --- a/src/libgui/FWCmdBasic.cpp +++ b/src/libgui/FWCmdBasic.cpp @@ -6,6 +6,11 @@ Author: Illiya Yalovoy + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -25,10 +30,17 @@ #include "global.h" #include "FWCmdBasic.h" +#include "fwbuilder/Rule.h" +#include "fwbuilder/RuleSet.h" +#include "fwbuilder/Policy.h" +#include "fwbuilder/NAT.h" +#include "fwbuilder/Routing.h" +#include "fwbuilder/Firewall.h" #include using namespace libfwbuilder; +#include "FWCmdRule.h" FWCmdBasic::FWCmdBasic(ProjectPanel *project, QUndoCommand* macro):QUndoCommand(macro) { @@ -84,3 +96,105 @@ void undoAndRemoveLastCommand(QUndoStack* undoStack) undoStack->push(cmd); } } + +void FWCmdBasic::setDiffType(Rule *rule, DiffType::Type diffType) +{ + if (!rule) return; + + DiffType::Type origDiffType = static_cast(project->getDiffType(rule->getId())); + m_diffLog.insert(rule->getId(), origDiffType); + + addStatistics(rule, diffType, origDiffType); + + // If we do changes to an inserted rule, we ignore that + // We want to know that we added a rule. + // Exception: if we remove it ... + // If we move an edited rule, we ignore that too :) + if (((origDiffType == DiffType::Add) && (diffType != DiffType::Remove)) + || ((origDiffType == DiffType::Edit) && (diffType == DiffType::Move))) { + + diffType = origDiffType; + } + + project->setDiffType(rule->getId(), diffType); +} + +void FWCmdBasic::resetDiffType(Rule *rule) +{ + if (!rule) return; + + DiffType::Type currentDiffType = static_cast(project->getDiffType(rule->getId())); + DiffType::Type origDiffType = static_cast(m_diffLog.value(rule->getId())); + removeStatistics(rule, currentDiffType, origDiffType); + project->setDiffType(rule->getId(), origDiffType); +} + +void FWCmdBasic::addStatistics(Rule *rule, DiffType::Type diffType, DiffType::Type origDiffType) +{ + foreach (Firewall *fw, UsageResolver().findFirewallsForObject(rule, project->db())) { + std::list rulesets; + rulesets.push_back(fw->getPolicy()); + rulesets.push_back(fw->getNAT()); + rulesets.push_back(fw->getRouting()); + + foreach(RuleSet *ruleSet, rulesets) { + if (ruleSet && rule->isChildOf(ruleSet)) { + + // We only set the move DiffType if that's the only change + // That a rule is added or edited is more important + if ((diffType == DiffType::Move) && (origDiffType != DiffType::None)) continue; + + if (diffType == DiffType::Edit) { + if (origDiffType == DiffType::Move) + modifyStatistics(ruleSet->getId(), origDiffType, false); + // We only set the edit DiffType on existing rules + // That we edit a newly created rule is normal - but we want to know that it was added + if (origDiffType == DiffType::Add) continue; + } + + // When deleting rules that are added - we only remove the add statistics + if (diffType == DiffType::Remove) { + modifyStatistics(ruleSet->getId(), origDiffType, false); + if (origDiffType == DiffType::Add) continue; + } + // The actual update + modifyStatistics(ruleSet->getId(), diffType, true); + } + } + } +} + +void FWCmdBasic::removeStatistics(Rule *rule, DiffType::Type diffType, DiffType::Type origDiffType) +{ + foreach (Firewall *fw, UsageResolver().findFirewallsForObject(rule, project->db())) { + std::list rulesets; + rulesets.push_back(fw->getPolicy()); + rulesets.push_back(fw->getNAT()); + rulesets.push_back(fw->getRouting()); + + foreach(RuleSet *ruleSet, rulesets) { + if (ruleSet && rule->isChildOf(ruleSet)) { + if ((origDiffType == DiffType::Add) && (diffType == DiffType::Remove)) { + // When reinserting a previously removed rule, that was added to the rule set. + // we only need to update the add statistics + modifyStatistics(ruleSet->getId(), origDiffType, true); + continue; + } + // The actual update + modifyStatistics(ruleSet->getId(), diffType, false); + modifyStatistics(ruleSet->getId(), origDiffType, true); + } + } + } +} + +void FWCmdBasic::modifyStatistics(int id, DiffType::Type diffType, bool increment) +{ + if (diffType == DiffType::None) return; + + int n = project->getStatistics().value( + QPair(id, diffType)); + + project->getStatistics().insert( + QPair(id, diffType), increment ? n++ : n--); +} diff --git a/src/libgui/FWCmdBasic.h b/src/libgui/FWCmdBasic.h index ff69f2885..8431b9b96 100644 --- a/src/libgui/FWCmdBasic.h +++ b/src/libgui/FWCmdBasic.h @@ -6,6 +6,11 @@ Author: Illiya Yalovoy + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -57,6 +62,14 @@ public: libfwbuilder::FWObject* getObject(int id); int id() const {return 1;} bool mergeWith(const QUndoCommand *other); + QHash m_diffLog; + void setDiffType(libfwbuilder::Rule *rule, DiffType::Type diffType); + void resetDiffType(libfwbuilder::Rule *rule); + +private: + void addStatistics(libfwbuilder::Rule *rule, DiffType::Type diffType, DiffType::Type origDiffType); + void removeStatistics(libfwbuilder::Rule *rule, DiffType::Type diffType, DiffType::Type origDiffType); + void modifyStatistics(int id, DiffType::Type diffType, bool increment); }; diff --git a/src/libgui/FWCmdMoveObject.cpp b/src/libgui/FWCmdMoveObject.cpp index c083a9c9e..fcff37b13 100644 --- a/src/libgui/FWCmdMoveObject.cpp +++ b/src/libgui/FWCmdMoveObject.cpp @@ -34,6 +34,7 @@ #include "fwbuilder/Firewall.h" #include "fwbuilder/RuleSet.h" #include "fwbuilder/Library.h" +#include "fwbuilder/RuleElement.h" #include #include @@ -112,6 +113,8 @@ void FWCmdMoveObject::undo() { FWObject *cobj = project->db()->findInIndex(obj_id); if (cobj) o->addRef(cobj); + if (RuleElement::cast(o)) + resetDiffType(Rule::cast(o->getParent())); } } } @@ -142,6 +145,8 @@ void FWCmdMoveObject::redo() { FWObject *cobj = project->db()->findInIndex(obj_id); if (cobj) o->removeRef(cobj); + if (RuleElement::cast(o)) + setDiffType(Rule::cast(o->getParent()), DiffType::Edit); } } } diff --git a/src/libgui/FWCmdRule.cpp b/src/libgui/FWCmdRule.cpp index a20aa5c2f..fcdfeb05d 100644 --- a/src/libgui/FWCmdRule.cpp +++ b/src/libgui/FWCmdRule.cpp @@ -6,6 +6,11 @@ Author: Illiya Yalovoy + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -37,6 +42,7 @@ #include "fwbuilder/NAT.h" #include "fwbuilder/Routing.h" #include "fwbuilder/RuleElement.h" +#include "fwbuilder/Firewall.h" #include @@ -136,11 +142,14 @@ void FWCmdRuleInsert::redoOnModel(RuleSetModel *md) } getRuleSetView()->selectRE(insertedRule,0); + + setDiffType(insertedRule, DiffType::Add); } void FWCmdRuleInsert::undoOnModel(RuleSetModel *md) { QModelIndex index = md->index(insertedRule); + resetDiffType(insertedRule); getRuleSetView()->scrollTo(index, QAbstractItemView::PositionAtCenter); getRuleSetView()->unselect(); md->removeRow(index.row(), index.parent()); @@ -218,6 +227,8 @@ void FWCmdRuleDelete::redoOnModel(RuleSetModel *md) qDebug() << "FWCmdRuleDelete::redoOnModel(RuleSetModel *md)"; foreach(Rule* rule, rulesToDelete) { + setDiffType(rule, DiffType::Remove); + QModelIndex index = md->index(rule, 0); md->removeRow(index.row(), index.parent()); } @@ -229,6 +240,9 @@ void FWCmdRuleDelete::redoOnModel(RuleSetModel *md) void FWCmdRuleDelete::undoOnModel(RuleSetModel *md) { md->restoreRules(rulesToDelete); + foreach(Rule* rule, rulesToDelete) { + resetDiffType(rule); + } } @@ -247,6 +261,9 @@ FWCmdRuleDeleteFromGroup::FWCmdRuleDeleteFromGroup( void FWCmdRuleDeleteFromGroup::undoOnModel(RuleSetModel *md) { md->restoreRules(rulesToDelete, false); + foreach(Rule* rule, rulesToDelete) { + resetDiffType(rule); + } } /******************************************************** @@ -317,11 +334,15 @@ FWCmdRuleMove::FWCmdRuleMove(ProjectPanel *project, RuleSet* ruleset, void FWCmdRuleMove::redoOnModel(RuleSetModel *md) { move(md, direction); + for (int id = firstId; id <= lastId; ++id) + setDiffType(Rule::cast(getObject(id)), DiffType::Move); } void FWCmdRuleMove::undoOnModel(RuleSetModel *md) { move(md, !direction); + for (int id = firstId; id <= lastId; ++id) + resetDiffType(Rule::cast(getObject(id))); } void FWCmdRuleMove::move(RuleSetModel *md, bool direction) @@ -364,12 +385,18 @@ FWCmdRuleRenameGroup::FWCmdRuleRenameGroup( void FWCmdRuleRenameGroup::redoOnModel(RuleSetModel *md) { + project->getRenamedGroups().insert(project->getRenamedGroups().key(oldName, oldName), + newName); + QModelIndex grp = md->index(oldName); md->renameGroup(grp, newName); } void FWCmdRuleRenameGroup::undoOnModel(RuleSetModel *md) { + project->getRenamedGroups().insert(project->getRenamedGroups().key(newName), + oldName); + QModelIndex grp = md->index(newName); md->renameGroup(grp, oldName); } @@ -389,6 +416,9 @@ FWCmdRuleRemoveFromGroup::FWCmdRuleRemoveFromGroup( void FWCmdRuleRemoveFromGroup::redoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + setDiffType(Rule::cast(getObject(id)), DiffType::Move); + QModelIndex group = md->index(groupName); QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); @@ -397,6 +427,9 @@ void FWCmdRuleRemoveFromGroup::redoOnModel(RuleSetModel *md) void FWCmdRuleRemoveFromGroup::undoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + resetDiffType(Rule::cast(getObject(id))); + QModelIndex group = md->index(groupName); QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); @@ -434,6 +467,9 @@ FWCmdRuleNewGroup::FWCmdRuleNewGroup( void FWCmdRuleNewGroup::redoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + setDiffType(Rule::cast(getObject(id)), DiffType::Move); + QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); QModelIndex index = md->createNewGroup(groupName, first.row(), last.row()); @@ -443,6 +479,9 @@ void FWCmdRuleNewGroup::redoOnModel(RuleSetModel *md) void FWCmdRuleNewGroup::undoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + resetDiffType(Rule::cast(getObject(id))); + QModelIndex group = md->index(groupName); QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); @@ -465,6 +504,9 @@ FWCmdRuleAddToGroup::FWCmdRuleAddToGroup( void FWCmdRuleAddToGroup::redoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + setDiffType(Rule::cast(getObject(id)), DiffType::Move); + QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); @@ -475,6 +517,9 @@ void FWCmdRuleAddToGroup::redoOnModel(RuleSetModel *md) void FWCmdRuleAddToGroup::undoOnModel(RuleSetModel *md) { + for (int id = firstRule->getId(); id <= lastRule->getId(); ++id) + resetDiffType(Rule::cast(getObject(id))); + QModelIndex group = md->index(groupName); QModelIndex first = md->index(firstRule, 0); QModelIndex last = md->index(lastRule, 0); @@ -493,27 +538,32 @@ FWCmdRuleChange::FWCmdRuleChange( { } -void FWCmdRuleChange::selectAffectedRule() +Rule* FWCmdRuleChange::selectAffectedRule() { RuleSetView* rsv = project->getCurrentRuleSetView(); RuleSetModel* md = (RuleSetModel*)rsv->model(); Rule* currentRule = md->getRule(rsv->currentIndex()); if(currentRule == 0 || (currentRule->getId() != getRule()->getId())) rsv->selectRE(getRule(), 0); + return currentRule; } void FWCmdRuleChange::redo() { prepareRuleSetView(); FWCmdChange::redo(); - selectAffectedRule(); + Rule *affectedRule = selectAffectedRule(); + if (affectedRule) + setDiffType(affectedRule, DiffType::Edit); } void FWCmdRuleChange::undo() { prepareRuleSetView(); FWCmdChange::undo(); - selectAffectedRule(); + Rule *affectedRule = selectAffectedRule(); + if (affectedRule) + resetDiffType(affectedRule); } void FWCmdRuleChange::notify() diff --git a/src/libgui/FWCmdRule.h b/src/libgui/FWCmdRule.h index 6024305ba..58540674d 100644 --- a/src/libgui/FWCmdRule.h +++ b/src/libgui/FWCmdRule.h @@ -85,6 +85,7 @@ public: void redoOnModel(RuleSetModel *md); void undoOnModel(RuleSetModel *md); + const libfwbuilder::Rule* getInsertedRule() const { return insertedRule; } }; /******************************************************** @@ -105,6 +106,7 @@ public: virtual void redoOnModel(RuleSetModel *md); virtual void undoOnModel(RuleSetModel *md); + const QList getDeletedRules() const { return this->rulesToDelete; } }; /******************************************************** @@ -245,7 +247,7 @@ class FWCmdRuleChange : public FWCmdChange protected: void prepareRuleSetView(); - void selectAffectedRule(); + libfwbuilder::Rule* selectAffectedRule(); virtual libfwbuilder::Rule* getRule(); public: diff --git a/src/libgui/FWWindow.cpp b/src/libgui/FWWindow.cpp index d0318d1b9..6815869cf 100644 --- a/src/libgui/FWWindow.cpp +++ b/src/libgui/FWWindow.cpp @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -103,6 +108,8 @@ #include "fwbuilder/FWObject.h" +#include "BackgroundCompileInfoWidget.h" + #include #include #include @@ -164,6 +171,7 @@ #include #include +#include "temporarydir.h" extern bool regCheck(); @@ -301,11 +309,13 @@ FWWindow::FWWindow() : QMainWindow(), // QMainWindow(NULL, Qt::Desktop), if (tabbar) tabbar->installEventFilter(new MDIEventFilter()); + m_temporaryDir = new TemporaryDir(QDir::tempPath().append("/fwbuilder-tempdir-")); + } FWWindow::~FWWindow() { - + delete m_temporaryDir; QList subwindows = m_mainWindow->m_space->subWindowList( QMdiArea::StackingOrder); @@ -769,6 +779,8 @@ bool FWWindow::loadFile(const QString &file_name, bool load_rcs_head) proj->readyStatus(true); proj->loadState(true); + if (st->getBool("/Diff/AutoCompile")) + autoCompile(); return true; } @@ -1747,6 +1759,16 @@ void FWWindow::inspect() } } +void FWWindow::autoCompile() +{ + if (activeProject() && !activeProject()->db()->isDirty()) + { + instDialog *idlg = new instDialog(this); + new BackgroundCompileInfoWidget(this, idlg, this); + idlg->autoCompile(this->activeProject()); + } +} + void FWWindow::addNewObjectMenu(QMenu *m) { QMenu *old_menu = m_mainWindow->newObjectAction->menu(); @@ -1759,3 +1781,10 @@ void FWWindow::showNewObjectMenu() m_mainWindow->newObjectAction->menu()->popup(QCursor::pos()); } +QString FWWindow::getTemporaryDirPath() const +{ + if (m_temporaryDir->isValid()) + return m_temporaryDir->path(); + return QString(); +} + diff --git a/src/libgui/FWWindow.h b/src/libgui/FWWindow.h index 50c5f2dbf..f32c2af8a 100644 --- a/src/libgui/FWWindow.h +++ b/src/libgui/FWWindow.h @@ -64,6 +64,7 @@ class findDialog; class FindObjectWidget; class FindWhereUsedWidget; class CompilerOutputPanel; +class TemporaryDir; namespace Ui { class FWBMainWindow_q; @@ -120,6 +121,8 @@ class FWWindow : public QMainWindow { QList ruleStaticActions; + TemporaryDir *m_temporaryDir; + public: QVector windowsTitles; QVector windowsPainters; @@ -202,6 +205,7 @@ public slots: virtual void install(std::set vf); virtual void install(); virtual void inspect(); + virtual void autoCompile(); virtual void insertRule(); virtual void addRuleAfterCurrent(); @@ -369,6 +373,8 @@ public slots: void addNewObjectMenu(QMenu*); void showNewObjectMenu(); + + QString getTemporaryDirPath() const; protected: diff --git a/src/libgui/FirewallCodeViewer.cpp b/src/libgui/FirewallCodeViewer.cpp index 1958499d2..2b7944e8a 100644 --- a/src/libgui/FirewallCodeViewer.cpp +++ b/src/libgui/FirewallCodeViewer.cpp @@ -6,6 +6,11 @@ Author: Roman Bovsunivskiy a2k0001@gmail.com + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -29,9 +34,22 @@ #include #include -FirewallCodeViewer::FirewallCodeViewer(QStringList files, QString name, QWidget *parent) : +#include "QFileInfo" +#include "global.h" +#include "FWBSettings.h" +#include "QProcess" +#include "QMessageBox" +#include "PrefsDialog.h" +#include "ProjectPanel.h" + +#include +#include +#include + +FirewallCodeViewer::FirewallCodeViewer(QStringList files, QString name, ProjectPanel *project, QWidget *parent) : QDialog(parent), - ui(new Ui::FirewallCodeViewer_q) + ui(new Ui::FirewallCodeViewer_q), + m_project(project) { ui->setupUi(this); this->files = files; @@ -39,6 +57,17 @@ FirewallCodeViewer::FirewallCodeViewer(QStringList files, QString name, QWidget ui->fileSelector->addItem(file.split("/").last()); fileSelected(0); ui->path->setText(name); + + QMenu *menu = new QMenu(); + QAction *showDiff = new QAction(tr("Show diff"), this); + QAction *showDiffSelectFile = new QAction(tr("Show diff with custom file..."), this); + menu->addAction(showDiff); + menu->addAction(showDiffSelectFile); + ui->diffBtn->setMenu(menu); + ui->diffBtn->setDefaultAction(showDiff); + + connect(showDiff, SIGNAL(triggered()), this, SLOT(showDiff())); + connect(showDiffSelectFile, SIGNAL(triggered()), this, SLOT(showDiffSelectFile())); } FirewallCodeViewer::~FirewallCodeViewer() @@ -58,6 +87,49 @@ void FirewallCodeViewer::changeEvent(QEvent *e) } } +void FirewallCodeViewer::showDiff(const QString &sourceFileName, const QString &destinationFileName) +{ + if (st->getDiffPath().isEmpty()) { + int ret = QMessageBox::warning(this, + tr("Could not start diff program"), + tr("You have not configured an external diff program yet.\n" + "Do you want to do it now?"), + QMessageBox::Yes, + QMessageBox::No + ); + if (ret == QMessageBox::Yes) { + PrefsDialog pd(this); + pd.selectTab("Diff"); + pd.exec(); + } + return; + } + + if (!QFileInfo(destinationFileName).isFile()) return; + + QStringList args; + + if (!QFileInfo(sourceFileName).isFile()) { + QString newSourceFileName = QFileDialog::getOpenFileName( + this, + tr("Select source file for diff..."), + st->getOpenFileDir()); + + if (!QFileInfo(newSourceFileName).isFile()) return; + + args << newSourceFileName; + } else { + args << sourceFileName; + } + + args << destinationFileName; + + QProcess *process = new QProcess(); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); + connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); + process->start(st->getDiffPath(), args); +} + void FirewallCodeViewer::fileSelected(int idx) { if (pages.contains(idx)) @@ -76,7 +148,43 @@ void FirewallCodeViewer::fileSelected(int idx) } } +void FirewallCodeViewer::processError(QProcess::ProcessError error) +{ + if (error == QProcess::FailedToStart) { + int ret = QMessageBox::warning(this, + tr("Could not start diff program"), + tr("Could not start the configured diff program.\n" + "Do you want to check the preferences?"), + QMessageBox::Yes, + QMessageBox::No + ); + if (ret == QMessageBox::Yes) { + PrefsDialog pd(this); + pd.selectTab("Diff"); + pd.exec(); + } + } +} + void FirewallCodeViewer::hideCloseButton() { ui->closeButton->hide(); } + +void FirewallCodeViewer::showDiff() +{ + QString fileName = this->files.at(ui->fileSelector->currentIndex()); + QString autoCompiledFileName; + + QDir tempDir(m_project->getTemporaryDirPath()); + + if (tempDir.exists()) + autoCompiledFileName = QString(tempDir.absolutePath()).append("/").append(fileName.split("/").last()); + + showDiff(autoCompiledFileName, fileName); +} + +void FirewallCodeViewer::showDiffSelectFile() +{ + showDiff(this->files.at(ui->fileSelector->currentIndex()), ""); +} diff --git a/src/libgui/FirewallCodeViewer.h b/src/libgui/FirewallCodeViewer.h index 49aab2277..5b757d75f 100644 --- a/src/libgui/FirewallCodeViewer.h +++ b/src/libgui/FirewallCodeViewer.h @@ -6,6 +6,11 @@ Author: Roman Bovsunivskiy a2k0001@gmail.com + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -35,12 +40,16 @@ namespace Ui { class FirewallCodeViewer_q; } +class ProjectPanel; + +#include + class FirewallCodeViewer : public QDialog { Q_OBJECT QStringList files; QMap pages; public: - FirewallCodeViewer(QStringList files, QString path, QWidget *parent = 0); + FirewallCodeViewer(QStringList files, QString path, ProjectPanel *project, QWidget *parent = 0); ~FirewallCodeViewer(); protected: @@ -48,8 +57,12 @@ protected: private: Ui::FirewallCodeViewer_q *ui; + ProjectPanel *m_project; + + void showDiff(const QString &destinationFileName, const QString &sourceFileName); public slots: void fileSelected(int); + void processError(QProcess::ProcessError); void hideCloseButton(); void keyPressEvent(QKeyEvent *event) { @@ -57,7 +70,8 @@ public slots: return QDialog::keyPressEvent(event); event->setAccepted(false); } - + void showDiff(); + void showDiffSelectFile(); }; #endif // FIREWALLCODEVIEWER_H diff --git a/src/libgui/FirewallCodeViewer.ui b/src/libgui/FirewallCodeViewer.ui index 3ab464524..fe54ac902 100644 --- a/src/libgui/FirewallCodeViewer.ui +++ b/src/libgui/FirewallCodeViewer.ui @@ -69,6 +69,28 @@ + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + Show diff + + + QToolButton::MenuButtonPopup + + + @@ -80,7 +102,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -130,8 +161,8 @@ reject() - 337 - 475 + 374 + 500 447 diff --git a/src/libgui/PrefsDialog.cpp b/src/libgui/PrefsDialog.cpp index 35fc09781..14095caeb 100644 --- a/src/libgui/PrefsDialog.cpp +++ b/src/libgui/PrefsDialog.cpp @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -150,12 +155,15 @@ PrefsDialog::PrefsDialog(QWidget *parent) : QDialog(parent) // dontSaveStdLib->setChecked( st->getDontSaveStdLib() ); m_dialog->sshPath->setText( st->getSSHPath() ); - m_dialog->scpPath->setText( st->getSCPPath() ); + m_dialog->scpPath->setText( st->getSCPPath() );; m_dialog->sshTimeout->setValue( st->getSSHTimeout() ); m_dialog->rememberSshPass->setChecked( st->getBool("Environment/RememberSshPassEnabled") ); + m_dialog->autoCompileChk->setChecked( st->getBool("/Diff/AutoCompile")); + m_dialog->diffPath->setText( st->getDiffPath() ); + m_dialog->showTips->setChecked( st->getBool("UI/NoStartTip") ); m_dialog->rulesLoggingOn->setChecked( @@ -245,6 +253,22 @@ PrefsDialog::PrefsDialog(QWidget *parent) : QDialog(parent) m_dialog->plink_hint->hide(); #endif + // Diff Viewer + + colors[FWBSettings::ADD_COLOR]=st->getDiffColor(FWBSettings::ADD_COLOR); + setButtonColor(m_dialog->addColorBtn, colors[FWBSettings::ADD_COLOR]); + + colors[FWBSettings::EDIT_COLOR]=st->getDiffColor(FWBSettings::EDIT_COLOR); + setButtonColor(m_dialog->editColorBtn, colors[FWBSettings::EDIT_COLOR]); + + colors[FWBSettings::MOVE_COLOR]=st->getDiffColor(FWBSettings::MOVE_COLOR); + setButtonColor(m_dialog->moveColorBtn, colors[FWBSettings::MOVE_COLOR]); + + colors[FWBSettings::REMOVE_COLOR]=st->getDiffColor(FWBSettings::REMOVE_COLOR); + setButtonColor(m_dialog->removeColorBtn, colors[FWBSettings::REMOVE_COLOR]); + + m_dialog->displayUnmodifiedRulesChk->setChecked(st->getDisplayUnmodifiedRules()); + // Fill lists of platforms and host OS QMap platforms = getAllPlatforms(false); @@ -350,6 +374,26 @@ void PrefsDialog::changeGrayColor() changeColor(m_dialog->grayBtn, FWBSettings::GRAY); } +void PrefsDialog::changeAddColor() +{ + changeColor(m_dialog->addColorBtn, FWBSettings::ADD_COLOR); +} + +void PrefsDialog::changeEditColor() +{ + changeColor(m_dialog->editColorBtn, FWBSettings::EDIT_COLOR); +} + +void PrefsDialog::changeMoveColor() +{ + changeColor(m_dialog->moveColorBtn, FWBSettings::MOVE_COLOR); +} + +void PrefsDialog::changeRemoveColor() +{ + changeColor(m_dialog->removeColorBtn, FWBSettings::REMOVE_COLOR); +} + void PrefsDialog::changeIconSize25() { //st->setIconsInRulesSize(FWBSettings::SIZE25X25); @@ -453,6 +497,21 @@ void PrefsDialog::findSCP() m_dialog->scpPath->setText(fp); } +void PrefsDialog::findDiff() +{ + QString diffPath = m_dialog->diffPath->text(); + if (!QFileInfo(diffPath).isFile()) diffPath = st->getDiffPath(); + if (!QFileInfo(diffPath).isFile()) diffPath = st->getOpenFileDir(); + + QString fp = QFileDialog::getOpenFileName( + this, tr("Find Diff utility"), diffPath); + + if (fp.isEmpty()) return; + st->setOpenFileDir(fp); + + m_dialog->diffPath->setText(fp); +} + void PrefsDialog::accept() { QString wd=m_dialog->wDir->text(); @@ -559,10 +618,20 @@ void PrefsDialog::accept() st->setSCPPath( m_dialog->scpPath->text() ); st->setSSHTimeout(m_dialog->sshTimeout->value()); + st->setBool("/Diff/AutoCompile", m_dialog->autoCompileChk->isChecked()); + st->setDiffPath( m_dialog->diffPath->text() ); + st->setBool("Environment/RememberSshPassEnabled", m_dialog->rememberSshPass->isChecked()); st->setCheckUpdates(m_dialog->checkUpdates->isChecked()); + st->setDiffColor(FWBSettings::ADD_COLOR, colors[FWBSettings::ADD_COLOR]); + st->setDiffColor(FWBSettings::EDIT_COLOR, colors[FWBSettings::EDIT_COLOR]); + st->setDiffColor(FWBSettings::MOVE_COLOR, colors[FWBSettings::MOVE_COLOR]); + st->setDiffColor(FWBSettings::REMOVE_COLOR, colors[FWBSettings::REMOVE_COLOR]); + + st->setDisplayUnmodifiedRules( m_dialog->displayUnmodifiedRulesChk->isChecked() ); + for (int row=0; row < m_dialog->enabled_platforms->rowCount(); ++row) { QTableWidgetItem *itm = m_dialog->enabled_platforms->item(row, 0); @@ -652,3 +721,13 @@ void PrefsDialog::objTooltipsEnabled(bool enabled) m_dialog->advTooltipMode->setChecked(false); m_dialog->advTooltipMode->setEnabled(enabled); } + +void PrefsDialog::selectTab(const QString &name) +{ + for (int i = m_dialog->tabWidget->count(); i >= 0; i--) { + if (m_dialog->tabWidget->tabText(i) == name) { + m_dialog->tabWidget->setCurrentIndex(i); + return; + } + } +} diff --git a/src/libgui/PrefsDialog.h b/src/libgui/PrefsDialog.h index ff4669973..29d44a3ae 100644 --- a/src/libgui/PrefsDialog.h +++ b/src/libgui/PrefsDialog.h @@ -73,6 +73,7 @@ public slots: virtual void findDataDir(); virtual void findSSH(); virtual void findSCP(); + virtual void findDiff(); virtual void changeRedColor(); virtual void changeOrangeColor(); virtual void changeYellowColor(); @@ -80,6 +81,10 @@ public slots: virtual void changeBlueColor(); virtual void changePurpleColor(); virtual void changeGrayColor(); + virtual void changeAddColor(); + virtual void changeEditColor(); + virtual void changeMoveColor(); + virtual void changeRemoveColor(); virtual void changeIconSize25(); virtual void changeIconSize16(); virtual void changeShowIcons(); @@ -89,6 +94,8 @@ public slots: virtual void checkSwUpdates(); virtual void checkForUpgrade(const QString&); virtual void objTooltipsEnabled(bool); + + void selectTab(const QString &name); }; #endif // __PREFSDIALOG_H diff --git a/src/libgui/ProjectPanel.cpp b/src/libgui/ProjectPanel.cpp index eb331aec2..4899a1397 100644 --- a/src/libgui/ProjectPanel.cpp +++ b/src/libgui/ProjectPanel.cpp @@ -7,6 +7,11 @@ Author: alek@codeminders.com refactoring and bugfixes: vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -52,6 +57,9 @@ #include "WorkflowIcons.h" #include "FirewallCodeViewer.h" +#include "RuleSetDiffDialog.h" +#include "temporarydir.h" + #include #include #include @@ -107,6 +115,7 @@ void ProjectPanel::initMain(FWWindow *main) fd->hide(); m_panel->icons->setUpSignals(this); + } void ProjectPanel::reset() @@ -132,6 +141,7 @@ ProjectPanel::ProjectPanel(QWidget *parent): editingTemplateLib(false), ruleSetRedrawPending(false), objdb(0), + origObjdb(0), fd(0), autosaveTimer(new QTimer(static_cast(this))), ruleSetTabIndex(0), visibleFirewall(0), @@ -158,6 +168,9 @@ ProjectPanel::ProjectPanel(QWidget *parent): connect(m_panel->topSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterPositionChanged(int,int))); + m_diffLog = QHash(); + m_renamedGroups = QHash(); + m_statistics = QHash, int>(); } ProjectPanel::~ProjectPanel() @@ -167,6 +180,7 @@ ProjectPanel::~ProjectPanel() undoStack->clear(); if (rcs) delete rcs; if (objdb) delete objdb; + if (origObjdb) delete origObjdb; delete m_panel; if (fwbdebug) qDebug() << "ProjectPanel::~ProjectPanel() done"; @@ -214,6 +228,19 @@ void ProjectPanel::clearObjects() m_panel->om->clearObjects(); } +const QString ProjectPanel::getTemporaryDirPath() const +{ + if (mainW->getTemporaryDirPath() != QString()) { + if (!rcs->getFileName().isEmpty()) { + QFileInfo fi(rcs->getFileName()); + return QString(mainW->getTemporaryDirPath()) + .append("/").append(fi.baseName()); + } + return mainW->getTemporaryDirPath(); + } + return QString(); +} + void ProjectPanel::clearFirewallTabs() { if (fwbdebug) qDebug() << "ProjectPanel::clearFirewallTabs"; @@ -695,6 +722,16 @@ void ProjectPanel::addRule() getCurrentRuleSetView()->insertRule(); } +/* + * This slot is connected to the "diff rule" button in the mini-toolbar + * at the top of the rule set view + */ +void ProjectPanel::diffThis() +{ + RuleSetDiffDialog rdd(this); + rdd.exec(); +} + void ProjectPanel::compileThis() { if (visibleRuleSet==NULL) return ; @@ -948,7 +985,7 @@ void ProjectPanel::inspect(set fws) else viewer_title = QString("%1").arg(first_fw->getName().c_str()); FirewallCodeViewer *viewer = - new FirewallCodeViewer(files, viewer_title, this); + new FirewallCodeViewer(files, viewer_title, this, this); viewer->show(); } diff --git a/src/libgui/ProjectPanel.h b/src/libgui/ProjectPanel.h index 340ae6c72..dc908d59d 100644 --- a/src/libgui/ProjectPanel.h +++ b/src/libgui/ProjectPanel.h @@ -6,6 +6,11 @@ Author: alek@codeminders.com + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -61,6 +66,15 @@ class FWBTree; #define DEFAULT_H_SPLITTER_POSITION 250 #define DEFAULT_V_SPLITTER_POSITION 450 +namespace DiffType { + enum Type { + None, + Add, + Remove, + Edit, + Move + }; +} class ProjectPanel: public QWidget { Q_OBJECT; @@ -74,7 +88,7 @@ class ProjectPanel: public QWidget { bool ruleSetRedrawPending; bool ready; - libfwbuilder::FWObjectDatabase *objdb; + libfwbuilder::FWObjectDatabase *objdb, *origObjdb; findDialog *fd; @@ -103,6 +117,9 @@ class ProjectPanel: public QWidget { std::map updateObjectsInTreePool; bool treeReloadPending; + QHash m_diffLog; + QHash m_renamedGroups; + QHash, int> m_statistics; public: @@ -132,9 +149,21 @@ public: void loadObjects(libfwbuilder::FWObjectDatabase *db); void clearObjects(); libfwbuilder::FWObjectDatabase* db() { return objdb; }; + libfwbuilder::FWObjectDatabase* origDb() { return origObjdb; } bool hasObject(libfwbuilder::FWObject* obj) { return objdb->findInIndex(obj->getId()); }; + + void setDiffType(int id, enum DiffType::Type type) { m_diffLog.insert(id, type); } + int getDiffType(int id) { return m_diffLog.value(id, DiffType::None); } + const QHash& getDiffLog() { return m_diffLog; } + QHash& getRenamedGroups() { return m_renamedGroups; } + QHash, int>& getStatistics() { return m_statistics; } + int getStatistics(int ruleSetId, DiffType::Type diffType) + { return m_statistics.value(QPair(ruleSetId, diffType), 0); } + + const QString getTemporaryDirPath() const; + // libfwbuilder::RuleElement* getRE(libfwbuilder::Rule* r, int col ); //wrapers for some ObjectManipulator functions @@ -274,6 +303,7 @@ public: virtual void inspectThis(); virtual void inspectAll(); virtual void addRule(); + virtual void diffThis(); void updateLastModifiedTimestampForAllFirewalls(); void updateObjectInTree(); diff --git a/src/libgui/ProjectPanel_file_ops.cpp b/src/libgui/ProjectPanel_file_ops.cpp index f4b778c13..f9ca73882 100644 --- a/src/libgui/ProjectPanel_file_ops.cpp +++ b/src/libgui/ProjectPanel_file_ops.cpp @@ -265,6 +265,13 @@ bool ProjectPanel::loadFile(const QString &fileName, bool load_rcs_head) unlink(new_rcs->getFileName().toLocal8Bit().constData()); st->setOpenFileDir(getFileDir(fileName)); + + // For Diff Viewer + if (origObjdb) + delete origObjdb; + origObjdb = new FWObjectDatabase(*objdb); + origObjdb->reIndex(); + return true; } @@ -973,6 +980,13 @@ void ProjectPanel::loadStandardObjects() if (fwbdebug) qDebug("ProjectPanel::load(): done last_modified=%s dirty=%d", ctime(&last_modified), objdb->isDirty()); + + // For Diff Viewer + if (origObjdb) + delete origObjdb; + origObjdb = new FWObjectDatabase(*objdb); + origObjdb->reIndex(); + } catch(FWException &ex) { QMessageBox::critical( @@ -1288,6 +1302,7 @@ bool ProjectPanel::loadFromRCS(RCS *_rcs) qDebug("ProjectPanel::load(): all done: " "dirty=%d last_modified=%s", db()->isDirty(), ctime(&last_modified)); + return true; } diff --git a/src/libgui/RuleSetDiffDelegate.cpp b/src/libgui/RuleSetDiffDelegate.cpp new file mode 100644 index 000000000..44ad2b9c3 --- /dev/null +++ b/src/libgui/RuleSetDiffDelegate.cpp @@ -0,0 +1,75 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + This program is free software which we release under the GNU General Public + License. You may redistribute and/or modify this program under the terms + of that license as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + To get a copy of the GNU General Public License, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "RuleSetDiffDelegate.h" + +#include + +#include "config.h" +#include "global.h" +#include "utils.h" +#include "FWBSettings.h" + +#include "fwbuilder/Rule.h" +#include "RuleSetDiffDialog.h" + + +using namespace libfwbuilder; +using namespace std; + +RuleSetDiffDelegate::RuleSetDiffDelegate(QObject *parent, + FWObjectSelectionModel *selectionModel, + QAbstractProxyModel *model, + ProjectPanel *project) + : RuleSetViewDelegate(parent, selectionModel), m_model(model), m_project(project) +{} + +void RuleSetDiffDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + RuleSetViewDelegate::paint(painter, option, m_model->mapToSource(index)); +} + +QSize RuleSetDiffDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return RuleSetViewDelegate::sizeHint(option, m_model->mapToSource(index)); +} + +QString RuleSetDiffDelegate::getRuleColor(RuleNode *node) const +{ + int changeType = m_project->getDiffType(node->rule->getId()); + + switch (changeType) { + case DiffType::Add: + return QString(st->getDiffColor(FWBSettings::ADD_COLOR)); + case DiffType::Edit: + return QString(st->getDiffColor(FWBSettings::EDIT_COLOR)); + case DiffType::Move: + return QString(st->getDiffColor(FWBSettings::MOVE_COLOR)); + case DiffType::Remove: + return QString(st->getDiffColor(FWBSettings::REMOVE_COLOR)); + default: + break; + } + return QString(); +} diff --git a/src/libgui/RuleSetDiffDelegate.h b/src/libgui/RuleSetDiffDelegate.h new file mode 100644 index 000000000..bac7e3f52 --- /dev/null +++ b/src/libgui/RuleSetDiffDelegate.h @@ -0,0 +1,44 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + 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 + +*/ + +#ifndef RULESETDIFFDELEGATE_H +#define RULESETDIFFDELEGATE_H + +#include "RuleSetViewDelegate.h" +#include "ProjectPanel.h" +#include + +class RuleSetDiffDelegate : public RuleSetViewDelegate +{ + Q_OBJECT +public: + RuleSetDiffDelegate(QObject *parent, FWObjectSelectionModel *selectionModel, QAbstractProxyModel *model, ProjectPanel *project); + void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + QSize sizeHint (const QStyleOptionViewItem &, const QModelIndex &) const; +private: + QAbstractProxyModel *m_model; + ProjectPanel *m_project; + virtual QString getRuleColor(RuleNode *node) const; +}; + +#endif // RULESETDIFFDELEGATE_H diff --git a/src/libgui/RuleSetDiffDialog.cpp b/src/libgui/RuleSetDiffDialog.cpp new file mode 100644 index 000000000..8d6fec2c1 --- /dev/null +++ b/src/libgui/RuleSetDiffDialog.cpp @@ -0,0 +1,350 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + This program is free software which we release under the GNU General Public + License. You may redistribute and/or modify this program under the terms + of that license as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + To get a copy of the GNU General Public License, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "RuleSetDiffDialog.h" +#include "RuleSetDiffModel.h" + +#include +#include +#include +#include + + +#include "RuleSetView.h" +#include "fwbuilder/Firewall.h" +#include "fwbuilder/Cluster.h" +#include "fwbuilder/Policy.h" +#include "fwbuilder/NAT.h" +#include "fwbuilder/Routing.h" +#include "fwbuilder/RuleSet.h" +#include "fwbuilder/Library.h" +#include "RuleSetDiffDelegate.h" +#include "FWObjectSelectionModel.h" +#include "FWCmdRule.h" +#include "fwbuilder/Firewall.h" +#include "fwbuilder/RuleElement.h" +#include "RuleSetModel.h" +#include "FWBSettings.h" +#include "global.h" + +using namespace libfwbuilder; +using namespace std; + +static bool sortByName(const FWObject *a, const FWObject *b) { return a->getName() < b->getName(); } + +RuleSetDiffDialog::RuleSetDiffDialog(ProjectPanel *project, QWidget *parent) : + QDialog(parent), + ui(new Ui::RuleSetDiffDialog_q), + m_project(project) +{ + ui->setupUi(this); + + connect(ui->firewall, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRuleSetList())); + connect(ui->ruleset, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRuleSetView())); + connect(ui->originalRuleSetView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(horizontalScrollBarValueChanged(int))); + connect(ui->currentRuleSetView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(horizontalScrollBarValueChanged(int))); + + connect(ui->originalRuleSetView, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); + connect(ui->currentRuleSetView, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); + connect(ui->originalRuleSetView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); + connect(ui->currentRuleSetView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); + connect(ui->originalRuleSetView, SIGNAL(expanded(QModelIndex)), this, SLOT(itemExpanded(QModelIndex))); + connect(ui->currentRuleSetView, SIGNAL(expanded(QModelIndex)), this, SLOT(itemExpanded(QModelIndex))); + connect(ui->originalRuleSetView, SIGNAL(collapsed(QModelIndex)), this, SLOT(itemCollapsed(QModelIndex))); + connect(ui->currentRuleSetView, SIGNAL(collapsed(QModelIndex)), this, SLOT(itemCollapsed(QModelIndex))); + + ui->displayUnmodifiedRulesBtn->setChecked(st->getDisplayUnmodifiedRules()); + connect(ui->displayUnmodifiedRulesBtn, SIGNAL(clicked()), this, SLOT(displayUnmodifiedRules())); + + m_currentObjdb = m_project->db(); + if (m_currentObjdb) + m_currentUserLibrary = findUserLibrary(m_currentObjdb); + + m_originalObjdb = m_project->origDb(); + if (m_originalObjdb) + m_originalUserLibrary = findUserLibrary(m_originalObjdb); + + updateFirewallList(); + + showMaximized(); +} + +Library* RuleSetDiffDialog::findUserLibrary(FWObjectDatabase *db) +{ + Library *lib = NULL; + foreach (FWObject *obj, db->getByType(Library::TYPENAME)) + { + if (obj->getName() == "User") + { + lib = Library::cast(obj); + break; + } + } + return lib; +} + +RuleSetDiffDialog::~RuleSetDiffDialog() +{ + delete ui; +} + +void RuleSetDiffDialog::updateFirewallList() +{ + if (!m_currentUserLibrary) return; + + list clusters = m_currentUserLibrary->getByTypeDeep(Cluster::TYPENAME); + clusters.sort(sortByName); + + foreach (FWObject *cluster, clusters) + if (m_originalUserLibrary->getById(cluster->getId(), true)) + ui->firewall->addItem(QString::fromStdString((cluster->getName())), QVariant(cluster->getId())); + + list firewalls = m_currentUserLibrary->getByTypeDeep(Firewall::TYPENAME); + firewalls.sort(sortByName); + + foreach(FWObject *firewall, firewalls) + if (m_originalUserLibrary->getById(firewall->getId(), true)) + ui->firewall->addItem(QString::fromStdString(firewall->getName()), QVariant(firewall->getId())); +} + +void RuleSetDiffDialog::updateRuleSetList() { + ui->ruleset->clear(); + + if (!m_currentUserLibrary) return; + + FWObject *currentFirewall = m_currentUserLibrary->getById( + ui->firewall->itemData(ui->firewall->currentIndex()).toInt(), true); + + FWObject *originalFirewall = m_originalUserLibrary->getById( + ui->firewall->itemData(ui->firewall->currentIndex()).toInt(), true); + + if (!currentFirewall || !originalFirewall) return; + + foreach (FWObject *ruleset, static_cast >(*currentFirewall)) { + if ((ruleset->getTypeName() == Policy::TYPENAME) || + (ruleset->getTypeName() == NAT::TYPENAME) || + (ruleset->getTypeName() == Routing::TYPENAME)) + if (originalFirewall->getById(ruleset->getId())) + ui->ruleset->addItem(QString::fromStdString(ruleset->getName()), QVariant(ruleset->getId())); + } +} + +void RuleSetDiffDialog::updateRuleSetView() { + if (!m_currentUserLibrary || !m_originalUserLibrary || !ui->ruleset->count()) return; + + FWObject *currentRuleSet = m_currentUserLibrary->getById( + ui->ruleset->itemData(ui->ruleset->currentIndex()).toInt(), true); + + FWObject *originalRuleSet = m_originalUserLibrary->getById(currentRuleSet->getId(), true); + + if (!currentRuleSet || !originalRuleSet) return; + + RuleSetModel *currentRuleSetModel, *originalRuleSetModel; + + if (Policy::isA(currentRuleSet)) { + currentRuleSetModel = new PolicyModel(Policy::cast(currentRuleSet), this); + originalRuleSetModel = new PolicyModel(Policy::cast(originalRuleSet), this); + } + + if (NAT::isA(currentRuleSet)) { + currentRuleSetModel = new NatModel(NAT::cast(currentRuleSet), this); + originalRuleSetModel = new NatModel(NAT::cast(originalRuleSet), this); + } + + if (Routing::isA(currentRuleSet)) { + currentRuleSetModel = new RoutingModel(Routing::cast(currentRuleSet), this); + originalRuleSetModel = new RoutingModel(Routing::cast(originalRuleSet), this); + } + + RuleSetDiffModel *originalDiffModel = new RuleSetDiffModel(this, originalRuleSetModel, m_project); + RuleSetDiffDelegate *originalDelegate = new RuleSetDiffDelegate(originalDiffModel, new FWObjectSelectionModel(), originalDiffModel, m_project); + ui->originalRuleSetView->setModel(originalDiffModel); + ui->originalRuleSetView->setItemDelegate(originalDelegate); + originalDiffModel->displayUnmodifiedRules(ui->displayUnmodifiedRulesBtn->isChecked()); + ui->originalRuleSetView->expandAll(); + + RuleSetDiffModel *currentDiffModel = new RuleSetDiffModel(this, currentRuleSetModel, m_project); + RuleSetDiffDelegate *currentDelegate = new RuleSetDiffDelegate(currentDiffModel, new FWObjectSelectionModel(), currentDiffModel, m_project); + ui->currentRuleSetView->setModel(currentDiffModel); + ui->currentRuleSetView->setItemDelegate(currentDelegate); + currentDiffModel->displayUnmodifiedRules(ui->displayUnmodifiedRulesBtn->isChecked()); + ui->currentRuleSetView->expandAll(); + + setLabelColor(ui->addColorLbl, st->getDiffColor(FWBSettings::ADD_COLOR)); + ui->addTextLbl->setText(QString(tr("Add (%1)")) + .arg(QString::number(m_project->getStatistics(currentRuleSet->getId(), DiffType::Add)))); + + setLabelColor(ui->editColorLbl, st->getDiffColor(FWBSettings::EDIT_COLOR)); + ui->editTextLbl->setText(QString(tr("Edit (%1)")) + .arg(QString::number(m_project->getStatistics(currentRuleSet->getId(), DiffType::Edit)))); + + setLabelColor(ui->moveColorLbl, st->getDiffColor(FWBSettings::MOVE_COLOR)); + ui->moveTextLbl->setText(QString(tr("Move (%1)")) + .arg(QString::number(m_project->getStatistics(currentRuleSet->getId(), DiffType::Move)))); + + setLabelColor(ui->removeColorLbl, st->getDiffColor(FWBSettings::REMOVE_COLOR)); + ui->removeTextLbl->setText(QString(tr("Remove (%1)")) + .arg(QString::number(m_project->getStatistics(currentRuleSet->getId(), DiffType::Remove)))); +} + +void RuleSetDiffDialog::setLabelColor(QLabel *label, const QString &color) +{ + QPalette palette; + palette.setColor(QPalette::Window, QColor(color)); + label->setAutoFillBackground(true); + label->setPalette(palette); +} + +void RuleSetDiffDialog::horizontalScrollBarValueChanged(int val) +{ + ui->originalRuleSetView->horizontalScrollBar()->setValue(val); + ui->currentRuleSetView->horizontalScrollBar()->setValue(val); +} + +void RuleSetDiffDialog::itemClicked(const QModelIndex &index) +{ + if (sender() == ui->currentRuleSetView) + selectItem(index, true); + else if (sender() == ui->originalRuleSetView) + selectItem(index, false); +} + +void RuleSetDiffDialog::itemDoubleClicked(const QModelIndex &index) +{ + if (sender() == ui->currentRuleSetView) + selectItem(index, true, true); + else if (sender() == ui->originalRuleSetView) + selectItem(index, false, true); +} + +void RuleSetDiffDialog::selectItem(const QModelIndex &index, bool sourceIsCurrentRuleSetView, bool doubleClick) +{ + RuleSetDiffModel *srcProxyModel, *dstProxyModel; + RuleSetModel *ruleSetModel; + QTreeView *view; + + if (sourceIsCurrentRuleSetView) { + srcProxyModel = static_cast(ui->currentRuleSetView->model()); + dstProxyModel = static_cast(ui->originalRuleSetView->model()); + ruleSetModel = static_cast(dstProxyModel->sourceModel()); + view = ui->originalRuleSetView; + } else { + srcProxyModel = static_cast(ui->originalRuleSetView->model()); + dstProxyModel = static_cast(ui->currentRuleSetView->model()); + ruleSetModel = static_cast(dstProxyModel->sourceModel()); + view = ui->currentRuleSetView; + } + + RuleNode *node = static_cast(srcProxyModel->mapToSource(index).internalPointer()); + + if (node->type == RuleNode::Rule) { + Rule *rule = Rule::cast(ruleSetModel->getRuleSet()->getById(node->rule->getId(), true)); + if (rule) { + view->setCurrentIndex(dstProxyModel->mapFromSource( + ruleSetModel->indexForPosition( + rule->getPosition()))); + if (doubleClick) { + ui->originalRuleSetView->scrollTo(ui->originalRuleSetView->currentIndex(), + QAbstractItemView::PositionAtCenter); + ui->currentRuleSetView->scrollTo(ui->currentRuleSetView->currentIndex(), + QAbstractItemView::PositionAtCenter); + } + return; + } + } + + if (node->type == RuleNode::Group) { + if (sourceIsCurrentRuleSetView) { + view->setCurrentIndex(dstProxyModel->mapFromSource( + ruleSetModel->index( + m_project->getRenamedGroups().key(node->name, node->name)))); + } else { + view->setCurrentIndex(dstProxyModel->mapFromSource( + ruleSetModel->index( + m_project->getRenamedGroups().value(node->name, node->name)))); + } + if (doubleClick) { + ui->originalRuleSetView->scrollTo(ui->originalRuleSetView->currentIndex(), + QAbstractItemView::PositionAtCenter); + ui->currentRuleSetView->scrollTo(ui->currentRuleSetView->currentIndex(), + QAbstractItemView::PositionAtCenter); + } + return; + } + + view->clearSelection(); +} + +void RuleSetDiffDialog::itemExpanded(const QModelIndex &index) +{ + expandCollapseItem(index, true); +} + +void RuleSetDiffDialog::itemCollapsed(const QModelIndex &index) +{ + expandCollapseItem(index); +} + +void RuleSetDiffDialog::expandCollapseItem(const QModelIndex &index, bool expand) +{ + RuleSetDiffModel *srcProxyModel, *dstProxyModel; + RuleSetModel *ruleSetModel; + QTreeView *view; + + if (sender() == ui->currentRuleSetView) { + srcProxyModel = static_cast(ui->currentRuleSetView->model()); + dstProxyModel = static_cast(ui->originalRuleSetView->model()); + ruleSetModel = static_cast(dstProxyModel->sourceModel()); + view = ui->originalRuleSetView; + } else if (sender() == ui->currentRuleSetView) { + srcProxyModel = static_cast(ui->originalRuleSetView->model()); + dstProxyModel = static_cast(ui->currentRuleSetView->model()); + ruleSetModel = static_cast(dstProxyModel->sourceModel()); + view = ui->currentRuleSetView; + } else { + return; + } + + RuleNode *node = static_cast(srcProxyModel->mapToSource(index).internalPointer()); + + if (node->type == RuleNode::Group) { + if (expand) { + view->expand(dstProxyModel->mapFromSource(ruleSetModel->index(node->name))); + } else { + view->collapse(dstProxyModel->mapFromSource(ruleSetModel->index(node->name))); + } + } +} + +void RuleSetDiffDialog::displayUnmodifiedRules() +{ + RuleSetDiffModel *originalDiffModel = static_cast(ui->originalRuleSetView->model()); + RuleSetDiffModel *currentDiffModel = static_cast(ui->currentRuleSetView->model()); + + if (!originalDiffModel || !currentDiffModel) return; + + originalDiffModel->displayUnmodifiedRules(ui->displayUnmodifiedRulesBtn->isChecked()); + ui->originalRuleSetView->expandAll(); + currentDiffModel->displayUnmodifiedRules(ui->displayUnmodifiedRulesBtn->isChecked()); + ui->currentRuleSetView->expandAll(); +} diff --git a/src/libgui/RuleSetDiffDialog.h b/src/libgui/RuleSetDiffDialog.h new file mode 100644 index 000000000..5675a21d6 --- /dev/null +++ b/src/libgui/RuleSetDiffDialog.h @@ -0,0 +1,80 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + 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 + +*/ + +#ifndef RULESETDIFFDIALOG_H +#define RULESETDIFFDIALOG_H + +#include + +#include +#include + +namespace libfwbuilder { +class FWObject; +class FWObjectDatabase; +class Library; +} + +class ProjectPanel; +class RuleSetModel; + +namespace Ui { +class RuleSetDiffDialog_q; +} + +class RuleSetDiffDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RuleSetDiffDialog(ProjectPanel *project, QWidget *parent = 0); + ~RuleSetDiffDialog(); + +public slots: + void updateFirewallList(); + void updateRuleSetList(); + void updateRuleSetView(); + void horizontalScrollBarValueChanged(int val); + + void itemClicked(const QModelIndex &index); + void itemDoubleClicked(const QModelIndex &index); + void selectItem(const QModelIndex &index, bool sourceIsCurrentRuleSetView, bool doubleClick = false); + + void itemExpanded(const QModelIndex &index); + void itemCollapsed(const QModelIndex &index); + void expandCollapseItem(const QModelIndex &index, bool expand = false); + + void displayUnmodifiedRules(); + +private: + Ui::RuleSetDiffDialog_q *ui; + ProjectPanel *m_project; + libfwbuilder::FWObjectDatabase *m_currentObjdb; + libfwbuilder::FWObjectDatabase *m_originalObjdb; + libfwbuilder::Library *m_currentUserLibrary; + libfwbuilder::Library *m_originalUserLibrary; + libfwbuilder::Library* findUserLibrary(libfwbuilder::FWObjectDatabase *db); + void setLabelColor(QLabel *label, const QString& color); +}; + +#endif // RULESETDIFFDIALOG_H diff --git a/src/libgui/RuleSetDiffModel.cpp b/src/libgui/RuleSetDiffModel.cpp new file mode 100644 index 000000000..041cf7307 --- /dev/null +++ b/src/libgui/RuleSetDiffModel.cpp @@ -0,0 +1,63 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + This program is free software which we release under the GNU General Public + License. You may redistribute and/or modify this program under the terms + of that license as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + To get a copy of the GNU General Public License, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "RuleSetDiffModel.h" +#include "RuleNode.h" +#include "fwbuilder/Rule.h" + +using namespace libfwbuilder; + +RuleSetDiffModel::RuleSetDiffModel(QObject *parent, RuleSetModel *model, ProjectPanel *project) : + QSortFilterProxyModel(parent), m_project(project), m_displayUnmodifiedRules(false) +{ + setSourceModel(model); +} + +void RuleSetDiffModel::displayUnmodifiedRules(bool val) +{ + if (m_displayUnmodifiedRules == val) return; + + beginResetModel(); + m_displayUnmodifiedRules = val; + endResetModel(); +} + +bool RuleSetDiffModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + if (m_displayUnmodifiedRules) + return true; + + QModelIndex index = sourceModel()->index(source_row, 0, source_parent); + + if (index.isValid()) { + + RuleNode *node = static_cast(index.internalPointer()); + if (!node) return false; + + if (RuleNode::Rule != node->type) return true; + + if (m_project->getDiffType(node->rule->getId()) != DiffType::None) + return true; + } + return false; +} diff --git a/src/libgui/RuleSetDiffModel.h b/src/libgui/RuleSetDiffModel.h new file mode 100644 index 000000000..7875451e9 --- /dev/null +++ b/src/libgui/RuleSetDiffModel.h @@ -0,0 +1,48 @@ +/* + + Firewall Builder + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + + 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 + +*/ + +#ifndef RULESETDIFFMODEL_H +#define RULESETDIFFMODEL_H + +#include +#include "ProjectPanel.h" +#include "RuleSetModel.h" + +class RuleSetDiffModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit RuleSetDiffModel(QObject *parent, RuleSetModel *model, ProjectPanel *project); + void displayUnmodifiedRules(bool val); +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; +private: + ProjectPanel* m_project; + bool m_displayUnmodifiedRules; +signals: + +public slots: + +}; + +#endif // RULESETDIFFMODEL_H diff --git a/src/libgui/RuleSetViewDelegate.cpp b/src/libgui/RuleSetViewDelegate.cpp index c3603b3ec..89d895776 100644 --- a/src/libgui/RuleSetViewDelegate.cpp +++ b/src/libgui/RuleSetViewDelegate.cpp @@ -212,8 +212,7 @@ void RuleSetViewDelegate::paintRule(QPainter *painter, if (node != 0) { - FWOptions *ropt = node->rule->getOptionsObject(); - QString color = ropt->getStr("color").c_str(); + QString color = getRuleColor(node); if (!color.isEmpty()) { painter->fillRect(option.rect, QColor(color)); @@ -712,3 +711,9 @@ DrawingContext RuleSetViewDelegate::initContext( return ctx; } + +QString RuleSetViewDelegate::getRuleColor(RuleNode *node) const +{ + FWOptions *ropt = node->rule->getOptionsObject(); + return QString(ropt->getStr("color").c_str()); +} diff --git a/src/libgui/RuleSetViewDelegate.h b/src/libgui/RuleSetViewDelegate.h index 1c3ac24e4..560f61f5f 100644 --- a/src/libgui/RuleSetViewDelegate.h +++ b/src/libgui/RuleSetViewDelegate.h @@ -107,6 +107,8 @@ private: void paintMetric(QPainter *painter, const QStyleOptionViewItem &option, const QVariant &v) const; QString constructActionText(ActionDesc &actionDesc)const; + + virtual QString getRuleColor(RuleNode * node ) const; }; #endif // RULESETVIEWDELEGATE_H diff --git a/src/libgui/instDialog.cpp b/src/libgui/instDialog.cpp index 4044d4f28..430b10fb2 100644 --- a/src/libgui/instDialog.cpp +++ b/src/libgui/instDialog.cpp @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -161,6 +166,9 @@ instDialog::instDialog(QWidget *p) : QDialog(p) proc.setProcessChannelMode(QProcess::MergedChannels); m_dialog->fwWorkList->setSortingEnabled(true); + + connect(currentFirewallsBar, SIGNAL(valueChanged(int)), this, SIGNAL(currentFirewallsBarValueChanged(int))); + isAutoCompiling = false; } /* @@ -176,13 +184,14 @@ void instDialog::show(ProjectPanel *proj, std::set fws) { canceledAll = false; - if (isVisible()) return; + if (isVisible() || isAutoCompiling) return; lastPage = -1; installer = NULL; finished = false; page_1_op = INST_DLG_COMPILE; compile_complete = false; rejectDialogFlag = false; + isAutoCompiling = false; m_dialog->selectTable->clear(); this->project = proj; @@ -279,6 +288,15 @@ void instDialog::show(ProjectPanel *proj, showPage(CHOOSE_OBJECTS); } +void instDialog::autoCompile(ProjectPanel *project) +{ + show(project, false, false, std::set()); + hide(); + isAutoCompiling = true; + selectAllFirewalls(); + nextButton->click(); +} + instDialog::~instDialog() { if (inst_opt_dlg != NULL) delete inst_opt_dlg; @@ -333,6 +351,13 @@ void instDialog::mainLoopCompile() // setFinishEnabled(currentPage(), false); // m_dialog->inspectGeneratedFiles->setEnabled(compile_complete); } + + if (isAutoCompiling) { + finishButton->click(); + isAutoCompiling = false; + emit autoCompileDone(); + deleteLater(); + } } } @@ -466,10 +491,12 @@ void instDialog::showPage(const int page) setBackEnabled(page, true); } else { - mw->fileSave(); + if (!isAutoCompiling) + mw->fileSave(); currentFirewallsBar->reset(); currentFirewallsBar->setFormat("%v/%m"); currentFirewallsBar->setMaximum(compile_list_initial_size); + emit currentFirewallsBarMaximumValueChanged(currentFirewallsBar->maximum()); m_dialog->procLogDisplay->clear(); fillCompileUIList(); qApp->processEvents(); @@ -514,10 +541,11 @@ void instDialog::showPage(const int page) viewer = new FirewallCodeViewer( files, QString("") + firewalls.front()->getName().c_str() + "", + project, this); else viewer = new FirewallCodeViewer( - files, tr("Multiple firewalls"), this); + files, tr("Multiple firewalls"), project, this); viewer->hideCloseButton(); viewer->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); diff --git a/src/libgui/instDialog.h b/src/libgui/instDialog.h index 9bc013c44..16d60e573 100644 --- a/src/libgui/instDialog.h +++ b/src/libgui/instDialog.h @@ -135,6 +135,7 @@ class instDialog : public QDialog, public FakeWizard bool onlySelected; bool secondPageVisited; bool canceledAll; + bool isAutoCompiling; QTextCharFormat normal_format; QTextCharFormat error_format; @@ -234,6 +235,8 @@ protected: public slots: void show(ProjectPanel *project, bool install, bool onlySelected, std::set fws); + void autoCompile(ProjectPanel *project); + void compilerFinished(int ret_code, QProcess::ExitStatus); void installerFinished(int ret_code, QProcess::ExitStatus); void installerSuccess(); @@ -270,6 +273,9 @@ public slots: signals: void activateRule(ProjectPanel*, QString, QString, int); + void currentFirewallsBarValueChanged(int); + void currentFirewallsBarMaximumValueChanged(int); + void autoCompileDone(); }; diff --git a/src/libgui/instDialog_compile.cpp b/src/libgui/instDialog_compile.cpp index c4b2105c4..9e378e712 100644 --- a/src/libgui/instDialog_compile.cpp +++ b/src/libgui/instDialog_compile.cpp @@ -6,6 +6,11 @@ Author: Vadim Kurland vadim@fwbuilder.org + + Copyright (C) 2013 UNINETT AS + + Author: Sirius Bakke + $Id$ This program is free software which we release under the GNU General Public @@ -50,6 +55,7 @@ #include #include #include +#include #include using namespace std; @@ -211,6 +217,14 @@ Can't compile firewall policy."), args.push_back("-f"); args.push_back(project->getRCS()->getFileName()); + // If we are compiling in the background (for diff), set wdir to temp directory + if (isAutoCompiling) { + QDir tempDir(project->getTemporaryDirPath()); + if (!tempDir.exists()) + tempDir.mkdir(project->getTemporaryDirPath()); + wdir = tempDir.absolutePath(); + } + if (wdir!="") { args.push_back("-d"); @@ -276,7 +290,7 @@ void instDialog::compilerFinished(int ret_code, QProcess::ExitStatus status) return; } - if (ret_code==0 && status==QProcess::NormalExit) + if (ret_code==0 && status==QProcess::NormalExit && !isAutoCompiling) { opSuccess(cnf.fwobj); // mw->updateLastCompiledTimestamp(cnf.fwobj); diff --git a/src/libgui/libgui.pro b/src/libgui/libgui.pro index 991776853..2e290d65e 100644 --- a/src/libgui/libgui.pro +++ b/src/libgui/libgui.pro @@ -223,6 +223,11 @@ HEADERS += ../../config.h \ importFirewallConfigurationWizard/IC_NetworkZonesPage.h \ importFirewallConfigurationWizard/ImportFirewallConfigurationWizard.h \ importFirewallConfigurationWizard/ImporterThread.h \ + RuleSetDiffDialog.h \ + RuleSetDiffDelegate.h \ + RuleSetDiffModel.h \ + BackgroundCompileInfoWidget.h \ + temporarydir.h @@ -439,7 +444,12 @@ SOURCES += ProjectPanel.cpp \ importFirewallConfigurationWizard/IC_ProgressPage.cpp \ importFirewallConfigurationWizard/IC_NetworkZonesPage.cpp \ importFirewallConfigurationWizard/ImportFirewallConfigurationWizard.cpp \ - importFirewallConfigurationWizard/ImporterThread.cpp + importFirewallConfigurationWizard/ImporterThread.cpp \ + RuleSetDiffDialog.cpp \ + RuleSetDiffDelegate.cpp \ + RuleSetDiffModel.cpp \ + BackgroundCompileInfoWidget.cpp \ + temporarydir.cpp FORMS = FWBMainWindow_q.ui \ @@ -573,6 +583,7 @@ FORMS = FWBMainWindow_q.ui \ importFirewallConfigurationWizard/ic_platformwarningpage_q.ui \ importFirewallConfigurationWizard/ic_progresspage_q.ui \ importFirewallConfigurationWizard/ic_networkzonespage_q.ui \ + rulesetdiffdialog_q.ui # fwtransfer stuff. diff --git a/src/libgui/prefsdialog_q.ui b/src/libgui/prefsdialog_q.ui index b2c1fedff..ca2e35dbf 100644 --- a/src/libgui/prefsdialog_q.ui +++ b/src/libgui/prefsdialog_q.ui @@ -72,7 +72,7 @@ - 1 + 0 @@ -383,7 +383,7 @@ own library of templates and use it in addition to the one we provide - 2 + 0 @@ -991,7 +991,16 @@ own library of templates and use it in addition to the one we provide QFrame::Plain - + + 0 + + + 0 + + + 0 + + 0 @@ -1034,8 +1043,8 @@ own library of templates and use it in addition to the one we provide <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/"><span style=" font-family:'Lucida Grande'; font-size:8pt; text-decoration: underline; color:#0000ff;">http://www.chiark.greenend.org.uk/~sgtatham/putty/</span></a></p></body></html> +</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/"><span style=" font-family:'Lucida Grande'; text-decoration: underline; color:#0000ff;">http://www.chiark.greenend.org.uk/~sgtatham/putty/</span></a></p></body></html> true @@ -1117,6 +1126,9 @@ are never stored permanently) + + true + Labels @@ -1524,6 +1536,206 @@ are never stored permanently) + + + Diff + + + + + + + + Rule Set Diff Viewer + + + + + + Use these colors to mark rules in the diff viewer + + + Qt::AlignCenter + + + false + + + + + + + 20 + + + + + + + + + + + + Remove + + + true + + + + + + + Add + + + true + + + + + + + + + + + + + + Edit + + + true + + + + + + + Move + + + true + + + + + + + + + + + + + + + + + + + + + + + Display unmodified rules + + + + + + + + + + Generated Output Diff Viewer + + + + + + Firewall Builder may compile your firewalls automaticly +when you load a file. The generated files will be stored +in a temporary directory and are deleted when you quit +the application. This will enable you to compare the +output of the generated files between the current version +and the unmodified version of the file you loaded. + + + + + + + Enable auto compiling when loading file + + + + + + + + + A full path to the graphical diff utility: + + + Qt::AlignVCenter + + + true + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Browse... + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 339 + 20 + + + + + + Platforms and OS @@ -1642,8 +1854,8 @@ are never stored permanently) accept() - 697 - 566 + 634 + 552 20 @@ -1658,8 +1870,8 @@ are never stored permanently) reject() - 780 - 566 + 720 + 552 20 @@ -1674,8 +1886,8 @@ are never stored permanently) changeIconSize25() - 243 - 360 + 119 + 101 20 @@ -1690,8 +1902,8 @@ are never stored permanently) findSCP() - 757 - 182 + 119 + 78 334 @@ -1722,8 +1934,8 @@ are never stored permanently) changeTreeFont() - 152 - 125 + 175 + 86 334 @@ -1738,8 +1950,8 @@ are never stored permanently) changeOrangeColor() - 353 - 160 + 149 + 94 20 @@ -1754,8 +1966,8 @@ are never stored permanently) changeBlueColor() - 353 - 286 + 149 + 94 20 @@ -1770,8 +1982,8 @@ are never stored permanently) changeIconSize16() - 243 - 327 + 119 + 101 20 @@ -1802,8 +2014,8 @@ are never stored permanently) objTooltipsEnabled(bool) - 65 - 53 + 57 + 67 3 @@ -1818,8 +2030,8 @@ are never stored permanently) changeCompilerOutputFont() - 152 - 169 + 175 + 88 334 @@ -1834,8 +2046,8 @@ are never stored permanently) findWDir() - 757 - 82 + 709 + 75 20 @@ -1850,8 +2062,8 @@ are never stored permanently) findDataDir() - 20 - 20 + 641 + 83 20 @@ -1866,8 +2078,8 @@ are never stored permanently) changeRedColor() - 353 - 118 + 149 + 94 20 @@ -1882,8 +2094,8 @@ are never stored permanently) changeYellowColor() - 353 - 202 + 149 + 94 20 @@ -1898,8 +2110,8 @@ are never stored permanently) findSSH() - 757 - 114 + 119 + 74 20 @@ -1914,8 +2126,8 @@ are never stored permanently) changeGreenColor() - 353 - 244 + 149 + 94 20 @@ -1930,8 +2142,8 @@ are never stored permanently) changePurpleColor() - 353 - 328 + 149 + 94 20 @@ -1946,8 +2158,8 @@ are never stored permanently) changeShowIcons() - 43 - 181 + 65 + 61 20 @@ -1962,8 +2174,8 @@ are never stored permanently) changeGrayColor() - 353 - 370 + 149 + 94 20 @@ -1971,6 +2183,86 @@ are never stored permanently) + + addColorBtn + clicked() + prefsDialog_q + changeAddColor() + + + 61 + 113 + + + 165 + 540 + + + + + editColorBtn + clicked() + prefsDialog_q + changeEditColor() + + + 69 + 155 + + + 141 + 547 + + + + + moveColorBtn + clicked() + prefsDialog_q + changeMoveColor() + + + 64 + 196 + + + 126 + 554 + + + + + removeColorBtn + clicked() + prefsDialog_q + changeRemoveColor() + + + 56 + 237 + + + 117 + 535 + + + + + browseForDiff + clicked() + prefsDialog_q + findDiff() + + + 327 + 452 + + + 411 + 540 + + + findSSH() @@ -1980,5 +2272,6 @@ are never stored permanently) changeTreeFont() changeCompilerOutputFont() objTooltipsEnabled(bool) + findDiff() diff --git a/src/libgui/projectpanel_q.ui b/src/libgui/projectpanel_q.ui index 3248b7f29..898b65bab 100644 --- a/src/libgui/projectpanel_q.ui +++ b/src/libgui/projectpanel_q.ui @@ -18,7 +18,16 @@ :/Images/fwbuilder3.png:/Images/fwbuilder3.png - + + 2 + + + 2 + + + 2 + + 2 @@ -46,7 +55,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -196,6 +214,41 @@ + + + + View diff + + + View diff + + + View diff + + + ... + + + + :/Icons/newobject_32.png:/Icons/newobject_32.png + + + + 25 + 25 + + + + false + + + QToolButton::DelayedPopup + + + Qt::NoArrow + + + @@ -325,8 +378,8 @@ compileThis() - 276 - 35 + 750 + 37 417 @@ -341,8 +394,8 @@ installThis() - 319 - 35 + 789 + 37 417 @@ -357,8 +410,8 @@ addRule() - 211 - 27 + 195 + 31 417 @@ -373,8 +426,8 @@ inspectThis() - 345 - 22 + 828 + 26 417 @@ -382,11 +435,28 @@ + + diff_this_fw + clicked() + ProjectPanel_q + diffThis() + + + 693 + 18 + + + 559 + 0 + + + compileThis() installThis() addRule() inspectThis() + diffThis() diff --git a/src/libgui/rulesetdiffdialog_q.ui b/src/libgui/rulesetdiffdialog_q.ui new file mode 100644 index 000000000..706d6ba00 --- /dev/null +++ b/src/libgui/rulesetdiffdialog_q.ui @@ -0,0 +1,443 @@ + + + RuleSetDiffDialog_q + + + Qt::ApplicationModal + + + + 0 + 0 + 800 + 600 + + + + Diff Viewer + + + + + + + + + + + + Firewall + + + + + + + + 1 + 0 + + + + + 200 + 0 + + + + + + + + + + + + Ruleset + + + + + + + + 1 + 0 + + + + + 200 + 0 + + + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 6 + + + 6 + + + 0 + + + + + + 0 + 0 + + + + + 16 + 16 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 65 + 0 + + + + Add (0) + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 65 + 0 + + + + Edit (0) + + + + + + + + + 6 + + + + + + 0 + 0 + + + + + 16 + 16 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 65 + 0 + + + + Remove (0) + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 65 + 0 + + + + Move (0) + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Close + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::LeftToRight + + + Display umodified rules + + + + + + + + + + + + + QLayout::SetNoConstraint + + + 10 + + + + + Current version + + + Qt::AlignCenter + + + + + + + Original version + + + Qt::AlignCenter + + + + + + + + 1 + 1 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + 1 + 1 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + + pushButton + clicked() + RuleSetDiffDialog_q + accept() + + + 738 + 23 + + + 587 + 22 + + + + + diff --git a/src/libgui/temporarydir.cpp b/src/libgui/temporarydir.cpp new file mode 100644 index 000000000..6b8ed3b9a --- /dev/null +++ b/src/libgui/temporarydir.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Backported to Qt 4 from Qt 5.1 + +#include "temporarydir.h" + +#include +#include "qplatformdefs.h" +#include + +//************* TemporaryDirPrivate +class TemporaryDirPrivate +{ +public: + TemporaryDirPrivate(); + ~TemporaryDirPrivate(); + + void create(const QString &templateName); + + QString path; + bool autoRemove; + bool success; +}; + +TemporaryDirPrivate::TemporaryDirPrivate() + : autoRemove(true), + success(false) +{ +} + +TemporaryDirPrivate::~TemporaryDirPrivate() +{ +} + +static QString defaultTemplateName() +{ + QString baseName; + baseName = QLatin1String("qt_temp"); + + return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX"); +} + +static char *q_mkdtemp(char *templateName) +{ + static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + const size_t length = strlen(templateName); + + char *XXXXXX = templateName + length - 6; + + if ((length < 6u) || strncmp(XXXXXX, "XXXXXX", 6)) + return 0; + + for (int i = 0; i < 256; ++i) { + int v = qrand(); + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + QString templateNameStr = QFile::decodeName(templateName); + + QDir tempPath(QDir::tempPath()); + if (!tempPath.mkdir(templateNameStr)) + continue; + return templateName; + } + return 0; +} + +void TemporaryDirPrivate::create(const QString &templateName) +{ + QByteArray buffer = QFile::encodeName(templateName); + if (!buffer.endsWith("XXXXXX")) + buffer += "XXXXXX"; + if (q_mkdtemp(buffer.data())) { // modifies buffer + success = true; + path = QFile::decodeName(buffer.constData()); + } +} + +//************* TemporaryDir + +/*! + \class QTemporaryDir + \inmodule QtCore + \reentrant + \brief The QTemporaryDir class creates a unique directory for temporary use. + + \ingroup io + + + QTemporaryDir is used to create unique temporary dirs safely. + The dir itself is created by the constructor. The name of the + temporary directory is guaranteed to be unique (i.e., you are + guaranteed to not overwrite an existing dir), and the directory will + subsequently be removed upon destruction of the QTemporaryDir + object. The directory name is either auto-generated, or created based + on a template, which is passed to QTemporaryDir's constructor. + + Example: + + \snippet code/src_corelib_io_qtemporarydir.cpp 0 + + It is very important to test that the temporary directory could be + created, using isValid(). Do not use exists(), since a default-constructed + QDir represents the current directory, which exists. + + The path to the temporary dir can be found by calling path(). + + A temporary directory will have some static part of the name and some + part that is calculated to be unique. The default path will be + determined from QCoreApplication::applicationName() (otherwise \c qt_temp) and will + be placed into the temporary path as returned by QDir::tempPath(). + If you specify your own path, a relative path will not be placed in the + temporary directory by default, but be relative to the current working directory. + In all cases, a random string will be appended to the path in order to make it unique. + + \sa QDir::tempPath(), QDir, QTemporaryFile +*/ + +/*! + Constructs a QTemporaryDir using as template the application name + returned by QCoreApplication::applicationName() (otherwise \c qt_temp). + The directory is stored in the system's temporary directory, QDir::tempPath(). + + \sa QDir::tempPath() +*/ +TemporaryDir::TemporaryDir() + : d_ptr(new TemporaryDirPrivate) +{ + d_ptr->create(defaultTemplateName()); +} + +/*! + Constructs a QTemporaryFile with a template name of \a templateName. + + If \a templateName is a relative path, the path will be relative to the + current working directory. You can use QDir::tempPath() to construct \a + templateName if you want use the system's temporary directory. + + If the \a templateName ends with XXXXXX it will be used as the dynamic portion + of the directory name, otherwise it will be appended. + Unlike QTemporaryFile, XXXXXX in the middle of the template string is not supported. + + \sa QDir::tempPath() +*/ +TemporaryDir::TemporaryDir(const QString &templateName) + : d_ptr(new TemporaryDirPrivate) +{ + if (templateName.isEmpty()) + d_ptr->create(defaultTemplateName()); + else + d_ptr->create(templateName); +} + +/*! + Destroys the temporary directory object. + If auto remove mode was set, it will automatically delete the directory + including all its contents. + + \sa autoRemove() +*/ +TemporaryDir::~TemporaryDir() +{ + if (d_ptr->autoRemove) + remove(); +} + +/*! + Returns true if the QTemporaryDir was created successfully. +*/ +bool TemporaryDir::isValid() const +{ + return d_ptr->success; +} + +/*! + Returns the path to the temporary directory. + Empty if the QTemporaryDir could not be created. +*/ +QString TemporaryDir::path() const +{ + return d_ptr->path; +} + +/*! + Returns true if the QTemporaryDir is in auto remove + mode. Auto-remove mode will automatically delete the directory from + disk upon destruction. This makes it very easy to create your + QTemporaryDir object on the stack, fill it with files, do something with + the files, and finally on function return it will automatically clean up + after itself. + + Auto-remove is on by default. + + \sa setAutoRemove(), remove() +*/ +bool TemporaryDir::autoRemove() const +{ + return d_ptr->autoRemove; +} + +/*! + Sets the QTemporaryDir into auto-remove mode if \a b is true. + + Auto-remove is on by default. + + \sa autoRemove(), remove() +*/ +void TemporaryDir::setAutoRemove(bool b) +{ + d_ptr->autoRemove = b; +} + +/*! + Removes the temporary directory, including all its contents. + + Returns true if removing was successful. +*/ +bool TemporaryDir::remove() +{ + if (!d_ptr->success) + return false; + Q_ASSERT(!path().isEmpty()); + Q_ASSERT(path() != QLatin1String(".")); + + return removeRecursively(path()); +} + +// This method is based on QTemporaryDir::remove from the Qt 5.1 branch +bool TemporaryDir::removeRecursively(const QString& dirPath) { + if (!QDir(dirPath).exists()) + return true; + + bool success = true; + // not empty -- we must empty it first + QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot); + while (di.hasNext()) { + di.next(); + const QFileInfo& fi = di.fileInfo(); + bool ok; + if (fi.isDir() && !fi.isSymLink()) + ok = removeRecursively(di.filePath()); + else + ok = QFile::remove(di.filePath()); + if (!ok) + success = false; + } + + if (success) { + QDir dir(dirPath); + QString path = dir.absolutePath(); + dir.cdUp(); + success = dir.rmdir(path); + } + + return success; +} diff --git a/src/libgui/temporarydir.h b/src/libgui/temporarydir.h new file mode 100644 index 000000000..10e4d7e0d --- /dev/null +++ b/src/libgui/temporarydir.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Backported to Qt 4 from Qt 5.1 + +#ifndef TEMPORARYDIR_H +#define TEMPORARYDIR_H + +#include +#include + +class TemporaryDirPrivate; + +class TemporaryDir +{ +public: + TemporaryDir(); + explicit TemporaryDir(const QString &templateName); + ~TemporaryDir(); + + bool isValid() const; + + bool autoRemove() const; + void setAutoRemove(bool b); + bool remove(); + + QString path() const; + +private: + QScopedPointer d_ptr; + + Q_DISABLE_COPY(TemporaryDir) + bool removeRecursively(const QString& path); +}; + +#endif // TEMPORARYDIR_H