You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/folder.cpp

413 lines
15 KiB

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* copyright (C) 2006 *
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
***************************************************************************/
// own header
#include "folder.h"
// qt/kde includes
#include <tqfile.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
// app includes
#include "uml.h"
#include "umldoc.h"
#include "umlview.h"
#include "umllistview.h"
#include "optionstate.h"
#include "object_factory.h"
#include "model_utils.h"
UMLFolder::UMLFolder(const TQString & name, Uml::IDType id)
: UMLPackage(name, id) {
init();
}
UMLFolder::~UMLFolder() {
}
void UMLFolder::init() {
m_BaseType = Uml::ot_Folder;
m_diagrams.setAutoDelete(true);
UMLObject::setStereotype("folder");
}
UMLObject* UMLFolder::clone() const {
UMLFolder *clone = new UMLFolder();
UMLObject::copyInto(clone);
return clone;
}
void UMLFolder::setLocalName(const TQString& localName) {
m_localName = localName;
}
TQString UMLFolder::getLocalName() {
return m_localName;
}
void UMLFolder::addView(UMLView *view) {
m_diagrams.append(view);
}
void UMLFolder::removeView(UMLView *view) {
// m_diagrams is set to autodelete!
m_diagrams.remove(view);
}
void UMLFolder::appendViews(UMLViewList& viewList, bool includeNested) {
if (includeNested) {
UMLObject *o;
for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
if (o->getBaseType() == Uml::ot_Folder) {
UMLFolder *f = static_cast<UMLFolder*>(o);
f->appendViews(viewList);
}
}
}
UMLView *v;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
viewList.append(v);
}
void UMLFolder::activateViews() {
UMLObject *o;
for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
if (o->getBaseType() == Uml::ot_Folder) {
UMLFolder *f = static_cast<UMLFolder*>(o);
f->activateViews();
}
}
UMLView *v;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
v->activateAfterLoad();
// Make sure we have a treeview item for each diagram.
// It may happen that we are missing them after switching off tabbed widgets.
Settings::OptionState optionState = Settings::getOptionState();
if (optionState.generalState.tabdiagrams)
return;
UMLListView *lv = UMLApp::app()->getListView();
for (UMLViewListIt it(m_diagrams); (v = it.current()) != NULL; ++it) {
if (lv->findItem(v->getID()) != NULL)
continue;
lv->createDiagramItem(v);
}
}
UMLView *UMLFolder::findView(Uml::IDType id) {
UMLView *v = NULL;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
if (v->getID() == id)
return v;
}
UMLObject *o;
for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
if (o->getBaseType() != Uml::ot_Folder)
continue;
UMLFolder *f = static_cast<UMLFolder*>(o);
v = f->findView(id);
if (v)
break;
}
return v;
}
UMLView *UMLFolder::findView(Uml::Diagram_Type type, const TQString &name, bool searchAllScopes) {
UMLView *v = NULL;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
if (v->getType() == type && v->getName() == name)
return v;
}
if (searchAllScopes) {
UMLObject *o;
for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
if (o->getBaseType() != Uml::ot_Folder)
continue;
UMLFolder *f = static_cast<UMLFolder*>(o);
v = f->findView(type, name, searchAllScopes);
if (v)
break;
}
}
return v;
}
void UMLFolder::setViewOptions(const Settings::OptionState& optionState) {
// for each view update settings
UMLView *v;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
v->setOptionState(optionState);
}
void UMLFolder::removeAllViews() {
UMLObject *o;
for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
if (o->getBaseType() != Uml::ot_Folder)
continue;
UMLFolder *f = static_cast<UMLFolder*>(o);
f->removeAllViews();
}
UMLView *v = NULL;
for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
// TODO ------------------ check this code - bad: calling back to UMLDoc::removeView()
v->removeAllAssociations(); // note : It may not be apparent, but when we remove all associations
// from a view, it also causes any UMLAssociations that lack parent
// association widgets (but once had them) to remove themselves from
// this document.
UMLApp::app()->getDocument()->removeView(v, false);
}
m_diagrams.clear();
}
void UMLFolder::setFolderFile(const TQString& fileName) {
m_folderFile = fileName;
}
TQString UMLFolder::getFolderFile() {
return m_folderFile;
}
void UMLFolder::saveContents(TQDomDocument& qDoc, TQDomElement& qElement) {
TQDomElement ownedElement = qDoc.createElement("UML:Namespace.ownedElement");
UMLObject *obj;
// Save contained objects if any.
for (UMLObjectListIt oit(m_objects); (obj = oit.current()) != NULL; ++oit)
obj->saveToXMI (qDoc, ownedElement);
// Save asscociations if any.
for (UMLObjectListIt ait(m_List); (obj = ait.current()) != NULL; ++ait)
obj->saveToXMI (qDoc, ownedElement);
qElement.appendChild(ownedElement);
// Save diagrams to `extension'.
if (m_diagrams.count()) {
TQDomElement diagramsElement = qDoc.createElement("diagrams");
UMLView *pView;
for (UMLViewListIt vit(m_diagrams); (pView = vit.current()) != NULL; ++vit) {
pView->saveToXMI(qDoc, diagramsElement);
}
TQDomElement extension = qDoc.createElement("XMI.extension");
extension.setAttribute("xmi.extender", "umbrello");
extension.appendChild( diagramsElement );
qElement.appendChild(extension);
}
}
void UMLFolder::save(TQDomDocument& qDoc, TQDomElement& qElement) {
UMLDoc *umldoc = UMLApp::app()->getDocument();
TQString elementName("UML:Package");
const Uml::Model_Type mt = umldoc->rootFolderType(this);
if (mt != Uml::N_MODELTYPES)
elementName = "UML:Model";
TQDomElement folderElement = UMLObject::save(elementName, qDoc);
saveContents(qDoc, folderElement);
qElement.appendChild(folderElement);
}
void UMLFolder::saveToXMI(TQDomDocument& qDoc, TQDomElement& qElement) {
if (m_folderFile.isEmpty()) {
save(qDoc, qElement);
return;
}
// See if we can create the external file.
// If not then internalize the folder.
UMLDoc *umldoc = UMLApp::app()->getDocument();
TQString fileName = umldoc->URL().directory() + '/' + m_folderFile;
TQFile file(fileName);
if (!file.open(IO_WriteOnly)) {
kError() << "UMLFolder::saveToXMI(" << m_folderFile << "): "
<< "cannot create file, contents will be saved in main model file"
<< endl;
m_folderFile = TQString();
save(qDoc, qElement);
return;
}
// Okay, external file is writable. Wrap up main file.
TQDomElement folderElement = UMLObject::save("UML:Package", qDoc);
TQDomElement extension = qDoc.createElement("XMI.extension");
extension.setAttribute("xmi.extender", "umbrello");
TQDomElement fileElement = qDoc.createElement("external_file");
fileElement.setAttribute("name", m_folderFile);
extension.appendChild(fileElement);
folderElement.appendChild(extension);
qElement.appendChild(folderElement);
// Save folder to external file.
TQDomDocument folderDoc;
TQDomElement folderRoot;
TQDomProcessingInstruction xmlHeading =
folderDoc.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"UTF-8\"");
folderDoc.appendChild(xmlHeading);
folderRoot = folderDoc.createElement("external_file");
folderRoot.setAttribute("name", m_Name);
folderRoot.setAttribute("filename", m_folderFile);
folderRoot.setAttribute("mainModel", umldoc->URL().fileName());
folderRoot.setAttribute("parentId", ID2STR(m_pUMLPackage->getID()));
folderRoot.setAttribute("parent", m_pUMLPackage->getFullyQualifiedName("::", true));
saveContents(folderDoc, folderRoot);
folderDoc.appendChild(folderRoot);
TQTextStream stream(&file);
stream.setEncoding(TQTextStream::UnicodeUTF8);
stream << folderDoc.toString();
file.close();
}
bool UMLFolder::loadDiagramsFromXMI(TQDomNode& diagrams) {
const Settings::OptionState optionState = Settings::getOptionState();
UMLDoc *umldoc = UMLApp::app()->getDocument();
bool totalSuccess = true;
for (TQDomElement diagram = diagrams.toElement(); !diagram.isNull();
diagrams = diagrams.nextSibling(), diagram = diagrams.toElement()) {
TQString tag = diagram.tagName();
if (tag != "diagram") {
kDebug() << "UMLFolder::loadDiagramsFromXMI: ignoring "
<< tag << " in <diagrams>" << endl;
continue;
}
UMLView * pView = new UMLView(this);
pView->setOptionState(optionState);
if (pView->loadFromXMI(diagram)) {
pView->hide();
umldoc->addView(pView);
} else {
delete pView;
totalSuccess = false;
}
}
return totalSuccess;
}
bool UMLFolder::loadFolderFile(const TQString& path) {
TQFile file(path);
if (!file.exists()) {
KMessageBox::error(0, i18n("The folderfile %1 does not exist.").arg(path), i18n("Load Error"));
return false;
}
if (!file.open(IO_ReadOnly)) {
KMessageBox::error(0, i18n("The folderfile %1 cannot be opened.").arg(path), i18n("Load Error"));
return false;
}
TQTextStream stream(&file);
TQString data = stream.read();
file.close();
TQDomDocument doc;
TQString error;
int line;
if (!doc.setContent( data, false, &error, &line)) {
kError() << "UMLFolder::loadFolderFile: Can't set content:"
<< error << " line:" << line << endl;
return false;
}
TQDomNode rootNode = doc.firstChild();
while (rootNode.isComment() || rootNode.isProcessingInstruction()) {
rootNode = rootNode.nextSibling();
}
if (rootNode.isNull()) {
kError() << "UMLFolder::loadFolderFile: Root node is Null" << endl;
return false;
}
TQDomElement element = rootNode.toElement();
TQString type = element.tagName();
if (type != "external_file") {
kError() << "UMLFolder::loadFolderFile: Root node has unknown type "
<< type << endl;
return false;
}
return load(element);
}
bool UMLFolder::load(TQDomElement& element) {
UMLDoc *umldoc = UMLApp::app()->getDocument();
bool totalSuccess = true;
for (TQDomNode node = element.firstChild(); !node.isNull();
node = node.nextSibling()) {
if (node.isComment())
continue;
TQDomElement tempElement = node.toElement();
TQString type = tempElement.tagName();
if (Model_Utils::isCommonXMIAttribute(type))
continue;
if (Uml::tagEq(type, "Namespace.ownedElement") ||
Uml::tagEq(type, "Namespace.contents")) {
//CHECK: Umbrello currently assumes that nested elements
// are ownedElements anyway.
// Therefore these tags are not further interpreted.
if (! load(tempElement)) {
kDebug() << "An error happened while loading the " << type
<< " of the " << m_Name << endl;
totalSuccess = false;
}
continue;
} else if (type == "XMI.extension") {
for (TQDomNode xtnode = node.firstChild(); !xtnode.isNull();
xtnode = xtnode.nextSibling()) {
TQDomElement el = xtnode.toElement();
const TQString xtag = el.tagName();
if (xtag == "diagrams") {
TQDomNode diagramNode = xtnode.firstChild();
if (!loadDiagramsFromXMI(diagramNode))
totalSuccess = false;
} else if (xtag == "external_file") {
const TQString rootDir(umldoc->URL().directory());
TQString fileName = el.attribute("name", "");
const TQString path(rootDir + '/' + fileName);
if (loadFolderFile(path))
m_folderFile = fileName;
} else {
kDebug() << "UMLFolder::load(" << m_Name
<< "): ignoring XMI.extension " << xtag << endl;
continue;
}
}
continue;
}
// Do not re-create the predefined Datatypes folder in the Logical View,
// it already exists.
UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical);
if (this == logicalView && Uml::tagEq(type, "Package")) {
TQString thisName = tempElement.attribute("name", "");
if (thisName == "Datatypes") {
UMLFolder *datatypeFolder = umldoc->getDatatypeFolder();
if (!datatypeFolder->loadFromXMI(tempElement))
totalSuccess = false;
continue;
}
}
UMLObject *pObject = NULL;
// Avoid duplicate creation of forward declared object
TQString idStr = tempElement.attribute("xmi.id", "");
if (!idStr.isEmpty()) {
Uml::IDType id = STR2ID(idStr);
pObject = umldoc->findObjectById(id);
if (pObject) {
kDebug() << "UMLFolder::load: object " << idStr
<< "already exists" << endl;
}
}
if (pObject == NULL) {
TQString stereoID = tempElement.attribute("stereotype", "");
pObject = Object_Factory::makeObjectFromXMI(type, stereoID);
if (!pObject) {
kWarning() << "UMLFolder::load: "
<< "Unknown type of umlobject to create: " << type << endl;
continue;
}
}
pObject->setUMLPackage(this);
if (!pObject->loadFromXMI(tempElement)) {
removeObject(pObject);
delete pObject;
totalSuccess = false;
}
}
return totalSuccess;
}
#include "folder.moc"