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
19package org.openoffice.xmerge.merger.merge;
20
21import org.w3c.dom.Node;
22import org.w3c.dom.Element;
23import org.w3c.dom.NodeList;
24import org.w3c.dom.NamedNodeMap;
25
32
39public final class PositionBaseRowMerge implements NodeMergeAlgorithm {
40
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}
This is an implementations of the Iterator interface.
This is an implementation of the NodeMergeAlgorithm interface.
Element splitColRepeatedCell(Element orgCell, int splitNum, int orgNum)
final ConverterCapabilities cc_
The capabilities of this converter.
void mergeCellSequences(Iterator orgSeq, Iterator modSeq)
void merge(Node orgRow, Node modRow)
This method is used to merge two given Node objects.
PositionBaseRowMerge(ConverterCapabilities cc)
Constructor.
Utility methods to handle sheet XML tree.
Definition: SheetUtil.java:32
static void emptyCell(ConverterCapabilities cc, Node node)
Empty the content of a cell value.
Definition: SheetUtil.java:50
Class containing static utility methods for handling XML trees.
Definition: XmlUtil.java:30
static Node deepClone(Node oldNode, Node newNode)
Perform a deep clone of certain Node which will base on the document Node of the old Node.
Definition: XmlUtil.java:42
A ConverterCapabilities object is used by DocumentMerger implementations.
boolean canConvertAttribute(String tag, String attribute)
Test to see if the device document format supports the tag attribute in question.
This interface contains constants for StarOffice XML tags, attributes (StarCalc cell types,...
String TAG_TABLE_CELL
Element tag for table:table-cell.
String ATTRIBUTE_TABLE_NUM_COLUMNS_REPEATED
Attribute tag for table:number-columns-repeated of element table:table-cell.
This is an interface used by the DiffAlgorithm and MergeAlgorithm to access a Document.
Definition: Iterator.java:27
boolean equivalent(Object obj1, Object obj2)
A method to allow the difference algorithm to test whether the obj1 and obj2 in the Iterator are cons...
Object start()
Move to the beginning of the sequence.
Object next()
Move to next element in the sequence.
This is an interface for a MergeAlgorithm to merge two Node objects.
int i
Document and PluginFactory implementations for XML based formats.
Provides implementations for the Iterator interface and related support classes.
The DiffAlgorithm and MergeAlgorithm are used to provide the merge capabilities of this project.
Provides general purpose utilities.
Provides interfaces for converting between two Document formats, and supports a "merge" interface for...
Definition: Convert.java:19