LibreOffice Module xmerge (master)  1
PositionBaseRowMerge.java
Go to the documentation of this file.
1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  * Licensed to the Apache Software Foundation (ASF) under one or more
11  * contributor license agreements. See the NOTICE file distributed
12  * with this work for additional information regarding copyright
13  * ownership. The ASF licenses this file to you under the Apache
14  * License, Version 2.0 (the "License"); you may not use this file
15  * except in compliance with the License. You may obtain a copy of
16  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 
19 package org.openoffice.xmerge.merger.merge;
20 
21 import org.w3c.dom.Node;
22 import org.w3c.dom.Element;
23 import org.w3c.dom.NodeList;
24 import org.w3c.dom.NamedNodeMap;
25 
32 
39 public final class PositionBaseRowMerge implements NodeMergeAlgorithm {
40 
42  private final ConverterCapabilities cc_;
43 
50  cc_ = cc;
51  }
52 
53  public void merge(Node orgRow, Node modRow) {
54 
55  Iterator orgCells = new CellNodeIterator(cc_, orgRow);
56  Iterator modCells = new CellNodeIterator(cc_, modRow);
57 
58  mergeCellSequences(orgCells, modCells);
59  }
60 
61  // used to compare the cell 1 by 1
62  private void mergeCellSequences(Iterator orgSeq, Iterator modSeq) {
63 
64  boolean needMerge = true;
65  Element orgCell, modCell;
66 
67  Object orgSeqObject = orgSeq.start();
68  Object modSeqObject = modSeq.start();
69 
70  while (orgSeqObject != null) {
71 
72  needMerge = true;
73 
74  if (modSeqObject == null) {
75  // no corresponding cell in the target, empty out the cell
76  SheetUtil.emptyCell(cc_, (Node)orgSeqObject);
77  orgSeqObject = orgSeq.next();
78 
79  } else {
80 
81  // compare the cell directly
82  if (!orgSeq.equivalent(orgSeqObject, modSeqObject)) {
83 
84  orgCell = (Element)orgSeqObject;
85  modCell = (Element)modSeqObject;
86 
87  // check whether the original cell with multiple column
88  // if so, need to split one out for merge
89  String orgColRepeated = orgCell.getAttribute(
91  String modColRepeated = modCell.getAttribute(
93 
94  int orgColNum = 1;
95  int modColNum = 1;
96 
97  if (orgColRepeated.length() > 0) {
98  orgColNum = Integer.parseInt(orgColRepeated);
99  }
100  if (modColRepeated.length() > 0) {
101  modColNum = Integer.parseInt(modColRepeated);
102  }
103 
104  // try to find out the common number of repeated cols
105  if (orgColNum == modColNum) {
106  orgSeqObject = orgSeq.next();
107  modSeqObject = modSeq.next();
108 
109  // cut the original cell into 2 half, first half
110  // have the repeated attribute = modify cell attr
111  } else if (orgColNum > modColNum) {
112  Element orgSplitCell = splitColRepeatedCell(
113  orgCell, modColNum,
114  orgColNum - modColNum);
115  // it may equal after the split!
116  if (orgSeq.equivalent(orgSplitCell, modCell)) {
117  needMerge = false;
118  }
119  orgCell = orgSplitCell;
120  modSeqObject = modSeq.next();
121 
122  // cut the modified cell into 2 half, first half
123  // have the repeated attribute = original cell attr
124  } else {
125  Element modSplitCell = splitColRepeatedCell(
126  modCell, orgColNum,
127  modColNum - orgColNum);
128  // it may equal after the split!
129  if (modSeq.equivalent(orgCell, modSplitCell)) {
130  needMerge = false;
131  }
132  modCell = modSplitCell;
133  orgSeqObject = orgSeq.next();
134  }
135 
136  if (needMerge) {
137  mergeCells(orgCell, modCell);
138  }
139 
140  } else {
141  // cells are equivalent, move on to next one.
142  orgSeqObject = orgSeq.next();
143  modSeqObject = modSeq.next();
144  } // end if-else
145  } // end if-else
146  } // end while loop
147 
148  // get the one of the original cell, so that the cloned node
149  // can base it to find the document node
150  orgCell = (Element)orgSeq.start();
151 
152  // add any extra cells to the original cell sequence.
153  for (; modSeqObject != null; modSeqObject = modSeq.next()) {
154  Node clonedNode = XmlUtil.deepClone(orgCell, (Node)modSeqObject);
155  Node parent = orgCell.getParentNode();
156  parent.appendChild(clonedNode);
157  }
158  }
159 
160  private Element splitColRepeatedCell(Element orgCell, int splitNum,
161  int orgNum) {
162  // NOTE: should we really want to do deep clone?
163  // in most the case, it is an empty cell, but the
164  // specification didn't forbid any node to use multiple
165  // column attributes. i.e. the node can contain text
166  // nodes or other things under it.
167  Element splitCell = (Element)(orgCell.cloneNode(true));
168 
169  if (splitNum > 1) {
170  splitCell.setAttribute(
172  String.valueOf(splitNum));
173  } else if (splitNum == 1) {
174  splitCell.removeAttribute(
176  }
177  if (orgNum > 1) {
178  orgCell.setAttribute(
180  String.valueOf(orgNum));
181  } else if (orgNum == 1) {
182  orgCell.removeAttribute(
184  }
185 
186  Node parentNode = orgCell.getParentNode();
187  parentNode.insertBefore(splitCell, orgCell);
188 
189  return splitCell;
190  }
191 
192  private void mergeCells(Element orgCell, Element modCell) {
193 
194  // remove all the supported attributes and possible text child for
195  // string cells
196  SheetUtil.emptyCell(cc_, orgCell);
197 
198  // copy all the supported attributes and possible text child from
199  // the modified cell
200  NamedNodeMap attrNodes = modCell.getAttributes();
201 
202  if (attrNodes != null) {
203 
204  // copy the first text:p node. As it's not necessary only string
205  // type cell can have a text:p section.
206  NodeList paraNodes =
207  modCell.getElementsByTagName(OfficeConstants.TAG_PARAGRAPH);
208 
209  Node firstParaNode = paraNodes.item(0);
210 
211  // try to clone the node
212  if (firstParaNode != null) {
213 
214  Node clonedNode = XmlUtil.deepClone(orgCell, firstParaNode);
215 
216  // insert as the first child of the original cell
217  Node firstChild = orgCell.getFirstChild();
218  if (firstChild != null) {
219  orgCell.insertBefore(clonedNode, firstChild);
220  } else {
221  orgCell.appendChild(clonedNode);
222  }
223  }
224 
225  // check all the attributes and copy those we supported in
226  // converter
227  // NOTE: for attribute list, refer to section 4.7.2 in specification
228  int len = attrNodes.getLength();
229 
230  for (int i = 0; i < len; i++) {
231  Node attr = attrNodes.item(i);
232 
233  // copy the supported attrs
235  attr.getNodeName())) {
236  orgCell.setAttribute(attr.getNodeName(),
237  attr.getNodeValue());
238  }
239  }
240  }
241  }
242 }
void mergeCellSequences(Iterator orgSeq, Iterator modSeq)
boolean canConvertAttribute(String tag, String attribute)
Test to see if the device document format supports the tag attribute in question. ...
static Node deepClone(Node oldNode, Node newNode)
Perform a deep clone of certain.
Definition: XmlUtil.java:42
Utility methods to handle sheet XML tree.
Definition: SheetUtil.java:32
Provides general purpose utilities.
boolean equivalent(Object obj1, Object obj2)
A method to allow the difference algorithm to test whether the.
This interface contains constants for StarOffice XML tags, attributes (StarCalc cell types...
final ConverterCapabilities cc_
The capabilities of this converter.
String TAG_TABLE_CELL
Element tag for table:table-cell.
int i
Class containing static utility methods for handling XML trees.
Definition: XmlUtil.java:30
Object start()
Move to the beginning of the sequence.
Object next()
Move to next element in the sequence.
static void emptyCell(ConverterCapabilities cc, Node node)
Empty the content of a cell value.
Definition: SheetUtil.java:50
void merge(Node orgRow, Node modRow)
This method is used to merge two given.
String ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED
Attribute tag for table:number-columns-repeated of element table:table-cell.
PositionBaseRowMerge(ConverterCapabilities cc)
Constructor.
This is an interface for a MergeAlgorithm to merge two.
Provides implementations for the Iterator interface and related support classes.
Provides interfaces for converting between two.
Definition: Convert.java:19
Element splitColRepeatedCell(Element orgCell, int splitNum, int orgNum)
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a.
Definition: Iterator.java:27