LibreOffice Module xmerge (master)  1
CharacterBaseParagraphMerge.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 java.util.List;
22 import org.w3c.dom.Node;
29 
36 public final class CharacterBaseParagraphMerge implements NodeMergeAlgorithm {
37 
47  public void merge(Node orgPara, Node modPara) {
48  CharacterParser orgParser = new CharacterParser(orgPara);
49  CharacterParser modParser = new CharacterParser(modPara);
50 
51  char[] orgCharArray = orgParser.getCharArray();
52  char[] modCharArray = modParser.getCharArray();
53 
55 
56  Difference[] diffResult = diffAlgo.computeDiffs(orgCharArray,
57  modCharArray);
58  // debug use
59  System.out.println("Diff Result: ");
60  for (int i = 0; i < diffResult.length; i++) {
61  Debug.log(Debug.INFO, diffResult[i].debug());
62  }
63 
64  applyDifference(orgParser, modParser, diffResult);
65  }
66 
67  private void applyDifference(CharacterParser orgParser,
68  CharacterParser modParser,
69  Difference[] diffs) {
70 
71  List<TextNodeEntry> orgNodeList = orgParser.getNodeList();
72  int diffCount = 0;
73  int numNode = orgNodeList.size();
74 
75  for (int i = 0; i < numNode; i++) {
76 
77  int extraChar = 0;
78  int orgDiffCount = diffCount;
79  TextNodeEntry orgTextNode = orgNodeList.get(i);
80 
81  Debug.log(Debug.INFO, "checking node " + (i + 1) + " of " + numNode);
82 
83  // check any difference in this node and estimate the new char num
84  for (; diffCount < diffs.length; diffCount++) {
85 
86  Debug.log(Debug.INFO, " checking diff " + (diffCount + 1) +
87  " of " + diffs.length);
88  Debug.log(Debug.INFO, " OrgPosision <" +
89  diffs[diffCount].getOrgPosition() + "> diffCount <" +
90  diffCount + "> orgDiffCount <" + orgDiffCount + ">");
91 
92  // don't need to check and diffs beyond the current node text
93  // range except the last node
94  if (diffs[diffCount].getOrgPosition() > orgTextNode.endChar() &&
95  i < numNode - 1) {
96  Debug.log(Debug.INFO, " breaking!");
97  break;
98  }
99 
100  if (diffs[diffCount].getOrgPosition()
101  >= orgTextNode.startChar()) {
102  if (diffs[diffCount].getOperation() == Difference.DELETE) {
103  extraChar--;
104  } else if (diffs[diffCount].getOperation()
105  == Difference.ADD) {
106  extraChar++;
107  }
108 
109  }
110  }
111 
112  Debug.log(Debug.INFO, " final diffCount <" + diffCount +
113  "> final orgDiffCount <" + orgDiffCount + ">");
114 
115  // will only try to merge if there is a difference in this node
116  if (diffCount > orgDiffCount) {
117 
118  Debug.log(Debug.INFO, " There is a difference, doing merge");
119  Debug.log(Debug.INFO, " TextNode name <" +
120  orgTextNode.node().getNodeName() + ">");
121  Debug.log(Debug.INFO, " TextNode value <" +
122  orgTextNode.node().getNodeValue() + ">");
123  Debug.log(Debug.INFO, " TextNode start char <" +
124  orgTextNode.startChar() + "> TextNode end char <" +
125  orgTextNode.endChar() + ">");
126  Debug.log(Debug.INFO, " extraChar value <" + extraChar + ">");
127 
128  coreMerge(orgDiffCount, diffCount, diffs,
129  modParser, orgTextNode, extraChar);
130  }
131  }
132  }
133 
134  private void coreMerge(int startDiffNum, int endDiffNum, Difference[] diffs,
135  CharacterParser modParser,
136  TextNodeEntry orgTextNode, int extraChar) {
137 
138  Node orgNode = orgTextNode.node();
139  char[] modTextArray = modParser.getCharArray();
140  String tmpString;
141 
142  // Handle situation where getNodeValue returns null
143  if (orgNode.getNodeValue() != null)
144  tmpString = orgNode.getNodeValue();
145  else
146  tmpString = "";
147 
148  char[] orgNodeText = tmpString.toCharArray();
149  char[] newNodeText;
150 
151  if (orgNodeText.length + extraChar > 0)
152  newNodeText = new char[orgNodeText.length + extraChar];
153  else
154  newNodeText = new char[0];
155 
156  int orgTextPosition = orgTextNode.startChar(); // used for block copy
157  int newTextPosition = 0; // used for block copy
158  int unChangedTextLength = 0;
159 
160  char[] cacheCharArray = new char[endDiffNum - startDiffNum];
161  int cacheLength = 0;
162  int lastDiffOperation = Difference.UNCHANGE;
163  int lastDiffPosition = -1;
164 
165  // starting to diff
166  for (int j = startDiffNum; j < endDiffNum; j++) {
167 
168  // copy any contents before the diff
169  if (diffs[j].getOrgPosition() > orgTextPosition) {
170  // need to flush first
171  if (cacheLength > 0) {
172  System.arraycopy(cacheCharArray, 0,
173  newNodeText, newTextPosition, cacheLength);
174  newTextPosition += cacheLength;
175 
176  // reset the markers
177  lastDiffPosition = -1;
178  lastDiffOperation = Difference.UNCHANGE;
179  cacheLength = 0;
180  }
181 
182  // find out the length how many characters are
183  // untouched by the diff
184  unChangedTextLength = diffs[j].getOrgPosition() -
185  orgTextPosition;
186  System.arraycopy(orgNodeText,
187  orgTextPosition - orgTextNode.startChar(),
188  newNodeText, newTextPosition,
189  unChangedTextLength);
190  orgTextPosition += unChangedTextLength;
191  newTextPosition += unChangedTextLength;
192  }
193 
194  // for any deleted characters, just skip without copy
195  // but still need to take care the cached characters
196  if (diffs[j].getOperation() == Difference.DELETE) {
197  orgTextPosition++;
198 
199  // flush out the cache and copy the content to new Text
200  if (cacheLength > 0) {
201  System.arraycopy(cacheCharArray, 0,
202  newNodeText, newTextPosition, cacheLength);
203  newTextPosition += cacheLength;
204 
205  // reset the markers
206  lastDiffPosition = -1;
207  lastDiffOperation = Difference.UNCHANGE;
208  cacheLength = 0;
209  }
210 
211  continue;
212 
213  // check whether we should flush the cache.
214  // For changed diffs, only continuous changes can be cached
215  // For Add diffs, only same insertion point can be cached
216  // and for both changed/add diffs, need to have same operation
217  // as last cached diffs.
218 
219  } else {
220  if (lastDiffOperation != diffs[j].getOperation() ||
221  (diffs[j].getOperation() == Difference.CHANGE &&
222  diffs[j].getOrgPosition() != lastDiffPosition + 1) ||
223  (diffs[j].getOperation() == Difference.ADD &&
224  diffs[j].getOrgPosition() != lastDiffPosition)) {
225 
226  // flush the cache
227  if (cacheLength > 0) {
228  System.arraycopy(cacheCharArray, 0, newNodeText,
229  newTextPosition, cacheLength);
230  newTextPosition += cacheLength;
231 
232  // reset the markers
233  cacheLength = 0;
234  }
235  }
236 
237  // add the diffs to the cache, now the diffs will be either
238  // a new 'changed' char or is an adjacent following change of
239  // last difference
240  cacheCharArray[cacheLength] =
241  modTextArray[diffs[j].getModPosition()];
242  cacheLength++;
243  lastDiffOperation = diffs[j].getOperation();
244  lastDiffPosition = diffs[j].getOrgPosition();
245 
246  // need to increment the original text position
247  // after we cached it
248  if (lastDiffOperation == Difference.CHANGE) {
249  orgTextPosition++;
250  }
251  }
252  }
253 
254  // flush any contents remaining in the cache
255  if (cacheLength > 0) {
256  System.arraycopy(cacheCharArray, 0, newNodeText,
257  newTextPosition, cacheLength);
258  newTextPosition += cacheLength;
259  // no need to reset any cache-related info as this is a last flush
260  }
261 
262  // copy any contents after all the diffs
263  int orgStartPosition = orgTextNode.startChar();
264  if (orgNodeText.length + orgStartPosition > orgTextPosition) {
265  unChangedTextLength = orgNodeText.length + orgStartPosition
266  - orgTextPosition;
267  System.arraycopy(orgNodeText, orgTextPosition - orgStartPosition,
268  newNodeText, newTextPosition,
269  unChangedTextLength);
270  }
271 
272  // set the text to the original node if there are any diffs processed.
273  // can't use newNodeText.length to check as even it is empty, we may
274  // process a whole bunch of deletion already (i.e. the whole
275  // orgNodeText deleted).
276  if (endDiffNum > startDiffNum) {
277  String newString = new String(newNodeText);
278  orgNode.setNodeValue(newString);
279  }
280  }
281 }
static final int INFO
Informational messages.
Definition: Debug.java:42
int startChar()
Returns the start character.
Provides general purpose utilities.
int getOrgPosition()
Get the original.
void merge(Node orgPara, Node modPara)
Merge two paragraphs.
static void log(int flag, String msg)
Log message based on the flag type.
Definition: Debug.java:205
static final int DELETE
Delete operation.
Definition: Difference.java:33
int getModPosition()
Get the modified.
static final int CHANGE
Change operation.
Definition: Difference.java:36
exports com.sun.star. java
int i
char[] getCharArray()
Returns the character array representation of the text.
String debug()
Display debug information.
int endChar()
Returns the end character.
Difference[] computeDiffs(char[] orgSeq, char[] modSeq)
Return an.
A small class to hold the start/end character position and the.
This is an interface for a MergeAlgorithm to merge two.
void applyDifference(CharacterParser orgParser, CharacterParser modParser, Difference[] diffs)
static final int UNCHANGE
Unchange operation (i.e.
Definition: Difference.java:39
This is a parser to return a character array for difference purpose.
Provides implementations for the Iterator interface and related support classes.
Provides interfaces for converting between two.
Definition: Convert.java:19
This class is used for logging debug messages.
Definition: Debug.java:39
List< TextNodeEntry > getNodeList()
Returns the.
static final int ADD
Add operation.
Definition: Difference.java:30
void coreMerge(int startDiffNum, int endDiffNum, Difference[] diffs, CharacterParser modParser, TextNodeEntry orgTextNode, int extraChar)