From 54f6bae48faa1a58b53222f3e67a9c5f0c6d2810 Mon Sep 17 00:00:00 2001 From: Theron Tock Date: Thu, 16 Jun 2011 14:49:06 -0700 Subject: [PATCH] Added support for user-defined folders. It's just a ui/display thing. The FWObject has a property "folder" that controls which sub-folder to display in. The placement of the object in the tree doesn't change even when placed into a user-defined folder. Turned on drag/drop in the object tree so that objects can be moved into these new folders (however, disabled dragging of system folders). --- src/libfwbuilder/etc/fwbuilder.dtd | 10 +- src/libfwbuilder/etc/fwbuilder.dtd.in | 10 +- src/libfwbuilder/src/fwbuilder/FWObject.cpp | 62 +++----- src/libfwbuilder/src/fwbuilder/Tools.cpp | 36 +++++ src/libfwbuilder/src/fwbuilder/Tools.h | 8 +- src/libgui/ObjectManipulator.cpp | 93 +++++++++--- src/libgui/ObjectManipulator.h | 5 + src/libgui/ObjectManipulator_ops.cpp | 63 ++++++++ src/libgui/ObjectManipulator_tree_ops.cpp | 63 +++++++- src/libgui/ObjectTreeView.cpp | 150 +++++++++++--------- src/libgui/ObjectTreeView.h | 8 +- src/libgui/ObjectTreeViewItem.cpp | 78 ++++------ src/libgui/ObjectTreeViewItem.h | 19 ++- src/libgui/RuleSetModel.cpp | 1 - 14 files changed, 392 insertions(+), 214 deletions(-) diff --git a/src/libfwbuilder/etc/fwbuilder.dtd b/src/libfwbuilder/etc/fwbuilder.dtd index 5fef3f726..2140db650 100644 --- a/src/libfwbuilder/etc/fwbuilder.dtd +++ b/src/libfwbuilder/etc/fwbuilder.dtd @@ -67,6 +67,7 @@ comment %STRING; #IMPLIED id ID #REQUIRED ro %BOOLEAN; #IMPLIED + folder %STRING; #IMPLIED '> @@ -112,7 +113,8 @@ diff --git a/src/libfwbuilder/etc/fwbuilder.dtd.in b/src/libfwbuilder/etc/fwbuilder.dtd.in index 00466a529..a4f4f6d5c 100644 --- a/src/libfwbuilder/etc/fwbuilder.dtd.in +++ b/src/libfwbuilder/etc/fwbuilder.dtd.in @@ -67,6 +67,7 @@ comment %STRING; #IMPLIED id ID #REQUIRED ro %BOOLEAN; #IMPLIED + folder %STRING; #IMPLIED '> @@ -112,7 +113,8 @@ diff --git a/src/libfwbuilder/src/fwbuilder/FWObject.cpp b/src/libfwbuilder/src/fwbuilder/FWObject.cpp index 3781a7e77..b2c28054f 100644 --- a/src/libfwbuilder/src/fwbuilder/FWObject.cpp +++ b/src/libfwbuilder/src/fwbuilder/FWObject.cpp @@ -64,27 +64,6 @@ string FWObject::NOT_FOUND=""; //#define TI_DEBUG -static void -parseKeywordsFromString(set &keywords, set &allKeywords, - const string &str) -{ - if (str.empty()) return; - string::size_type pos = 0; - for ( ; ; ) { - string::size_type delim = str.find(',', pos); - if (delim == string::npos) { - keywords.insert(str.substr(pos)); - allKeywords.insert(str.substr(pos)); - break; - } else { - keywords.insert(str.substr(pos, delim - pos)); - allKeywords.insert(str.substr(pos, delim - pos)); - pos = delim + 1; - } - } -} - - void FWObject::fromXML(xmlNodePtr root) throw(FWException) { assert(root!=NULL); @@ -111,12 +90,23 @@ void FWObject::fromXML(xmlNodePtr root) throw(FWException) FREEXMLBUFF(n); } - if (dbroot != 0) { - n = FROMXMLCAST(xmlGetProp(root, TOXMLCAST("keywords"))); - if (n != 0) { - parseKeywordsFromString(keywords, dbroot->keywords, n); - FREEXMLBUFF(n); - } + n = FROMXMLCAST(xmlGetProp(root, TOXMLCAST("keywords"))); + if (n != 0) { + keywords = stringToSet(n); + dbroot->keywords.insert(keywords.begin(), keywords.end()); + FREEXMLBUFF(n); + } + + n = FROMXMLCAST(xmlGetProp(root, TOXMLCAST("subfolders"))); + if (n != 0) { + setStr("subfolders", n); + FREEXMLBUFF(n); + } + + n = FROMXMLCAST(xmlGetProp(root, TOXMLCAST("folder"))); + if (n != 0) { + setStr("folder", n); + FREEXMLBUFF(n); } n=FROMXMLCAST(xmlGetProp(root,TOXMLCAST("ro"))); @@ -160,20 +150,6 @@ xmlNodePtr FWObject::toXML(xmlNodePtr xml_parent_node) throw(FWException) return toXML(xml_parent_node, true); } -static string keywordsAsString(const set &keywords) -{ - if (keywords.empty()) return ""; - set::const_iterator iter = keywords.begin(); - string ret = *iter; - ++iter; - while (iter != keywords.end()) { - ret += ","; - ret += *iter; - ++iter; - } - return ret; -} - xmlNodePtr FWObject::toXML(xmlNodePtr parent, bool process_children) throw(FWException) { @@ -195,7 +171,7 @@ xmlNodePtr FWObject::toXML(xmlNodePtr parent, bool process_children) if (!keywords.empty()) { xmlNewProp(me, TOXMLCAST("keywords"), - STRTOXMLCAST(keywordsAsString(keywords))); + STRTOXMLCAST(setToString(keywords))); } for(map::const_iterator i=data.begin(); i!=data.end(); ++i) @@ -669,7 +645,7 @@ void FWObject::remStr(const string &name) void FWObject::setStr(const string &name, const string &val) { - if (name[0]!='.') checkReadOnly(); + if (name[0]!='.' && name != "folder") checkReadOnly(); string old_val = data[name]; if (old_val != val) { diff --git a/src/libfwbuilder/src/fwbuilder/Tools.cpp b/src/libfwbuilder/src/fwbuilder/Tools.cpp index 5830d2b92..0604025e8 100644 --- a/src/libfwbuilder/src/fwbuilder/Tools.cpp +++ b/src/libfwbuilder/src/fwbuilder/Tools.cpp @@ -228,4 +228,40 @@ string stringify(const vector& parts, const string& delimiter) return result; } + +set stringToSet(const string &str) +{ + set ret; + size_t lastpos = 0; + for ( ; ; ) { + size_t pos = str.find(',', lastpos); + if (pos == string::npos) { + if (lastpos < str.size()) { + ret.insert(str.substr(lastpos)); + } + return ret; + } + ret.insert(str.substr(lastpos, pos - lastpos)); + lastpos = pos + 1; + } +} + + +string setToString(const set &s) +{ + string ret; + set::const_iterator iter; + bool first = true; + for (iter = s.begin(); iter != s.end(); ++iter) { + if (first) { + first = false; + } else { + ret += ","; + } + ret += *iter; + } + + return ret; +} + } diff --git a/src/libfwbuilder/src/fwbuilder/Tools.h b/src/libfwbuilder/src/fwbuilder/Tools.h index 113120b2a..0e222ab0b 100644 --- a/src/libfwbuilder/src/fwbuilder/Tools.h +++ b/src/libfwbuilder/src/fwbuilder/Tools.h @@ -45,6 +45,7 @@ #include #include #include +#include #ifndef _WIN32 # include @@ -109,8 +110,11 @@ namespace libfwbuilder * Strip identifier from string 'in' and return as string. */ std::string strip(const std::string& in, const std::string& identifier); + + /* Convert from string <-> set, using comma as delim */ + std::set stringToSet(const std::string &str); + std::string setToString(const std::set &s); + } #endif - - diff --git a/src/libgui/ObjectManipulator.cpp b/src/libgui/ObjectManipulator.cpp index aba9ce888..ab9d1d883 100644 --- a/src/libgui/ObjectManipulator.cpp +++ b/src/libgui/ObjectManipulator.cpp @@ -405,6 +405,13 @@ static void addKeywordsMenu(ObjectManipulator *om, QMenu *menu) void ObjectManipulator::contextMenuRequested(const QPoint &pos) { + if (popup_menu == NULL) + { + popup_menu = new QMenu(this); + popup_menu->setObjectName("objectTreeContextMenu"); + } else + popup_menu->clear(); + /* in extended selection mode there may be several selected items */ QTreeWidget *objTreeView = getCurrentObjectTree(); @@ -417,19 +424,24 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) ObjectTreeViewItem *otvi=dynamic_cast(item); if (otvi==NULL) return; // happens when user clicks outside an item + FWObject *obj = otvi->getFWObject(); + if (obj == 0) { + assert(otvi->getUserFolderParent() != 0); + QAction *action = + popup_menu->addAction(tr("Remove"), this, SLOT(removeUserFolder())); + if (otvi->childCount() > 0) { + action->setEnabled(false); + } + popup_menu->exec(QCursor::pos()); + return; + } + if (!getCurrentObjectTree()->isSelected(otvi->getFWObject())) openObjectInTree( otvi, true ); //if (currentObj==NULL) currentObj=otvi->getFWObject(); FWObject *currentObj = getSelectedObject(); - if (popup_menu == NULL) - { - popup_menu = new QMenu(this); - popup_menu->setObjectName("objectTreeContextMenu"); - } else - popup_menu->clear(); - if (item->childCount() > 0) { if (item->isExpanded()) @@ -535,7 +547,7 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) if (getCurrentObjectTree()->getNumSelected()==1) { - + bool addSubfolder = false; if ( (Firewall::isA(currentObj) || Host::isA(currentObj)) && ! currentObj->isReadOnly() ) { @@ -639,16 +651,21 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) popup_menu, StateSyncClusterGroup::TYPENAME)); } - if (currentObj->getPath(true)=="Firewalls") + if (currentObj->getPath(true)=="Firewalls") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, Firewall::TYPENAME)); + } - if (currentObj->getPath(true)=="Clusters") + if (currentObj->getPath(true)=="Clusters") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, Cluster::TYPENAME)); + } if (currentObj->getPath(true)=="Objects/Addresses") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, IPv4::TYPENAME)); AddObjectActions.append( @@ -657,26 +674,33 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) if (currentObj->getPath(true)=="Objects/DNS Names") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, DNSName::TYPENAME)); } if (currentObj->getPath(true)=="Objects/Address Tables") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, AddressTable::TYPENAME)); } - if (currentObj->getPath(true)=="Objects/Address Ranges") + if (currentObj->getPath(true)=="Objects/Address Ranges") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, AddressRange::TYPENAME)); + } - if (currentObj->getPath(true)=="Objects/Hosts") + if (currentObj->getPath(true)=="Objects/Hosts") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, Host::TYPENAME)); + } if (currentObj->getPath(true)=="Objects/Networks") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, Network::TYPENAME)); AddObjectActions.append( @@ -684,51 +708,76 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) } if (currentObj->getPath(true)=="Objects/Groups") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, ObjectGroup::TYPENAME)); AddObjectActions.append( addNewObjectMenuItem(popup_menu, DynamicGroup::TYPENAME)); } - if (currentObj->getPath(true)=="Services/Custom") + if (currentObj->getPath(true)=="Services/Custom") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, CustomService::TYPENAME)); + } - if (currentObj->getPath(true)=="Services/IP") + if (currentObj->getPath(true)=="Services/IP") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, IPService::TYPENAME)); + } if (currentObj->getPath(true)=="Services/ICMP") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, ICMPService::TYPENAME)); AddObjectActions.append( addNewObjectMenuItem(popup_menu, ICMP6Service::TYPENAME)); } - if (currentObj->getPath(true)=="Services/TCP") + if (currentObj->getPath(true)=="Services/TCP") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, TCPService::TYPENAME)); + } - if (currentObj->getPath(true)=="Services/UDP") + if (currentObj->getPath(true)=="Services/UDP") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, UDPService::TYPENAME)); + } - if (currentObj->getPath(true)=="Services/TagServices") + if (currentObj->getPath(true)=="Services/TagServices") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, TagService::TYPENAME)); + } - if (currentObj->getPath(true)=="Services/Groups") + if (currentObj->getPath(true)=="Services/Groups") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, ServiceGroup::TYPENAME)); + } - if (currentObj->getPath(true)=="Services/Users") + if (currentObj->getPath(true)=="Services/Users") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, UserService::TYPENAME)); + } - if (currentObj->getPath(true)=="Time") + if (currentObj->getPath(true)=="Time") { + addSubfolder = true; AddObjectActions.append( addNewObjectMenuItem(popup_menu, Interval::TYPENAME)); + } + + if (addSubfolder) { + QAction *action = popup_menu->addAction(tr("New Subfolder"), this, + SLOT(addSubfolderSlot())); + action->setData(currentObj->getId()); + AddObjectActions.append(action); + } popup_menu->addSeparator(); @@ -742,7 +791,7 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) findID->setEnabled( !FWBTree().isStandardFolder(currentObj)); whereUsedID->setEnabled( !FWBTree().isStandardFolder(currentObj)); } - + popup_menu->addSeparator(); popup_menu->addAction( tr("Group"), this, SLOT( groupObjects() ) ) ->setDisabled(getCurrentObjectTree()->getNumSelected()==1); @@ -855,7 +904,7 @@ void ObjectManipulator::contextMenuRequested(const QPoint &pos) // if (inDeletedObjects) movID->setText( tr("Undelete...") ); - popup_menu->exec( objTreeView->mapToGlobal( pos ) ); + popup_menu->exec(QCursor::pos()); } bool ObjectManipulator::getDeleteMenuState(FWObject *obj) diff --git a/src/libgui/ObjectManipulator.h b/src/libgui/ObjectManipulator.h index 9b1a54f90..42c426894 100644 --- a/src/libgui/ObjectManipulator.h +++ b/src/libgui/ObjectManipulator.h @@ -190,6 +190,10 @@ public slots: void selectionChanged(QTreeWidgetItem *cur); + void removeUserFolder(); + void moveItems(ObjectTreeViewItem *dest, + const std::list &items); + /** * open object obj in the editor. Does not open editor panel * if it is closed. Asks FWWindow permission to own editor. @@ -268,6 +272,7 @@ public slots: virtual void simulateInstall(); virtual void findWhereUsedSlot(); + void addSubfolderSlot(); void addNewKeywordSlot(); void processKeywordSlot(); diff --git a/src/libgui/ObjectManipulator_ops.cpp b/src/libgui/ObjectManipulator_ops.cpp index 10b6606d2..82f74c4e6 100644 --- a/src/libgui/ObjectManipulator_ops.cpp +++ b/src/libgui/ObjectManipulator_ops.cpp @@ -743,3 +743,66 @@ void ObjectManipulator::processKeywordSlot() doKeyword(getCurrentObjectTree()->getSelectedObjects(), (list[0] == "add"), list[1].toUtf8().constData(), m_project); } + + +void ObjectManipulator::addSubfolderSlot() +{ + const QAction *qAct = dynamic_cast(sender()); + if (qAct == 0) return; + + FWObject *obj = getCurrentObjectTree()->getCurrentObject(); + assert(obj->getId() == qAct->data().toInt()); + + QString folder = QInputDialog::getText(0, tr("Add Subfolder"), + tr("Enter new subfolder name")); + folder = folder.simplified(); + if (folder.isEmpty()) return; + if (fwbdebug) { + qDebug() << "ObjectManipulator::addSubfolder: " << folder; + } + + set folders = stringToSet(obj->getStr("subfolders")); + folders.insert(folder.toUtf8().constData()); + string encoded = setToString(folders); + + obj->setStr("subfolders", encoded); + + QTreeWidgetItem *item = getCurrentObjectTree()->currentItem(); + ObjectTreeViewItem *sub = new ObjectTreeViewItem(item); + sub->setUserFolderParent(obj); + sub->setUserFolderName(folder); + sub->setText(0, folder); + sub->setIcon(0, QIcon(LoadPixmap(":/Icons/SystemGroup/icon-tree"))); + refreshSubtree(item, sub); +} + + +void ObjectManipulator::removeUserFolder() +{ + ObjectTreeViewItem *item = dynamic_cast + (getCurrentObjectTree()->currentItem()); + if (item == 0 || item->getUserFolderParent() == 0) return; + ObjectTreeViewItem *parent = dynamic_cast + (item->parent()); + assert(parent != 0); + + FWObject *parentObj = parent->getFWObject(); + set folders = stringToSet(parentObj->getStr("subfolders")); + folders.erase(item->getUserFolderName().toUtf8().constData()); + parentObj->setStr("subfolders", setToString(folders)); + + QList children = item->takeChildren(); + while (!children.isEmpty()) { + ObjectTreeViewItem *child = dynamic_cast + (children.takeFirst()); + assert(child != 0); + child->getFWObject()->setStr("folder", ""); + parent->addChild(child); + } + + parent->removeChild(item); + delete item; + + refreshSubtree(parent, 0); + +} diff --git a/src/libgui/ObjectManipulator_tree_ops.cpp b/src/libgui/ObjectManipulator_tree_ops.cpp index b5c3a0a64..f60736195 100644 --- a/src/libgui/ObjectManipulator_tree_ops.cpp +++ b/src/libgui/ObjectManipulator_tree_ops.cpp @@ -242,7 +242,11 @@ ObjectTreeViewItem* ObjectManipulator::insertObject(ObjectTreeViewItem *itm, nitm->setIcon( 0, QIcon(pm) ); // nitm->setIcon( 1, QIcon(pm) ); - nitm->setFlags(nitm->flags() | Qt::ItemIsDragEnabled); + if (FWBTree().isSystem(obj)) { + nitm->setFlags(nitm->flags() & ~Qt::ItemIsDragEnabled); + } else { + nitm->setFlags(nitm->flags() | Qt::ItemIsDragEnabled); + } nitm->setProperty("type", obj->getTypeName().c_str() ); nitm->setFWObject( obj ); @@ -271,6 +275,20 @@ void ObjectManipulator::insertSubtree(ObjectTreeViewItem *itm, FWObject *obj) if (FWBTree().isStandardFolder(obj)) nitm->setExpanded( st->getExpandTree()); + QMap folders; + set subfolders = stringToSet(obj->getStr("subfolders")); + set::const_iterator iter; + for (iter = subfolders.begin(); iter != subfolders.end(); ++iter) { + ObjectTreeViewItem *sub = new ObjectTreeViewItem(nitm); + sub->setUserFolderParent(obj); + QString name = QString::fromUtf8((*iter).c_str()); + sub->setUserFolderName(name); + sub->setText(0, name); + sub->setIcon(0, QIcon(LoadPixmap(":/Icons/SystemGroup/icon-tree"))); + + folders[name] = sub; + } + if (Cluster::isA(obj)) { for (FWObjectTypedChildIterator it = obj->findByType(StateSyncClusterGroup::TYPENAME); @@ -313,12 +331,17 @@ void ObjectManipulator::insertSubtree(ObjectTreeViewItem *itm, FWObject *obj) return; } - for (list::iterator m=obj->begin(); m!=obj->end(); m++) { FWObject *o1=*m; if (FWReference::cast(o1)!=NULL) continue; - insertSubtree( nitm, o1 ); + + ObjectTreeViewItem *item = 0; + QString folder = QString::fromUtf8(o1->getStr("folder").c_str()); + item = folders.value(folder); + if (item == 0) item = nitm; + + insertSubtree( item, o1 ); } } @@ -591,16 +614,15 @@ void ObjectManipulator::addLib(FWObject *lib) SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*) ), this, SLOT(selectionChanged(QTreeWidgetItem*))); + connect(objTreeView, SIGNAL(moveItems_sign(ObjectTreeViewItem *, const std::list &)), + this, SLOT(moveItems(ObjectTreeViewItem *, const std::list &))); ObjectTreeViewItem *itm1=new ObjectTreeViewItem( objTreeView ); itm1->setLib(""); itm1->setExpanded(TRUE); -/* need to enable dragging in order to avoid object highlighting in - * the tree when user drags mouse cursor */ - - itm1->setFlags(itm1->flags() | Qt::ItemIsDragEnabled); + itm1->setFlags(itm1->flags() & ~Qt::ItemIsDragEnabled); itm1->setText( 0, getTreeLabel(lib, 0) ); itm1->setText( 1, getTreeLabel(lib, 1) ); @@ -682,3 +704,30 @@ void ObjectManipulator::refreshSubtree(QTreeWidgetItem *parent, QTreeWidgetItem getCurrentObjectTree()->update(); } +void ObjectManipulator::moveItems(ObjectTreeViewItem *dest, + const list &items) +{ + string folder; + QTreeWidgetItem *destItem; + if (dest->getUserFolderParent() != 0) { + folder = dest->getUserFolderName().toUtf8().constData(); + destItem = dest; + } else { + folder = dest->getFWObject()->getStr("folder"); + if (FWBTree().isSystem(dest->getFWObject())) { + destItem = dest; + } else { + destItem = dest->parent(); + } + } + + list::const_iterator iter; + for (iter = items.begin(); iter != items.end(); ++iter) { + (*iter)->setStr("folder", folder); + ObjectTreeViewItem *item = allItems[*iter]; + item->parent()->removeChild(item); + destItem->addChild(item); + } + + refreshSubtree(destItem, 0); +} diff --git a/src/libgui/ObjectTreeView.cpp b/src/libgui/ObjectTreeView.cpp index f5672503d..7be005577 100644 --- a/src/libgui/ObjectTreeView.cpp +++ b/src/libgui/ObjectTreeView.cpp @@ -43,6 +43,9 @@ #include "fwbuilder/Firewall.h" #include "fwbuilder/Group.h" #include "fwbuilder/Interface.h" +#include "fwbuilder/NAT.h" +#include "fwbuilder/Routing.h" +#include "fwbuilder/Policy.h" #include "fwbuilder/Resources.h" #include @@ -98,7 +101,7 @@ ObjectTreeView::ObjectTreeView(ProjectPanel* project, setExpandsOnDoubleClick(false); -// setAcceptDrops( TRUE ); + setDragEnabled(true); item_before_drag_started=NULL; lastSelected = NULL; second_click = false; @@ -329,17 +332,18 @@ void ObjectTreeView::focusOutEvent(QFocusEvent* ev) void ObjectTreeView::updateTreeIcons() { QTreeWidgetItemIterator it(this); - while ( *it ) + for ( ; *it; ++it) { QTreeWidgetItem *itm = *it; ObjectTreeViewItem *otvi = dynamic_cast(itm); FWObject *obj = otvi->getFWObject(); + /* We can have obj==0 if it's a user-create subfolder */ + if (obj == 0) continue; + QPixmap pm_obj; IconSetter::setObjectIcon(obj, &pm_obj, 0); itm->setIcon(0, pm_obj ); - - ++it; } update(); } @@ -349,10 +353,11 @@ void ObjectTreeView::startDrag(Qt::DropActions supportedActions) QTreeWidgetItem *ovi = currentItem(); if (ovi==NULL) return; - ObjectTreeViewItem *otvi=dynamic_cast(ovi); - FWObject *current_obj = getCurrentObject(); + /* User-defined folders can't be dragged */ + if (current_obj == 0) return; + if (fwbdebug) qDebug("ObjectTreeView::startDrag: this: %p current_obj: %s", this, current_obj->getName().c_str()); @@ -450,10 +455,6 @@ void ObjectTreeView::startDrag(Qt::DropActions supportedActions) if (fwbdebug) qDebug("ObjectTreeView::dragObject() this=%p visible=%d", this,visible); - FWObject *edit_obj = mw->getOpenedEditor(); - - if (fwbdebug) qDebug("ObjectTreeView::dragObject() returns !NULL"); - drag->start(supportedActions); } @@ -463,79 +464,87 @@ void ObjectTreeView::dragEnterEvent( QDragEnterEvent *ev) ev->setDropAction(Qt::MoveAction); } -bool ObjectTreeView::isCurrReadOnly(QDragMoveEvent *ev) -{ -// the tree can accept drop only if it goes into a group and if that group -// validates the object and tree is not read-only - QTreeWidgetItem *ovi = itemAt(ev->pos()); - - ObjectTreeViewItem *otvi=dynamic_cast(ovi); - FWObject *trobj; - if (otvi && (trobj = otvi->getFWObject())) - return trobj->isReadOnly(); - return false; -} - void ObjectTreeView::dragMoveEvent( QDragMoveEvent *ev) { QWidget *fromWidget = ev->source(); // The source of DnD object must be the same instance of fwbuilder - if (!fromWidget) - { - ev->setAccepted(false); - return; - } - - if (isCurrReadOnly(ev) || - !ev->mimeData()->hasFormat(FWObjectDrag::FWB_MIME_TYPE)) - { + if (!fromWidget || fromWidget != this) { + notWanted: ev->setAccepted(false); return; } - list dragol; - if (!FWObjectDrag::decode(ev, dragol)) - ev->setAccepted(false); - for (list::iterator i=dragol.begin();i!=dragol.end(); ++i) - { - FWObject *dragobj = *i; - assert(dragobj!=NULL); + ObjectTreeViewItem *dest = + dynamic_cast(itemAt(ev->pos())); + if (dest == 0) goto notWanted; - if (FWBTree().isSystem(dragobj)) - { -// can not drop system folder anywhere - ev->setAccepted(false); - return; - } + list objs; + if (!FWObjectDrag::decode(ev, objs)) goto notWanted; - // see #1976 do not allow pasting object that has been deleted - if (dragobj->getLibrary()->getId() == FWObjectDatabase::DELETED_OBJECTS_ID) - { - ev->setAccepted(false); - return; + bool dragIsNoop = true; + list::const_iterator iter; + for (iter = objs.begin(); iter != objs.end(); ++iter) { + FWObject *dragobj = *iter; + assert(dragobj != 0); + + if (Interface::cast(dragobj) != 0 || + Interface::cast(dragobj->getParent()) != 0 || + Policy::cast(dragobj) != 0 || + NAT::cast(dragobj) != 0 || + Routing::cast(dragobj) != 0) goto notWanted; + + /* See if destination is a user folder */ + if (dest->getUserFolderParent() != 0) { + /* Dragged object has to match parent of user folder */ + if (dest->getUserFolderParent() != dragobj->getParent()) { + goto notWanted; + } + + /* Are we dragging within the same user folder? */ + if (dest->getUserFolderName() != + QString::fromUtf8(dragobj->getStr("folder").c_str())) { + dragIsNoop = false; + } + } else { + /* OK to drag onto parent itself, or object that shares parent */ + if (dragobj->getParent() != dest->getFWObject() && + dragobj->getParent() != dest->getFWObject()->getParent()) { + goto notWanted; + } + + /* Are we dragging to a new place? */ + if ((FWBTree().isSystem(dest->getFWObject()) && + dragobj->getStr("folder") != "") || + (dest->getFWObject()->getStr("folder") != + dragobj->getStr("folder"))) { + dragIsNoop = false; + } } } + if (dragIsNoop) goto notWanted; + + ev->setDropAction(Qt::MoveAction); ev->setAccepted(true); } -/* - * See ticket #483: d&d of objects inside the tree should not be allowed - */ + void ObjectTreeView::dropEvent(QDropEvent *ev) { - ev->setAccepted(false); - return; -} + ObjectTreeViewItem *dest = + dynamic_cast(itemAt(ev->pos())); + if (dest == 0) { + notWanted: + ev->setAccepted(false); + return; + } -FWObject *ObjectTreeView::getDropTarget(QDropEvent *ev, FWObject*) -{ - QTreeWidgetItem *ovi = itemAt(ev->pos()); + list objs; + if (!FWObjectDrag::decode(ev, objs)) goto notWanted; - ObjectTreeViewItem *otvi = dynamic_cast(ovi); - if (otvi) return otvi->getFWObject(); - else return NULL; + emit moveItems_sign(dest, objs); + ev->setAccepted(true); } void ObjectTreeView::dragLeaveEvent( QDragLeaveEvent *ev) @@ -547,6 +556,9 @@ void ObjectTreeView::dragLeaveEvent( QDragLeaveEvent *ev) void ObjectTreeView::mouseMoveEvent( QMouseEvent * e ) { + /* This stops highlighting of stuff in the tree when the user + clicks and tries to drag something non-draggable. */ + if (state() == DragSelectingState) return; QTreeWidget::mouseMoveEvent(e); if (e==NULL) return; } @@ -745,6 +757,9 @@ void ObjectTreeView::itemSelectionChanged() QTreeWidgetItem *itm = (*it); ObjectTreeViewItem *otvi = dynamic_cast(itm); + FWObject *obj = otvi->getFWObject(); + if (obj == 0) continue; + selectedObjects.push_back(otvi->getFWObject()); if (fwbdebug) qDebug( @@ -783,14 +798,14 @@ void ObjectTreeView::ExpandTreeItems(const set &ids) qDebug() << "ObjectTreeView::ExpandTreeItems()"; QTreeWidgetItemIterator it(this); - while ( *it ) + for ( ; *it; ++it) { QTreeWidgetItem *itm = *it; ObjectTreeViewItem *otvi=dynamic_cast(itm); FWObject *obj = otvi->getFWObject(); + if (obj == 0) continue; if (ids.count(obj->getId())) itm->setExpanded(true); - ++it; } } @@ -852,10 +867,9 @@ void ObjectTreeView::setFilter(QString text) if (fwbdebug) qDebug() << "ObjectTreeView::setFilter " << text; - QTreeWidgetItemIterator wit(this); - while (*wit) - { + for (QTreeWidgetItemIterator wit(this); *wit; ++wit) { ObjectTreeViewItem *otvi = dynamic_cast(*wit); + if (otvi->getUserFolderParent() != 0) continue; FWObject *obj = otvi->getFWObject(); if (filterMatches(text, otvi, obj)) { @@ -869,8 +883,6 @@ void ObjectTreeView::setFilter(QString text) } else { (*wit)->setHidden(true); } - - ++wit; } if (!text.isEmpty()) this->expandAll(); diff --git a/src/libgui/ObjectTreeView.h b/src/libgui/ObjectTreeView.h index 95dc469f9..d3a6c7b1a 100644 --- a/src/libgui/ObjectTreeView.h +++ b/src/libgui/ObjectTreeView.h @@ -45,6 +45,7 @@ namespace libfwbuilder { }; class ProjectPanel; +class ObjectTreeViewItem; class ObjectTreeView : public QTreeWidget { @@ -66,11 +67,6 @@ class ObjectTreeView : public QTreeWidget std::vector selectedObjects; ProjectPanel* m_project; - - bool isCurrReadOnly(QDragMoveEvent *ev); - libfwbuilder::FWObject *getDropTarget( - QDropEvent *ev, libfwbuilder::FWObject* dragobj); - QSet resolveChildren(QTreeWidgetItem*); QSet resolveParents(QTreeWidgetItem*); @@ -169,6 +165,8 @@ protected: void objectDropped_sign(libfwbuilder::FWObject *); void deleteObject_sign(libfwbuilder::FWObject *); void contextMenuRequested_sign(const QPoint&); + void moveItems_sign(ObjectTreeViewItem *dest, + const std::list &items); }; diff --git a/src/libgui/ObjectTreeViewItem.cpp b/src/libgui/ObjectTreeViewItem.cpp index 9eaf4a3da..e465c8a15 100644 --- a/src/libgui/ObjectTreeViewItem.cpp +++ b/src/libgui/ObjectTreeViewItem.cpp @@ -80,59 +80,31 @@ QVariant ObjectTreeViewItem::data(int column, int role) const return QTreeWidgetItem::data(column, role); } -bool ObjectTreeViewItem::operator<( const QTreeWidgetItem & other ) const + +static int getRank(FWObject *obj) { - int rank1 = -1; - int rank2 = -1; - const ObjectTreeViewItem * otvi = - dynamic_cast(& other); + /* User-defined folders are first */ + if (obj == 0) return 0; + + if (Interface::cast(obj) != 0) return 5; + if (Policy::cast(obj) != 0) return 2; + if (NAT::cast(obj) != 0) return 3; + if (Routing::cast(obj) != 0) return 4; - if (otvi->objptr==NULL) return true ; - if (objptr==NULL) return true ; - - if (Interface::cast(otvi->objptr)!=NULL) - { - rank1=3; - } - if (Policy::cast(otvi->objptr)!=NULL) - { - rank1=0; - } - if (NAT::cast(otvi->objptr)!=NULL) - { - rank1=1; - } - if (Routing::cast(otvi->objptr)!=NULL) - { - rank1=2; - } - if (Interface::cast(objptr)!=NULL) - { - rank2=3; - } - if (Policy::cast(objptr)!=NULL) - { - rank2=0; - } - if (NAT::cast(objptr)!=NULL) - { - rank2=1; - } - if (Routing::cast(objptr)!=NULL) - { - rank2=2; - } - - if (rank1==rank2) - { - QString s1 = objptr->getName().c_str(); - QString s2 = otvi->objptr->getName ().c_str(); - //return ( s1 < s2); - return ( s1.toLower() < s2.toLower()); - } - if (rank1>rank2) - { - return true ; - } - return false ; + return 1; +} + + +bool ObjectTreeViewItem::operator<(const QTreeWidgetItem &other) const +{ + const ObjectTreeViewItem *otvi = + dynamic_cast(&other); + + int rank1 = getRank(otvi->objptr); + int rank2 = getRank(objptr); + + if (rank1 == rank2) + return text(0).toLower() < otvi->text(0).toLower(); + + return rank1 > rank2; } diff --git a/src/libgui/ObjectTreeViewItem.h b/src/libgui/ObjectTreeViewItem.h index c81ebe447..17551a5ce 100644 --- a/src/libgui/ObjectTreeViewItem.h +++ b/src/libgui/ObjectTreeViewItem.h @@ -43,21 +43,28 @@ class ObjectTreeView; class ObjectTreeViewItem : public QTreeWidgetItem { libfwbuilder::FWObject *objptr; + libfwbuilder::FWObject *userFolderParent; + QString userFolderName; QMap props; QString lib; public: - ObjectTreeViewItem(QTreeWidget *parent) : QTreeWidgetItem(parent) { - objptr=NULL; - } + ObjectTreeViewItem(QTreeWidget *parent) : + QTreeWidgetItem(parent), objptr(0), userFolderParent(0) {} - ObjectTreeViewItem(QTreeWidgetItem *parent) : QTreeWidgetItem(parent){ - objptr=NULL; - } + ObjectTreeViewItem(QTreeWidgetItem *parent) : + QTreeWidgetItem(parent), objptr(0), userFolderParent(0) {} libfwbuilder::FWObject *getFWObject() const { return objptr; } + libfwbuilder::FWObject *getUserFolderParent() { return userFolderParent; } void setFWObject(libfwbuilder::FWObject *obj) { objptr=obj; } + void setUserFolderParent(libfwbuilder::FWObject *obj) { + userFolderParent = obj; + } + + void setUserFolderName(const QString &name) { userFolderName = name; } + const QString &getUserFolderName() { return userFolderName; } ObjectTreeView* getTree(); diff --git a/src/libgui/RuleSetModel.cpp b/src/libgui/RuleSetModel.cpp index c4a959ebc..b64b153f2 100644 --- a/src/libgui/RuleSetModel.cpp +++ b/src/libgui/RuleSetModel.cpp @@ -1203,7 +1203,6 @@ bool RuleSetModel::isGroup(const QModelIndex &index) const void RuleSetModel::resetAllSizes() { - qDebug() << "resetAllSizes()"; emit layoutAboutToBeChanged (); root->resetAllSizes(); emit layoutChanged ();