]> git.sven.stormbind.net Git - sven/vym.git/blob - src/imports.cpp
New upstream version 2.9.22
[sven/vym.git] / src / imports.cpp
1 #include "imports.h"
2
3 #include "attributeitem.h"
4 #include "branchitem.h"
5 #include "file.h"
6 #include "linkablemapobj.h"
7 #include "mainwindow.h"
8 #include "misc.h"
9 #include "vymmodel.h"
10 #include "xsltproc.h"
11
12 #include <QMessageBox>
13
14 extern Main *mainWindow;
15 extern QDir vymBaseDir;
16
17 ImportBase::ImportBase()
18 {
19     model = NULL;
20     init();
21 }
22
23 ImportBase::ImportBase(VymModel *m)
24 {
25     model = m;
26     init();
27 }
28
29 ImportBase::~ImportBase()
30 {
31     // Remove tmpdir
32     removeDir(tmpDir);
33 }
34
35 void ImportBase::init() 
36 {
37     bool ok;
38     tmpDir.setPath(makeTmpDir(ok, "vym-import"));
39     if (!tmpDir.exists() || !ok)
40         QMessageBox::critical(
41             0, QObject::tr("Error"),
42             QObject::tr("Couldn't access temporary directory\n"));
43 }
44
45 void ImportBase::setDir(const QString &p) { inputDir = p; }
46
47 void ImportBase::setFile(const QString &p) { inputFile = p; }
48
49 bool ImportBase::transform() { return true; }
50
51 QString ImportBase::getTransformedFile() { return transformedFile; }
52
53 /////////////////////////////////////////////////
54 ImportFirefoxBookmarks::ImportFirefoxBookmarks(VymModel *m) : ImportBase(m) 
55 {
56     totalBookmarks = currentBookmarks = 0;
57 }
58
59 bool ImportFirefoxBookmarks::transform()
60 {
61     QStringList lines;
62     QFile file(inputFile);
63
64     progressDialog.setAutoReset(false);
65     progressDialog.setAutoClose(false);
66     progressDialog.setMinimumWidth(600);
67     progressDialog.setCancelButton(NULL);
68     progressDialog.setWindowTitle(QObject::tr("Import Firefox bookmarks","Import dialog"));
69     progressDialog.setLabelText(
70         QObject::tr("Loading bookmarks:", "Progress dialog while importing bookmarks"));
71
72     if (file.open(QIODevice::ReadOnly)) {
73         QJsonDocument jsdoc = QJsonDocument::fromJson(file.readAll());
74         file.close();
75
76         QJsonObject jsobj = jsdoc.object();
77
78         QJsonArray jsarr = jsobj["children"].toArray();
79         foreach (const QJsonValue &value, jsarr) {
80             parseJson (value, ParseMode::countBookmarks);
81         }
82
83         progressDialog.setRange(0, totalBookmarks);
84         progressDialog.setValue(1);
85         progressDialog.setWindowModality(Qt::WindowModal);
86         progressDialog.show();
87         QApplication::processEvents();
88
89         model->blockReposition();
90
91         parseJson (jsobj, ParseMode::buildMap);
92         
93         model->unblockReposition();
94
95         mainWindow->statusMessage(
96                 QObject::tr("Imported %1 bookmarks", "Import dialog").arg(totalBookmarks));
97     }
98
99     return false;
100 }
101
102 bool ImportFirefoxBookmarks::parseJson(QJsonValue jsval, ParseMode mode, BranchItem *selbi)
103 {
104     if (!selbi) {
105         selbi = model->getSelectedBranch();
106         if (!selbi) {
107             qWarning() << "ImportFirefoxBookmarks: No branch selected!";
108             return false;
109         }
110     }
111
112     QJsonObject jsobj = jsval.toObject();
113
114     if (mode == countBookmarks) {
115         // Count bookmarks 
116         if (jsobj.contains("uri") && jsobj["uri"].isString())
117             totalBookmarks++;
118     } else {
119         // Build map
120         selbi = model->addNewBranch(selbi);
121         selbi->setHeadingPlainText(jsobj["title"].toString());
122
123         if (jsobj.contains("uri") && jsobj["uri"].isString()) {
124             currentBookmarks++;
125             progressDialog.setValue(currentBookmarks);
126             selbi->setURL(jsobj["uri"].toString());
127         }
128
129         AttributeItem *ai;
130
131         foreach (QString key, jsobj.keys())
132         {
133             if (key != "children") {
134                 ai = new AttributeItem();
135                 ai->setKey(key);
136                 // Integer types: dateAdded, id, index, lastModified, typeCode
137                 // Special: postData
138                 if (key == "dateAdded" || key == "lastModified") {
139                     qlonglong l = jsobj[key].toVariant().toLongLong();
140                     QDateTime dt;
141                     dt.setMSecsSinceEpoch(l / 1000);
142                     ai->setValue(dt);
143                     ai->setAttributeType(AttributeItem::DateTime);
144                 } else if (key == "id" || key == "index" || 
145                         key == "lastModified" || key == "typeCode" ) {
146                     ai->setValue(jsobj[key].toInt());
147                 } else if (key == "postData") 
148                     ai->setValue(QString("null"));
149                 else if (jsobj[key].isString()) 
150                     ai->setValue(jsobj[key].toString());
151                 else {
152                 // Ignore only the "postdata: null" field for now
153                     qWarning() << "Firefox import, unknown key type: " << jsobj[key].type();
154                     qDebug() << "                Firefox bookmark: " << key << jsobj[key].toString();
155                     ai->setValue(QString("unknown type."));
156                 }
157
158                 model->setAttribute(selbi, ai); // FIXME-3 deep copy?
159             }
160         }
161
162         model->emitDataChanged(selbi); // FIXME-2 required, but can reposition in between be blocked?
163     } // build bookmakrs
164
165     if (jsobj.contains("children") && jsobj["children"].isArray()) {
166
167         QJsonArray jsarr = jsobj["children"].toArray();
168         foreach (const QJsonValue &val, jsarr) {
169             parseJson (val, mode, selbi);
170         }
171
172         if (selbi->depth() > 2) {
173             selbi->scroll();
174             model->emitDataChanged(selbi); // FIXME-2 required, but can reposition in between be blocked?
175         }
176     } 
177
178     return true;
179 }
180    
181 /////////////////////////////////////////////////
182 bool ImportMM::transform()
183 {
184     // try to unzip
185     if (File::Success == unzipDir(tmpDir, inputFile)) {
186
187         // Set short name, too. Search from behind:
188         transformedFile = inputFile;
189         int i = transformedFile.lastIndexOf("/");
190         if (i >= 0)
191             transformedFile = transformedFile.remove(0, i + 1);
192         transformedFile.replace(".mmap", ".xml");
193         transformedFile = tmpDir.path() + "/" + transformedFile;
194
195         XSLTProc p;
196         p.setInputFile(tmpDir.path() + "/Document.xml");
197         p.setOutputFile(transformedFile);
198         p.setXSLFile(vymBaseDir.path() + "/styles/mmap2vym.xsl");
199         p.process();
200
201         return true;
202     }
203     else
204         return false;
205 }