]> git.sven.stormbind.net Git - sven/vym.git/blob - src/export-confluence.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / export-confluence.cpp
1 #include "export-confluence.h"
2
3 #include <QMessageBox>
4
5 #include "attributeitem.h"
6 #include "branchobj.h"
7 #include "mainwindow.h"
8 #include "settings.h"
9 #include "warningdialog.h"
10 #include "xmlobj.h"
11
12 extern QString flagsPath;
13 extern Main *mainWindow;
14 extern QString vymName;
15 extern QString vymVersion;
16 extern QString vymHome;
17 extern Settings settings;
18
19 ExportConfluence::ExportConfluence() : ExportBase() { init(); }
20
21 ExportConfluence::ExportConfluence(VymModel *m) : ExportBase(m) { init(); }
22
23 void ExportConfluence::init()
24 {
25     createNewPage = true;
26     exportName = "ConfluenceNewPage";
27
28     extension = ".html";
29
30     url = "";
31     pageName = "";
32
33     agent = nullptr;
34 }
35
36 void ExportConfluence::setCreateNewPage(bool b) {createNewPage = b; }
37
38 void ExportConfluence::setURL(const QString &u) { url = u; }
39
40 void ExportConfluence::setPageName(const QString &t) { pageName = t;}
41
42 QString ExportConfluence::getBranchText(BranchItem *current)
43 {
44     if (current) {
45         QRectF hr;
46         LinkableMapObj *lmo = current->getLMO();
47         if (lmo) {
48             hr = ((BranchObj *)lmo)->getBBoxHeading();
49         }
50         QString id = model->getSelectString(current);
51         QString heading = quoteMeta(current->getHeadingPlain());
52
53         // Numbering
54         QString number;
55         if (dia.useNumbering()) number = getSectionString(current) + " ";
56
57         // Long headings are will have linebreaks by default
58         heading = heading.replace("\\n", " ");
59
60         if (dia.useTextColor()) {
61             QColor c = current->getHeadingColor();
62             QString cs = QString("rgb(%1,%2,%3);")
63                              .arg(c.red())
64                              .arg(c.green())
65                              .arg(c.blue());
66             heading = QString("<span style='color: %1'>%2</span>")
67                           .arg(cs)
68                           .arg(number + heading);
69         }
70
71         QString s;
72
73         // Task flags
74         QString taskFlags;
75         /*
76         if (dia.useTaskFlags)
77         {
78             Task *task = current->getTask();
79             if (task)
80             {
81                 QString taskName = task->getIconString();
82                 taskFlags += QString("<img src=\"flags/flag-%1.png\"
83         alt=\"%2\">") .arg(taskName) .arg(QObject::tr("Flag: %1","Alt tag in
84         HTML export").arg(taskName));
85             }
86         }
87         */
88
89         // User flags
90         QString userFlags;
91         /*
92         if (dia.useUserFlags)
93         {
94             foreach (QString flag, current->activeFlagNames())          //
95         better don't use activeFlagNames, won't work for userflags userFlags +=
96         QString("<img src=\"flags/flag-%1.png\" alt=\"%2\">") .arg(flag)
97                     .arg(QObject::tr("Flag: %1","Alt tag in HTML
98         export").arg(flag));
99         }
100         */
101
102         // URL
103         //     <ac:link>
104         //<ri:user ri:userkey="55df23264acf166a014b54c57792009b"/>
105         //</ac:link> </span>
106         
107         // For URLs check, if there is already a Confluence user in an attribute
108         QString url;
109         AttributeItem *ai = current->getAttributeByKey("ConfluenceUser.userKey");
110         if (ai) {
111             url = ai->getKey();
112             s += QString(" <ac:link> <ri:user ri:userkey=\"%1\"/></ac:link>").arg(ai->getValue().toString());
113         } else {
114             url = current->getURL();
115
116             if (!url.isEmpty()) {
117                 if (url.contains(settings.value("/atlassian/confluence/url",
118                        "---undefined---").toString()) && url.contains("&")) {
119
120                     // Fix ampersands in URL to Confluence itself
121                     url = quoteMeta(url);
122                 } 
123
124                 s += QString("<a href=\"%1\">%2</a>")
125                          .arg(url)
126                          .arg(taskFlags + heading + userFlags);
127             } else
128                 s += taskFlags + heading + userFlags;
129         }
130
131         // Include images
132         if (dia.includeImages())
133         {
134             int imageCount = current->imageCount();
135             ImageItem *image;
136             QString imagePath;
137             for (int i=0; i< imageCount; i++)
138             {
139                 image = current->getImageNum(i);
140                 imagePath =  "image-" + image->getUuid().toString() + ".png";
141                 image->saveImage( dirPath + "/" + imagePath);
142                 agent->addUploadAttachmentPath(imagePath);
143                 s += "<p> <span style=\"color: rgb(0,170,255);\">";
144                 // Limit size
145                 if (image->width()  > 250)
146                     s+= "<ac:image ac:width=\"250\" >";
147                 else
148                     s += "<ac:image>";
149                 s += QString("<ri:attachment ri:filename=\"%1\"/></ac:image></span></p>").arg(imagePath);
150
151             }
152         }
153
154         // Include note
155         if (!current->isNoteEmpty()) {
156             VymNote note = current->getNote();
157             QString n;
158             if (note.isRichText()) {
159                 n = note.getText();
160                 QRegExp re("<p.*>");
161                 re.setMinimal(true);
162                 re.setPattern("</?html>");
163                 n.replace(re, "");
164
165                 re.setPattern("</?head.*>");
166                 n.replace(re, "");
167
168                 re.setPattern("</?body.*>");
169                 n.replace(re, "");
170
171                 re.setPattern("</?meta.*>");
172                 n.replace(re, "");
173
174                 re.setPattern("<style.*>.*</style>");
175                 n.replace(re, "");
176
177                 re.setPattern("<!DOCTYPE.*>");
178                 n.replace(re,"");
179
180                 re.setPattern("&(?!\\w*;)");
181                 n.replace(re, "&amp;");
182             }
183             else {
184                 n = current->getNoteASCII(0, 0);
185                 n.replace("&", "&amp;");
186                 n.replace("<", "&lt;");
187                 n.replace(">", "&gt;");
188                 if (current->getNote().getFontHint() == "fixed")
189                     n = "<pre>" + n + "</pre>";
190                 else {
191                     n = "<p>" + n + "</p>";
192                     n.replace("\n", "</p><p>");
193                 }
194             }
195
196             s += "\n<table class=\"vym-note\"><tr><td>\n" + n +
197                  "\n</td></tr></table>\n";
198         }
199         return s;
200     }
201     return QString();
202 }
203
204 QString ExportConfluence::buildList(BranchItem *current)
205 {
206     QString r;
207
208     uint i = 0;
209     uint visChilds = 0;
210
211     BranchItem *bi = current->getFirstBranch();
212
213     QString ind = "\n" + indent(current->depth() + 1, false);
214
215     QString sectionBegin = "";
216     QString sectionEnd   = "" ;
217     QString itemBegin;
218     QString itemEnd;
219
220     QString expandBegin;
221     QString expandEnd;
222
223     switch (current->depth() + 1) {
224     case 0:
225         itemBegin = "<h1>";
226         itemEnd = "</h1>";
227         break;
228     case 1:
229         itemBegin = "<h3>";
230         itemEnd = "</h3>";
231         break;
232     case 2:
233         itemBegin = "<h4>";
234         itemEnd = "</h4>";
235         break;
236     default:
237         sectionBegin =
238             "<ul " +
239             QString("class=\"vym-list-ul-%1\"").arg(current->depth() + 1) + ">";
240         sectionEnd = "</ul>";
241         itemBegin = "  <li>";
242         itemEnd = "  </li>";
243         break;
244     }
245
246     while (bi) {
247         if (bi && !bi->hasHiddenExportParent() && !bi->isHidden()) {
248             r += ind + sectionBegin;
249             if ( bi && bi->isScrolled())
250             {
251                 expandBegin = "\n" + ind;
252                 expandBegin += QString("<ac:structured-macro ac:macro-id=\"%1\" ac:name=\"expand\" ac:schema-version=\"1\">").arg(bi->getUuid().toString()) ;
253                 expandBegin += "<ac:rich-text-body>";
254                 expandEnd = "\n" + ind + "</ac:rich-text-body>";
255                 expandEnd += "</ac:structured-macro>";
256             } else
257             {
258                 expandBegin = "";
259                 expandEnd   = "";
260             }
261
262             if (!bi->hasHiddenExportParent() && !bi->isHidden() ) {
263                 visChilds++;
264                 r += ind;
265                 r += itemBegin;
266                     
267                 // Check if first mapcenter is already usded for pageName
268                 if ( !(bi == model->getRootItem()->getFirstBranch() && dia.mapCenterToPageName()))  
269                     r += getBranchText(bi);
270
271                 if (itemBegin.startsWith("<h"))
272                 {
273                     // Current item is heading
274                     r += itemEnd;
275                     r += expandBegin;
276                     r += buildList(bi);
277                     r += expandEnd;
278                 }
279                 else
280                 {
281                     // Current item is list item
282                     r += expandBegin;
283                     r += buildList(bi);
284                     r += expandEnd;
285                     r += itemEnd;
286                 }
287             }
288             r += ind + sectionEnd;
289         }
290         i++;
291         bi = current->getBranchNum(i);
292     }
293
294     return r;
295 }
296
297 QString ExportConfluence::createTOC()
298 {
299     QString toc;
300     QString number;
301     toc += "<table class=\"vym-toc\">\n";
302     toc += "<tr><td class=\"vym-toc-title\">\n";
303     toc += QObject::tr("Contents:", "Used in HTML export");
304     toc += "\n";
305     toc += "</td></tr>\n";
306     toc += "<tr><td>\n";
307     BranchItem *cur = NULL;
308     BranchItem *prev = NULL;
309     model->nextBranch(cur, prev);
310     while (cur) {
311         if (!cur->hasHiddenExportParent() && !cur->hasScrolledParent()) {
312             if (dia.useNumbering())
313                 number = getSectionString(cur);
314             toc +=
315                 QString("<div class=\"vym-toc-branch-%1\">").arg(cur->depth());
316             toc += QString("<a href=\"#%1\"> %2 %3</a><br />\n")
317                        .arg(model->getSelectString(cur))
318                        .arg(number)
319                        .arg(quoteMeta(cur->getHeadingPlain()));
320             toc += "</div>";
321         }
322         model->nextBranch(cur, prev);
323     }
324     toc += "</td></tr>\n";
325     toc += "</table>\n";
326     return toc;
327 }
328
329 void ExportConfluence::doExport(bool useDialog)
330 {
331     // Initialize tmp directory below tmp dir of map vym itself
332     setupTmpDir();
333
334     filePath = tmpDir.path() + "/export.html";
335
336     // Setup dialog and read settings
337     dia.setMapName(model->getMapName());
338     dia.setFilePath(model->getFilePath());
339     dia.setURL(url);
340     dia.setPageName(pageName);
341     BranchItem *bi = (BranchItem*)(model->findBySelectString("mc0"));
342     if (bi)
343         dia.setPageNameHint(bi->getHeadingPlain());
344
345     dia.readSettings();
346
347     if (useDialog) {
348         if (dia.exec() != QDialog::Accepted)
349             return;
350         model->setChanged();
351         url = dia.getUrl();
352         createNewPage = dia.getCreateNewPage();
353         pageName = dia.getPageName();
354     }
355
356     // Open file for writing
357     QFile file(filePath);
358     if (!file.open(QIODevice::WriteOnly)) {
359         QMessageBox::critical(
360             0, QObject::tr("Critical Export Error"),
361             QObject::tr("Trying to save HTML file:") + "\n\n" +
362                 QObject::tr("Could not write %1").arg(filePath));
363         return;
364     }
365     QTextStream ts(&file);
366     ts.setCodec("UTF-8");
367
368     // Hide stuff during export
369     model->setExportMode(true);
370
371     // Create Confluence agent
372     agent = new ConfluenceAgent();
373     if (createNewPage)
374         agent->setJobType(ConfluenceAgent::CreatePage);
375     else
376         agent->setJobType(ConfluenceAgent::UpdatePage);
377     agent->setPageURL(url);
378     agent->setNewPageName(pageName);
379     agent->setUploadPagePath(filePath);
380     agent->setModelID(model->getModelID());
381
382     // Include image of map
383     QString mapImageFilePath = tmpDir.path() + "/mapImage.png";
384     if (dia.includeMapImage())
385     {
386         offset = model->exportImage (mapImageFilePath, false, "PNG");
387         QImage img(mapImageFilePath);
388         ts << "<p>";
389         ts << "  <span style=\"color: rgb(0,170,255);\">\n";
390         if (img.width() > 800)
391             ts << "    <ac:image ac:width=\"800\" >";
392         else
393             ts << "    <ac:image >";
394         ts << "      <ri:attachment ri:filename=\"mapImage.png\"/>";
395         ts << "    </ac:image>\n";
396         ts << "  </span>";
397         ts << "</p>";
398
399
400         agent->addUploadAttachmentPath(mapImageFilePath);
401     }
402
403     // Include table of contents
404     // if (dia.useTOC) ts << createTOC();
405
406     // Main loop over all mapcenters
407     ts << buildList(model->getRootItem()) << "\n";
408
409     ts << "<p style=\"text-align: center;\"> <sub> <em>Page created with ";
410     ts << "<a href=\"https://sourceforge.net/projects/vym/\">" << vymName << " " << vymVersion<< "</a>";
411     ts << "</em> </sub> </p>";
412
413     file.close();
414
415
416     agent->startJob();
417
418     QStringList args;
419
420     // exportName migtht be changed by agent AFTER successfull export and sent to vymModel!
421     exportName = (createNewPage) ? "ConfluenceNewPage" : "ConfluenceUpdatePage";
422     args <<  url;
423     if (!pageName.isEmpty()) 
424         args <<  pageName;
425
426     result = ExportBase::Ongoing;
427
428     // Prepare human readable info in tooltip of LastExport
429     model->setExportLastDestination(
430             QString("Page title: \"%1\"\nUrl: \"%2\"").arg(url));
431
432     completeExport(args);
433
434     dia.saveSettings();
435     model->setExportMode(false);
436
437     // Note: ConfluenceAgent professionally destroys itself after completion
438 }