19
19
import static com .igormaznitsa .mindmap .swing .panel .StandardTopicAttribute .ATTR_FILL_COLOR ;
20
20
import static com .igormaznitsa .mindmap .swing .panel .StandardTopicAttribute .ATTR_TEXT_COLOR ;
21
21
22
-
23
22
import com .igormaznitsa .meta .annotation .MustNotContainNull ;
24
23
import com .igormaznitsa .meta .annotation .ReturnsOriginal ;
25
24
import com .igormaznitsa .meta .common .utils .Assertions ;
42
41
import java .awt .Color ;
43
42
import java .io .File ;
44
43
import java .io .FileInputStream ;
44
+ import java .io .IOException ;
45
45
import java .net .URI ;
46
46
import java .net .URISyntaxException ;
47
47
import java .util .ArrayList ;
54
54
import javax .annotation .Nonnull ;
55
55
import javax .annotation .Nullable ;
56
56
import javax .swing .Icon ;
57
+ import javax .xml .parsers .ParserConfigurationException ;
57
58
import javax .xml .xpath .XPath ;
58
59
import javax .xml .xpath .XPathConstants ;
60
+ import javax .xml .xpath .XPathExpressionException ;
59
61
import javax .xml .xpath .XPathFactory ;
62
+ import org .jsoup .parser .Parser ;
60
63
import org .w3c .dom .Attr ;
61
64
import org .w3c .dom .Document ;
62
65
import org .w3c .dom .Element ;
66
69
67
70
public class Freemind2MindMapImporter extends AbstractImporter {
68
71
69
- private static final Icon ICO = ImageIconServiceProvider .findInstance ().getIconForId (IconID .POPUP_EXPORT_FREEMIND );
72
+ private static final Icon ICO =
73
+ ImageIconServiceProvider .findInstance ().getIconForId (IconID .POPUP_EXPORT_FREEMIND );
70
74
71
75
private static final Logger LOGGER = LoggerFactory .getLogger (Freemind2MindMapImporter .class );
72
76
73
- private static final Set <String > TOKEN_NEEDS_NEXT_LINE = new HashSet <>(Arrays .asList ("br" , "div" , "p" , "li" ));
77
+ private static final Set <String > TOKEN_NEEDS_NEXT_LINE =
78
+ new HashSet <>(Arrays .asList ("br" , "div" , "p" , "li" ));
74
79
75
80
@ Nonnull
76
81
private static String findArrowlinkDestination (@ Nonnull final Element element ) {
77
82
final List <Element > arrows = Utils .findDirectChildrenForName (element , "arrowlink" );
78
83
return arrows .isEmpty () ? "" : findAttribute (arrows .get (0 ), "destination" );
79
84
}
80
85
81
- private static void processImageLinkForTopic (@ Nonnull final File rootFolder , @ Nonnull final Topic topic , @ Nonnull @ MustNotContainNull final String [] imageUrls ) {
86
+ private static void processImageLinkForTopic (@ Nonnull final File rootFolder ,
87
+ @ Nonnull final Topic topic ,
88
+ @ Nonnull @ MustNotContainNull
89
+ final String [] imageUrls ) {
82
90
for (final String s : imageUrls ) {
83
91
try {
84
92
URI imageUri = URI .create (s );
@@ -91,7 +99,8 @@ private static void processImageLinkForTopic(@Nonnull final File rootFolder, @No
91
99
}
92
100
93
101
if (file .isFile ()) {
94
- topic .setAttribute (ImageVisualAttributePlugin .ATTR_KEY , Utils .rescaleImageAndEncodeAsBase64 (file , -1 ));
102
+ topic .setAttribute (ImageVisualAttributePlugin .ATTR_KEY ,
103
+ Utils .rescaleImageAndEncodeAsBase64 (file , -1 ));
95
104
break ;
96
105
}
97
106
} catch (Exception ex ) {
@@ -102,7 +111,10 @@ private static void processImageLinkForTopic(@Nonnull final File rootFolder, @No
102
111
103
112
@ Nonnull
104
113
@ ReturnsOriginal
105
- private static StringBuilder processHtmlElement (@ Nonnull final NodeList list , @ Nonnull final StringBuilder builder , @ Nonnull @ MustNotContainNull final List <String > imageURLs ) {
114
+ private static StringBuilder processHtmlElement (@ Nonnull final NodeList list ,
115
+ @ Nonnull final StringBuilder builder ,
116
+ @ Nonnull @ MustNotContainNull
117
+ final List <String > imageURLs ) {
106
118
for (int i = 0 ; i < list .getLength (); i ++) {
107
119
final Node n = list .item (i );
108
120
switch (n .getNodeType ()) {
@@ -136,15 +148,19 @@ private static StringBuilder processHtmlElement(@Nonnull final NodeList list, @N
136
148
137
149
@ Nonnull
138
150
@ ReturnsOriginal
139
- private static StringBuilder extractTextFromHtmlElement (@ Nonnull final Element element , @ Nonnull final StringBuilder buffer , @ Nonnull @ MustNotContainNull final List <String > imageURLs ) {
151
+ private static StringBuilder extractTextFromHtmlElement (@ Nonnull final Element element ,
152
+ @ Nonnull final StringBuilder buffer ,
153
+ @ Nonnull @ MustNotContainNull
154
+ final List <String > imageURLs ) {
140
155
processHtmlElement (element .getChildNodes (), buffer , imageURLs );
141
156
return buffer ;
142
157
}
143
158
144
159
@ Nonnull
145
160
@ MustNotContainNull
146
161
private static List <RichContent > extractRichContent (@ Nonnull final Element richContentElement ) {
147
- final List <Element > richContents = Utils .findDirectChildrenForName (richContentElement , "richcontent" );
162
+ final List <Element > richContents =
163
+ Utils .findDirectChildrenForName (richContentElement , "richcontent" );
148
164
149
165
final List <RichContent > result = new ArrayList <>();
150
166
@@ -155,7 +171,9 @@ private static List<RichContent> extractRichContent(@Nonnull final Element richC
155
171
try {
156
172
foundImageUrls .clear ();
157
173
final RichContentType type = RichContentType .valueOf (textType );
158
- final String text = extractTextFromHtmlElement (e , new StringBuilder (), foundImageUrls ).toString ().replace ("\r " , "" );
174
+ final String text =
175
+ extractTextFromHtmlElement (e , new StringBuilder (), foundImageUrls ).toString ()
176
+ .replace ("\r " , "" );
159
177
result .add (new RichContent (type , text , foundImageUrls ));
160
178
} catch (IllegalArgumentException ex ) {
161
179
LOGGER .warn ("Unknown node type : " + textType );
@@ -166,7 +184,8 @@ private static List<RichContent> extractRichContent(@Nonnull final Element richC
166
184
}
167
185
168
186
@ Nonnull
169
- private static String findAttribute (@ Nonnull final Element element , @ Nonnull final String attribute ) {
187
+ private static String findAttribute (@ Nonnull final Element element ,
188
+ @ Nonnull final String attribute ) {
170
189
final NamedNodeMap map = element .getAttributes ();
171
190
for (int i = 0 ; i < map .getLength (); i ++) {
172
191
final Attr attr = (Attr ) map .item (i );
@@ -180,15 +199,29 @@ private static String findAttribute(@Nonnull final Element element, @Nonnull fin
180
199
@ Override
181
200
@ Nullable
182
201
public MindMap doImport (@ Nonnull final PluginContext context ) throws Exception {
183
- final File file = this .selectFileForExtension (context , Texts .getString ("MMDImporters.Freemind2MindMap.openDialogTitle" ), null , "mm" , "Freemind files (.MM)" , Texts .getString ("MMDImporters.ApproveImport" ));
202
+ final File file = this .selectFileForExtension (context ,
203
+ Texts .getString ("MMDImporters.Freemind2MindMap.openDialogTitle" ), null , "mm" ,
204
+ "Freemind files (.MM)" , Texts .getString ("MMDImporters.ApproveImport" ));
184
205
185
206
if (file == null ) {
186
207
return null ;
187
208
}
188
209
189
- final Document document = Utils .loadHtmlDocument (new FileInputStream (file ), "UTF-8" , true );
210
+ try (final FileInputStream in = new FileInputStream (file )) {
211
+ final File rootFolder = file .getParentFile ();
212
+ return extractTopics (rootFolder == null ? file : rootFolder , in );
213
+ }
214
+ }
215
+
216
+ @ Nonnull
217
+ public MindMap extractTopics (@ Nonnull final File rootFolder ,
218
+ @ Nonnull final FileInputStream inputStream )
219
+ throws ParserConfigurationException , IOException , XPathExpressionException {
220
+ final Document document = Utils .load (inputStream , "UTF-8" , Parser .xmlParser (), true );
221
+
190
222
final XPath xpath = XPathFactory .newInstance ().newXPath ();
191
- final Element rootElement = (Element ) xpath .evaluate ("/html/body/map" , document , XPathConstants .NODE );
223
+ final Element rootElement =
224
+ (Element ) xpath .evaluate ("/map" , document , XPathConstants .NODE );
192
225
193
226
if (rootElement == null ) {
194
227
throw new IllegalArgumentException ("Can't parse freemind file as xhtml" );
@@ -203,7 +236,8 @@ public MindMap doImport(@Nonnull final PluginContext context) throws Exception {
203
236
if (list .isEmpty ()) {
204
237
Assertions .assertNotNull (resultedMap .getRoot ()).setText ("Empty" );
205
238
} else {
206
- parseTopic (file .getParentFile (), resultedMap , null , resultedMap .getRoot (), list .get (0 ), idTopicMap , linksMap );
239
+ parseTopic (rootFolder , resultedMap , null , resultedMap .getRoot (), list .get (0 ), idTopicMap ,
240
+ linksMap );
207
241
}
208
242
209
243
for (final Map .Entry <String , String > l : linksMap .entrySet ()) {
@@ -217,7 +251,10 @@ public MindMap doImport(@Nonnull final PluginContext context) throws Exception {
217
251
return resultedMap ;
218
252
}
219
253
220
- private void parseTopic (@ Nonnull final File rootFolder , @ Nonnull final MindMap map , @ Nullable Topic parent , @ Nullable Topic preGeneratedTopic , @ Nonnull Element element , @ Nonnull final Map <String , Topic > idTopicMap , @ Nonnull final Map <String , String > linksMap ) {
254
+ private void parseTopic (@ Nonnull final File rootFolder , @ Nonnull final MindMap map ,
255
+ @ Nullable Topic parent , @ Nullable Topic preGeneratedTopic ,
256
+ @ Nonnull Element element , @ Nonnull final Map <String , Topic > idTopicMap ,
257
+ @ Nonnull final Map <String , String > linksMap ) {
221
258
222
259
final String text = findAttribute (element , "text" );
223
260
final String id = findAttribute (element , "id" );
@@ -246,14 +283,17 @@ private void parseTopic(@Nonnull final File rootFolder, @Nonnull final MindMap m
246
283
final Color backgroundColorConverted = Utils .html2color (backgroundColor , false );
247
284
248
285
if (colorConverted != null ) {
249
- topicToProcess .setAttribute (ATTR_TEXT_COLOR .getText (), Utils .color2html (colorConverted , false ));
286
+ topicToProcess .setAttribute (ATTR_TEXT_COLOR .getText (),
287
+ Utils .color2html (colorConverted , false ));
250
288
}
251
289
252
290
if (backgroundColorConverted != null ) {
253
- topicToProcess .setAttribute (ATTR_FILL_COLOR .getText (), Utils .color2html (backgroundColorConverted , false ));
291
+ topicToProcess .setAttribute (ATTR_FILL_COLOR .getText (),
292
+ Utils .color2html (backgroundColorConverted , false ));
254
293
} else {
255
294
if (colorConverted != null ) {
256
- topicToProcess .setAttribute (ATTR_FILL_COLOR .getText (), Utils .color2html (Utils .makeContrastColor (colorConverted ), false ));
295
+ topicToProcess .setAttribute (ATTR_FILL_COLOR .getText (),
296
+ Utils .color2html (Utils .makeContrastColor (colorConverted ), false ));
257
297
}
258
298
}
259
299
}
@@ -348,7 +388,8 @@ private static final class RichContent {
348
388
private final String text ;
349
389
private final String [] imageUrls ;
350
390
351
- private RichContent (@ Nonnull final RichContentType type , @ Nonnull final String text , @ Nonnull @ MustNotContainNull final List <String > foundImageUrls ) {
391
+ private RichContent (@ Nonnull final RichContentType type , @ Nonnull final String text ,
392
+ @ Nonnull @ MustNotContainNull final List <String > foundImageUrls ) {
352
393
this .type = type ;
353
394
this .text = text ;
354
395
this .imageUrls = foundImageUrls .toArray (new String [0 ]);
0 commit comments