dotfileformat.cpp 5.11 KB
Newer Older
1
/*
2
    This file is part of Rocs.
3
4
5
    Copyright 2010       Tomaz Canabrava <tomaz.canabrava@gmail.com>
    Copyright 2010       Wagner Reck <wagner.reck@gmail.com>
    Copyright 2012-2014  Andreas Cord-Landwehr <cordlandwehr@kde.org>
6

7
8
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
9
    published by the Free Software Foundation; either version 2 of
10
    the License, or (at your option) any later version.
11
12
13
14
15
16
17

    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.

    You should have received a copy of the GNU General Public License
18
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
20
*/

21
22
#include "dotfileformat.h"
#include "fileformats/fileformatinterface.h"
23
#include "modifiers/topology.h"
24
25
26
27
#include "graphdocument.h"
#include "node.h"
#include "edge.h"
#include <KLocalizedString>
28
#include <KPluginFactory>
29
#include <QFile>
30
31
#include <QTextStream>
#include <QUrl>
32
#include <QHash>
33
#include <QVector>
34
35
#include "dotgrammarhelper.h"
#include "dotgrammar.h"
36

37
extern DotParser::DotGraphParsingHelper* phelper;
38

39
using namespace GraphTheory;
40

41
42
43
static QString processNode(const NodePtr &node);
static QString processEdge(const EdgePtr &edge);

44
45
46
47
48
K_PLUGIN_FACTORY_WITH_JSON( FilePluginFactory,
                            "dotfileformat.json",
                            registerPlugin<DotFileFormat>();)

DotFileFormat::~DotFileFormat()
49
{
50
51
}

52
53
DotFileFormat::DotFileFormat(QObject* parent, const QList< QVariant >&) :
    FileFormatInterface("rocs_dotfileformat", parent)
54
{
55
56
}

57
const QStringList DotFileFormat::extensions() const
58
{
59
    return QStringList()
60
           << i18n("Graphviz Format (%1)", QString("*.dot"));
61
62
}

63
void DotFileFormat::readFile()
64
{
65
66
    GraphDocumentPtr document = GraphDocument::create();
    setGraphDocument(document);
67

68
    QList < QPair<QString, QString> > edges;
69
70
71
72
    QFile fileHandle(file().toLocalFile());
    if (!fileHandle.open(QFile::ReadOnly)) {
        setError(CouldNotOpenFile, i18n("Could not open file \"%1\" in read mode: %2", file().toLocalFile(), fileHandle.errorString()));
        return;
73
    }
74
    QString content = fileHandle.readAll();
75
    if (!DotParser::parse(content.toStdString(), document)) {
76
77
        setError(EncodingProblem, i18n("Could not parse file \"%1\".", file().toLocalFile()));
        return;
78
    }
79
80

    Topology::directedGraphDefaultTopology(document);
81
     setError(None);
82
83
}

84
void DotFileFormat::writeFile(GraphDocumentPtr document)
85
{
86
    // prepare file handle for output
87
    QFile fileHandle(file().toLocalFile());
88
    QVariantList subgraphs;
89
90
91
    if (!fileHandle.open(QFile::WriteOnly | QFile::Text)) {
        setError(FileIsReadOnly, i18n("Cannot open file %1 to write document. Error: %2", file().fileName(), fileHandle.errorString()));
        return;
92
93
    }
    QTextStream out(&fileHandle);
94

95
96
    out << "digraph {\n";

97
98
99
100
    // create fast access list of already processed nodes: serialize each node only once
    QHash<int, bool> processedData;

    // process all data elements
101
    for (const NodePtr &node : document->nodes()) {
102
        out << processNode(node);
103
104
105
    }

    // process all edges
106
    for (const auto &edge : document->edges()) {
107
        out << processEdge(edge);
108
    }
109
110
111
    out << "}\n";
    setError(None);
    return;
112
113
}

114
static QString processEdge(const EdgePtr &edge)
115
{
116
    QString edgeStr;
117
    edgeStr.append(QString(" %1 -> %2 ")
118
119
                .arg(edge->from()->id())
                .arg(edge->to()->id()));
120
121

    // process properties if present
122
    bool firstProperty = true;
123
    if (!edge->property("name").toString().isEmpty()) {
124
        firstProperty = false;
125
        edgeStr.append("[");
126
        edgeStr.append(QString(" label = \"%2\" ").arg(edge->property("name").toString()));
127
    }
128
    for(const QByteArray &property : edge->dynamicPropertyNames()) {
129
        if (firstProperty == true) {
130
                firstProperty = false;
131
                edgeStr.append("[");
132
            } else {
133
                edgeStr.append(", ");
134
        }
135
        edgeStr.append(QString(" %1 = \"%2\" ").arg(QString(property)).arg(edge->property(property).toString()));
136
    }
137
    if (!firstProperty) { // at least one property was inserted
138
139
140
        edgeStr.append("]");
    }
    return edgeStr.append(";\n");
141
142
}

143
static QString processNode(const NodePtr &node)
144
{
145
    QString nodeStr;
146

147
    // use identifier for unique identification, store name as argument "label"
148
149
150
151
152
    nodeStr = QString("%1").arg(node->id());
    nodeStr.append(" [ ");
    if (!node->dynamicProperty("name").toString().isEmpty()) {
        nodeStr.append(QString("label=\"%1\" ").arg(node->dynamicProperty("name").toString()));
    }
153

154
    for(const QByteArray &property : node->dynamicPropertyNames()) {
155
156
        nodeStr.append(", ");
        nodeStr.append(QString(" %1 = \"%2\" ").arg(QString(property)).arg(node->property(property).toString()));
157
    }
158
159
160

    // at least one property was inserted
    nodeStr.append("]");
161
    return nodeStr.append(";\n");
162
163
}

164
#include "dotfileformat.moc"