1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.wordtemplate.service;
35
36 import fr.paris.lutece.plugins.wordtemplate.exception.WordTemplateException;
37 import java.util.ArrayList;
38 import java.util.List;
39 import org.apache.poi.xwpf.usermodel.BodyElementType;
40 import org.apache.poi.xwpf.usermodel.IBody;
41 import org.apache.poi.xwpf.usermodel.IBodyElement;
42 import org.apache.poi.xwpf.usermodel.XWPFDocument;
43 import org.apache.poi.xwpf.usermodel.XWPFParagraph;
44 import org.apache.poi.xwpf.usermodel.XWPFRun;
45 import org.apache.poi.xwpf.usermodel.XWPFTable;
46 import org.apache.poi.xwpf.usermodel.XWPFTableCell;
47 import org.apache.poi.xwpf.usermodel.XWPFTableRow;
48 import org.apache.xmlbeans.XmlCursor;
49 import org.apache.xmlbeans.XmlException;
50 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
51 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
52 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
53 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
54 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
55 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
56 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
57 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
58
59
60
61
62 public class WordService
63 {
64
65
66
67
68
69
70
71
72 public String getContent( IBody body ) throws XmlException
73 {
74 StringBuilder stringBuilder = new StringBuilder( );
75
76 for ( IBodyElement bodyElement : body.getBodyElements( ) )
77 {
78 if ( bodyElement.getElementType( ).equals( BodyElementType.PARAGRAPH ) )
79 {
80 for ( XWPFRun run : ( (XWPFParagraph) bodyElement ).getRuns( ) )
81 {
82 String text = run.getText( 0 );
83 stringBuilder.append( text );
84 }
85 }
86 if ( bodyElement.getElementType( ).equals( BodyElementType.TABLE ) )
87 {
88 for ( XWPFTableRow row : ( (XWPFTable) bodyElement ).getRows( ) )
89 {
90 for ( XWPFTableCell cell : row.getTableCells( ) )
91 {
92 getContent( cell );
93 }
94 }
95 }
96 }
97
98 return stringBuilder.toString( );
99 }
100
101
102
103
104
105
106
107
108
109 public static void cloneBodyElement( IBodyElement clone, IBodyElement source )
110 {
111 if ( clone.getElementType( ).equals( BodyElementType.PARAGRAPH ) && source.getElementType( ).equals( BodyElementType.PARAGRAPH ) )
112 {
113 cloneParagraph( (XWPFParagraph) clone, (XWPFParagraph) source, false );
114 return;
115 }
116 if ( clone.getElementType( ).equals( BodyElementType.TABLE ) && source.getElementType( ).equals( BodyElementType.TABLE ) )
117 {
118 cloneTable( (XWPFTable) clone, (XWPFTable) source, false );
119 return;
120 }
121 throw new WordTemplateException( "Try to clone one BodyElement into another but with different type" );
122 }
123
124
125
126
127
128
129
130
131
132
133 public static void cloneParagraph( XWPFParagraph clone, XWPFParagraph source, boolean isEmpty )
134 {
135 CTPPr pPr = clone.getCTP( ).isSetPPr( ) ? clone.getCTP( ).getPPr( ) : clone.getCTP( ).addNewPPr( );
136 pPr.set( source.getCTP( ).getPPr( ) );
137
138 if ( isEmpty )
139 {
140 return;
141 }
142
143 for ( XWPFRun run : source.getRuns( ) )
144 {
145 XWPFRun newRun = clone.createRun( );
146 cloneRun( newRun, run, false );
147 }
148 }
149
150
151
152
153
154
155
156
157
158
159 public static void cloneRun( XWPFRun clone, XWPFRun source, boolean isEmpty )
160 {
161 CTRPr rPr = clone.getCTR( ).isSetRPr( ) ? clone.getCTR( ).getRPr( ) : clone.getCTR( ).addNewRPr( );
162 rPr.set( source.getCTR( ).getRPr( ) );
163
164 if ( isEmpty )
165 {
166 return;
167 }
168
169 clone.setText( source.getText( 0 ) );
170 }
171
172
173
174
175
176
177
178
179
180
181 public static void cloneTable( XWPFTable clone, XWPFTable source, boolean isEmpty )
182 {
183 CTTblPr tblPr = clone.getCTTbl( ).getTblPr( ) != null ? clone.getCTTbl( ).getTblPr( ) : clone.getCTTbl( ).addNewTblPr( );
184 tblPr.set( source.getCTTbl( ).getTblPr( ) );
185
186 if ( isEmpty )
187 {
188 return;
189 }
190
191 boolean first = true;
192 List<XWPFTableRow [ ]> newRows = new ArrayList<>( );
193
194 for ( XWPFTableRow row : source.getRows( ) )
195 {
196 XWPFTableRow newRow;
197 if ( first && clone.getRow( 0 ) != null )
198 {
199 newRow = clone.getRow( 0 );
200 }
201 else
202 {
203 newRow = clone.createRow( );
204 }
205 XWPFTableRow [ ] twoRows = {
206 newRow, row
207 };
208 newRows.add( twoRows );
209 first = false;
210 }
211
212 for ( XWPFTableRow [ ] newRow : newRows )
213 {
214 cloneTableRow( newRow [0], newRow [1], false );
215 }
216 }
217
218
219
220
221
222
223
224
225
226
227 public static void cloneTableRow( XWPFTableRow clone, XWPFTableRow source, boolean isEmpty )
228 {
229 CTTrPr trPr = clone.getCtRow( ).getTrPr( ) != null ? clone.getCtRow( ).getTrPr( ) : clone.getCtRow( ).addNewTrPr( );
230 trPr.set( source.getCtRow( ).getTrPr( ) );
231
232 if ( isEmpty )
233 {
234 return;
235 }
236
237 boolean first = true;
238
239 for ( XWPFTableCell cell : source.getTableCells( ) )
240 {
241 XWPFTableCell newCell;
242 if ( first && clone.getCell( 0 ) != null )
243 {
244 newCell = clone.getCell( 0 );
245 }
246 else
247 {
248 newCell = clone.createCell( );
249 }
250 cloneTableCell( newCell, cell );
251 first = false;
252 }
253 }
254
255
256
257
258
259
260
261
262
263 public static void cloneTableCell( XWPFTableCell clone, XWPFTableCell source )
264 {
265 cloneTableCell( clone, source, 0, source.getBodyElements( ).size( ) );
266 }
267
268
269
270
271
272
273
274
275
276
277
278 public static void cloneTableCell( XWPFTableCell clone, XWPFTableCell source, int fromIndex, int toIndex )
279 {
280 CTTcPr tcPr = clone.getCTTc( ).getTcPr( ) != null ? clone.getCTTc( ).getTcPr( ) : clone.getCTTc( ).addNewTcPr( );
281 tcPr.set( source.getCTTc( ).getTcPr( ) );
282
283 XWPFParagraph firstParagraph = clone.getParagraphs( ).get( 0 );
284 XmlCursor cursor = firstParagraph.getCTP( ).newCursor( );
285
286 if ( !( fromIndex >= 0 && fromIndex <= toIndex && toIndex <= source.getBodyElements( ).size( ) ) )
287 {
288 return;
289 }
290
291 for ( int i = fromIndex; i < toIndex; i++ )
292 {
293 IBodyElement bodyElement = source.getBodyElements( ).get( i );
294 if ( bodyElement.getElementType( ).equals( BodyElementType.PARAGRAPH ) )
295 {
296 XWPFParagraph newParagraph = clone.insertNewParagraph( cursor );
297 cloneParagraph( newParagraph, (XWPFParagraph) bodyElement, false );
298 cursor.dispose( );
299 cursor = newParagraph.getCTP( ).newCursor( );
300 cursor.toNextSibling( );
301 }
302 if ( bodyElement.getElementType( ).equals( BodyElementType.TABLE ) )
303 {
304 XWPFTable newTable = clone.insertNewTbl( cursor );
305 cloneTable( newTable, (XWPFTable) bodyElement, false );
306 cursor.dispose( );
307 cursor = newTable.getCTTbl( ).newCursor( );
308 cursor.toNextSibling( );
309 }
310 }
311 cursor.dispose( );
312 clone.removeParagraph( clone.getParagraphs( ).size( ) - 1 );
313 }
314
315
316
317
318
319
320
321
322
323
324 public static XWPFTable insertTable( IBody body, XWPFTable table, int posDest )
325 {
326 IBodyElement bodyElement;
327
328 if ( posDest > body.getBodyElements( ).size( ) || posDest < 0 )
329 {
330 return null;
331 }
332
333 if ( posDest == body.getBodyElements( ).size( ) )
334 {
335 bodyElement = body.getBodyElements( ).get( posDest - 1 );
336 }
337 else
338 {
339 bodyElement = body.getBodyElements( ).get( posDest );
340 }
341
342 XmlCursor cursor = getCursor( bodyElement );
343
344 if ( posDest == body.getBodyElements( ).size( ) )
345 {
346 cursor.toParent( );
347 cursor.toEndToken( );
348 }
349
350 XWPFTable newTable = insertTable( body, table, cursor );
351 return newTable;
352 }
353
354
355
356
357
358
359
360
361
362
363 public static XWPFTable insertTable( IBody body, XWPFTable table, XmlCursor cursor )
364 {
365 XWPFTable newTable = body.insertNewTbl( cursor );
366 WordService.cloneTable( newTable, table, false );
367 return newTable;
368 }
369
370
371
372
373
374
375
376
377
378 public static XWPFTableRow insertTableRow( XWPFTable table, XWPFTableRow tableRow, int posDest )
379 {
380 table.getCTTbl( ).insertNewTr( posDest );
381 table.getCTTbl( ).setTrArray( posDest, tableRow.getCtRow( ) );
382 XWPFTableRow newTableRow = new XWPFTableRow( table.getCTTbl( ).getTrArray( posDest ), table );
383
384 table.getRows( ).add( posDest, newTableRow );
385
386 return newTableRow;
387 }
388
389
390
391
392
393
394
395
396
397 public static XWPFTableRow insertTableRow( XWPFTable table, XWPFTableRow tableRow, XmlCursor cursor )
398 {
399 XWPFTableRow cursorTableRow = table.getRow( (CTRow) cursor.getObject( ) );
400 int posDest = table.getRows( ).indexOf( cursorTableRow );
401 return insertTableRow( table, tableRow, posDest );
402 }
403
404
405
406
407
408
409
410
411
412 public static XWPFTableCell insertTableCell( XWPFTableRow tableRow, XWPFTableCell tableCell, int posDest )
413 {
414 tableCell = addTableCell( tableRow, posDest );
415 cloneTableCell( tableRow.getCell( posDest ), tableCell );
416 return tableRow.getCell( posDest );
417 }
418
419
420
421
422
423
424
425
426
427 public static XWPFTableCell insertTableCell( XWPFTableRow tableRow, XWPFTableCell tableCell, XmlCursor cursor )
428 {
429 XWPFTableCell cursorTableCell = tableRow.getTableCell( (CTTc) cursor.getObject( ) );
430 int posDest = tableRow.getTableCells( ).indexOf( cursorTableCell );
431 return insertTableCell( tableRow, tableCell, posDest );
432 }
433
434
435
436
437
438
439
440
441
442 public static XWPFParagraph insertParagraph( IBody body, XWPFParagraph paragraph, int posDest )
443 {
444 IBodyElement bodyElement;
445
446 if ( posDest > body.getBodyElements( ).size( ) || posDest < 0 )
447 {
448 return null;
449 }
450
451 if ( posDest == body.getBodyElements( ).size( ) )
452 {
453 bodyElement = body.getBodyElements( ).get( posDest - 1 );
454 }
455 else
456 {
457 bodyElement = body.getBodyElements( ).get( posDest );
458 }
459
460 XmlCursor cursor = getCursor( bodyElement );
461
462 if ( posDest == body.getBodyElements( ).size( ) )
463 {
464 cursor.toParent( );
465 cursor.toEndToken( );
466 }
467
468 return insertParagraph( body, paragraph, cursor );
469 }
470
471
472
473
474
475
476
477
478
479 public static XWPFParagraph insertParagraph( IBody body, XWPFParagraph paragraph, XmlCursor cursor )
480 {
481 XWPFParagraph newParagraph = body.insertNewParagraph( cursor );
482 WordService.cloneParagraph( newParagraph, paragraph, false );
483 return newParagraph;
484 }
485
486
487
488
489
490
491
492
493
494 public static XWPFRun insertRun( XWPFParagraph paragraphe, XWPFRun run, int posDest )
495 {
496 XWPFRun newRun = paragraphe.insertNewRun( posDest );
497 cloneRun( newRun, run, false );
498 return newRun;
499 }
500
501
502
503
504
505
506
507
508
509 public static XWPFRun insertRun( XWPFParagraph paragraphe, XWPFRun run, XmlCursor cursor )
510 {
511 XWPFRun cursorRun = paragraphe.getRun( (CTR) cursor.getObject( ) );
512 int posDest = paragraphe.getRuns( ).indexOf( cursorRun );
513 return insertRun( paragraphe, run, posDest );
514 }
515
516
517
518
519
520
521
522 public static void splitParagraph( XWPFParagraph paragraph, int pos )
523 {
524 if ( !( pos > 0 && pos < paragraph.getRuns( ).size( ) ) )
525 {
526 return;
527 }
528 XWPFParagraph beforeParagraph = WordService.insertParagraph( paragraph.getBody( ), paragraph, paragraph.getCTP( ).newCursor( ) );
529 while ( beforeParagraph.removeRun( pos ) )
530 {
531 }
532 while ( pos > 0 )
533 {
534 pos--;
535 paragraph.removeRun( pos );
536 }
537 }
538
539
540
541
542
543
544
545 public static void splitRun( XWPFRun run, int pos )
546 {
547 if ( !( run.getParent( ) instanceof XWPFParagraph ) )
548 {
549 return;
550 }
551 if ( !( pos > 0 && pos < run.toString( ).length( ) ) )
552 {
553 return;
554 }
555 String beforeText = run.toString( ).substring( 0, pos );
556 String afterText = run.toString( ).substring( pos );
557 XWPFParagraph paragraph = (XWPFParagraph) run.getParent( );
558 int numRun = paragraph.getRuns( ).indexOf( run );
559 XWPFRun beforeRun = paragraph.insertNewRun( numRun );
560 WordService.cloneRun( beforeRun, run, true );
561 beforeRun.setText( beforeText, 0 );
562 run.setText( afterText, 0 );
563 }
564
565
566
567
568
569
570
571 public static void splitTable( XWPFTable table, int pos )
572 {
573 if ( !( pos > 0 && pos < table.getRows( ).size( ) ) )
574 {
575 return;
576 }
577 XWPFTable beforeTable = WordService.insertTable( table.getBody( ), table, table.getCTTbl( ).newCursor( ) );
578 while ( beforeTable.removeRow( pos ) )
579 {
580 }
581 while ( pos > 0 )
582 {
583 pos--;
584 table.removeRow( pos );
585 }
586 }
587
588
589
590
591
592
593
594 public static void splitTableRow( XWPFTableRow tableRow, int pos )
595 {
596 if ( !( pos > 0 && pos < tableRow.getTableCells( ).size( ) ) )
597 {
598 return;
599 }
600 XWPFTableRow beforeTableRow = WordService.insertTableRow( tableRow.getTable( ), tableRow, tableRow.getCtRow( ).newCursor( ) );
601 while ( WordService.removeTableCell( beforeTableRow, pos ) )
602 {
603 }
604 while ( pos > 0 )
605 {
606 pos--;
607 WordService.removeTableCell( tableRow, pos );
608 }
609 }
610
611
612
613
614
615
616
617 public static void splitTableCell( XWPFTableCell tableCell, int pos )
618 {
619 if ( !( pos > 0 && pos < tableCell.getBodyElements( ).size( ) ) )
620 {
621 return;
622 }
623 XWPFTableRow tableRow = tableCell.getTableRow( );
624 int posCell = tableRow.getTableCells( ).indexOf( tableCell );
625 XWPFTableCell beforeTableCell1 = WordService.addTableCell( tableRow, posCell );
626 XWPFTableCell beforeTableCell2 = WordService.addTableCell( tableRow, posCell );
627 WordService.cloneTableCell( beforeTableCell2, tableCell, 0, pos );
628 WordService.cloneTableCell( beforeTableCell1, tableCell, pos, tableCell.getBodyElements( ).size( ) );
629 WordService.removeTableCell( tableRow, posCell + 2 );
630 }
631
632
633
634
635
636
637
638
639 public static XWPFTableCell addTableCell( XWPFTableRow tableRow, int posDest )
640 {
641 CTTc cTTc = tableRow.getCtRow( ).insertNewTc( posDest );
642 XWPFTableCell tableCell = new XWPFTableCell( cTTc, tableRow, tableRow.getTable( ).getBody( ) );
643 tableRow.getTableCells( ).add( posDest, tableCell );
644 return tableRow.getCell( posDest );
645 }
646
647
648
649
650
651
652
653
654 public static boolean removeTableCell( XWPFTableRow tableRow, int posDest )
655 {
656 if ( posDest >= 0 && posDest < tableRow.getTableCells( ).size( ) )
657 {
658 tableRow.getCtRow( ).removeTc( posDest );
659 tableRow.getTableCells( ).remove( posDest );
660 return true;
661 }
662 return false;
663 }
664
665
666
667
668
669
670
671 public static void removeBodyElement( IBody body, int posDest )
672 {
673 IBodyElement bodyElement = body.getBodyElements( ).get( posDest );
674 XmlCursor cursor = getCursor( bodyElement );
675 removeElement( cursor );
676 }
677
678
679
680
681
682
683 public static void removeElement( XmlCursor cursor )
684 {
685 cursor.removeXml( );
686 }
687
688
689
690
691
692
693
694 public static XmlCursor getCursor( IBodyElement bodyElement )
695 {
696 XmlCursor cursor = null;
697
698 switch( bodyElement.getElementType( ) )
699 {
700 case PARAGRAPH:
701 cursor = ( (XWPFParagraph) bodyElement ).getCTP( ).newCursor( );
702 break;
703 case TABLE:
704 cursor = ( (XWPFTable) bodyElement ).getCTTbl( ).newCursor( );
705 break;
706 }
707
708 return cursor;
709 }
710 }