View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the License); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.editor.textEditor.viewers;
13  
14  import java.util.ArrayList;
15  import java.util.List;
16  import java.util.Set;
17  
18  import org.eclipse.gef.EditPart;
19  import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
20  import org.w3c.dom.Node;
21  
22  import sk.baka.ikslibs.ids.IDManager;
23  import sk.baka.ikslibs.interval.DOMInterval;
24  import sk.baka.ikslibs.interval.DOMIntervalSet;
25  import sk.uniba.euromath.editor.selections.DOMSelectionChangedEvent;
26  import sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener;
27  import sk.uniba.euromath.editor.selections.IDOMSelectionProvider;
28  import sk.uniba.euromath.editor.textEditor.ITextPieceContainer;
29  import sk.uniba.euromath.editor.textEditor.ITextPieceKeeper;
30  import sk.uniba.euromath.editor.textEditor.TextEditPartFactory;
31  import sk.uniba.euromath.editor.textEditor.editParts.TextEditPart;
32  import sk.uniba.euromath.editor.xmlEditor.IdVisualInfo;
33  import sk.uniba.euromath.editor.xmlEditor.XMLEditDomain;
34  import sk.uniba.euromath.editor.xmlEditor.XMLEditPartFactory;
35  import sk.uniba.euromath.editor.xmlEditor.XMLEditor;
36  import sk.uniba.euromath.editor.xmlEditor.editParts.XMLEditPart;
37  import sk.uniba.euromath.editor.xmlEditor.viewers.IXMLGraphicalViewer;
38  
39  /***
40   * Overrides selection funcionality of ScrollingGraphicalViewer. Selection is represented by DOMIntervalSet.
41   * Converts DOMIntervals from DOMIntervalSet to EditParts and start offset and end offset in this EditParts
42   * 
43   * Call @see #commitSelection() when selecting ends (mouse up, button up), this fires selection to 
44   * <code>selectionChangedListeners</code> 
45   * 
46   * @author Martin Kollar
47   */
48  
49  public class ScrollingTextGraphicalViewer extends ScrollingGraphicalViewer 
50  				implements IXMLGraphicalViewer{
51  	
52  	/***
53  	 * Local selection for this viewer. This selection is commited to listeners by calling 
54  	 * fireSelectionChanged() method
55  	 */
56  	private DOMIntervalSet localSelection;
57  	protected List<IDOMSelectionChangedListener> selectionChangedListeners =
58  		new ArrayList<IDOMSelectionChangedListener>();
59  
60  	private XMLEditor editor;
61  	
62  	/***
63  	 * @param editor Editor that uses this viewer to view its state
64  	 */
65  	public ScrollingTextGraphicalViewer(XMLEditor editor){
66  		super();
67  		this.editor = editor;
68  	}
69  	
70  	/***
71  	 * @param listener new listener to be add from selectionChangedListeners
72  	 */
73  	public void addSelectionChangedListener(IDOMSelectionChangedListener listener) {
74  		if (!(selectionChangedListeners.contains(listener)))
75  			selectionChangedListeners.add(listener);
76  	}
77  
78  	/***
79  	 * @param listener listener to be removed from selectionChangedListeners
80  	 */
81  	public void removeSelectionChangedListener(IDOMSelectionChangedListener listener) {
82  		selectionChangedListeners.remove(listener);
83  	}
84  
85  	public void showSelection(DOMIntervalSet selection) {
86  		// TODO Auto-generated method stub
87  		
88  	}
89  	
90  	/***
91  	 * Deselects editparts with Ids, that were in previous selection and select editparts
92  	 * that are in DOMIntervalSet
93  	 * @param selection DOMIntervalSet containing DOMInetervals, that have to be selected
94  	 */
95  	public void setSelection(DOMIntervalSet selection) {
96  		IdVisualInfo visualInfo = ((XMLEditPartFactory)getEditPartFactory()).getVisualInfo();
97  		
98  		Set<String> oldIds = getDOMSelection().getContentIds(getIDManager());
99  		
100 		for (String notSelectedId : oldIds){
101 			//deselect appropriate EditParts
102             if (notSelectedId.indexOf(':') >= 0)
103             	notSelectedId = notSelectedId.substring(0, notSelectedId.indexOf(':'));
104             
105             List<XMLEditPart> notSelectedParts = visualInfo.getVisualParts(notSelectedId);
106             for (XMLEditPart editPart : notSelectedParts)
107             	deselect(editPart);
108 		}
109 		
110 		this.localSelection = selection;
111 		
112 		for (DOMInterval interval : selection.getIntervals()){
113 			
114 			List<Node> contents = interval.getContents();
115 			
116 			int startOffset = -1;
117 			int endOffset = -1;
118 						
119 			if ( (interval.getStartingIndex() > -1) && (interval.getEndingIndex() > -1) ) {
120 				//this interval selects text
121 				if (getEditPartFactory() instanceof TextEditPartFactory){
122 					
123 					ITextPieceContainer container1 = ((TextEditPartFactory)getEditPartFactory()).
124 						getIdLastContainerMap().get(interval.from.pointsTo);					
125 					ITextPieceKeeper keeper1 = container1.OffsetInPieceKeeper(interval.getStartingIndex());
126 					startOffset = interval.getStartingIndex() - keeper1.getTextPieceInfo().getOffset();
127 					
128 					ITextPieceContainer container2 = ((TextEditPartFactory)getEditPartFactory()).
129 						getIdLastContainerMap().get(interval.to.pointsTo);					
130 					ITextPieceKeeper keeper2 = container2.OffsetInPieceKeeper(interval.getEndingIndex());
131 					endOffset = interval.getEndingIndex() - keeper2.getTextPieceInfo().getOffset();
132 					
133 					if (container1 == container2){
134 						// interval is contained in one textual node
135 						int i = container1.indexOf(keeper1);
136 						int j = container1.indexOf(keeper2);
137 						if (i==j){
138 							// interval is in one ITextPieceKeeper
139 							
140 							//TODO: Kollar - implement folovong select method
141 							keeper1.select(startOffset, endOffset);
142 							select(keeper1, startOffset, endOffset);
143 							break; //go to another interval from DOMIntervalSet
144 						}
145 						if (i<j){
146 							select(keeper1, startOffset, keeper1.getText().length());
147 							select(keeper2, 0, endOffset);
148 							keeper1.select(startOffset,keeper1.getText().length());
149 							keeper2.select(0, endOffset);
150 							for (int k = i+1; k<j-1; k++){
151 								//select(((XMLEditPart)container1.getPiece(k)));
152 								ITextPieceKeeper keeper = container1.getPiece(k);
153 								keeper.select();
154 								select(keeper,0,keeper.getText().length());
155 							}
156 							break; //go to another interval from DOMIntervalSet
157 						}
158 						throw new IllegalStateException("Interval starting index have to be befor interval ending index");
159 					}
160 						
161 					//interval is more than one container
162 					ITextPieceContainer container;
163 					for (Node node : contents){
164 						String nodeId = getIDManager().getIDNull(node);
165 						if (nodeId != null){
166 							container = ((TextEditPartFactory)getEditPartFactory()).
167 								getIdLastContainerMap().get(nodeId);
168 							
169 							int fromKeeper = 0;
170 							int toKeeper = container.getPieceCount()-1;
171 							if (container == container1)
172 								fromKeeper = container1.indexOf(keeper1);
173 							if (container == container2)
174 								toKeeper = container2.indexOf(keeper2);
175 							for (int i=fromKeeper; i<toKeeper; i++){
176 								ITextPieceKeeper keeper = container.getPiece(i);
177 								int start;
178 								int end;
179 								if (keeper == keeper1)
180 									start = startOffset;
181 								else
182 									start = 0;
183 								if (keeper == keeper2)
184 									end = endOffset;
185 								else
186 									end = keeper.getText().length();
187 								keeper.select(start, end);
188 								select(keeper,start,end);
189 								break; //go to another interval from DOMIntervalSet
190 							}
191 						}
192 					}
193 					
194 				}
195 			}
196 			// We are not using TextEditPartFactory (probably using XMLEditor)
197 			// or selecting whole elements
198 			for (Node node : contents){
199 				String nodeId = getIDManager().getIDNull(node);
200 				if (nodeId != null){
201 		            List<XMLEditPart> selectedParts = visualInfo.getVisualParts(nodeId);
202 		            for(XMLEditPart xmlEditPart : selectedParts){
203 		            	select(xmlEditPart);
204 		            }
205 		        }
206 			}
207 				
208 			//editparts in this interval are processed we can go to next interval
209 		}
210 	}
211 		
212 	
213 	/***
214 	 * Effect is same as using setSelection
215 	 *@param event DOMSelectionChangedEvent that contains source of new selction, that should be
216 	 *				some XMLEditor and DOMIntervalSet as selection
217 	 */
218 	public void selectionChanged(DOMSelectionChangedEvent event) {
219 		setSelection(event.getDOMSelection());
220 	}
221 	
222 	/***
223 	 * This is called when selecting ends (mouse up or button up)
224 	 */
225 	@Override
226 	protected void fireSelectionChanged(){
227 		DOMSelectionChangedEvent event = new DOMSelectionChangedEvent(this, this.localSelection);
228 		for (IDOMSelectionChangedListener listener : selectionChangedListeners)
229 			listener.selectionChanged(event);
230 	}
231 
232 	protected void select(ITextPieceKeeper keeper, int start, int end){
233 		keeper.select(start, end);
234 		if (!(getSelectedEditParts().contains(keeper))){
235 			getSelectedEditParts().add(keeper);
236 			//fireSelectionChanged();
237 		}
238 	}
239 	
240 	/***
241 	 * Selecting whole EditPart. When this EditPart was not in selected EditParts, than 
242 	 * fireSelectionChanged()
243 	 * 
244 	 * If <code>editpart</code> is ITextPieceKeeper then visualization is left on 
245 	 * @see ITextPieceKeeper#select()
246 	 * If <code>editpart</code> is not ITextPieceKeeper then visualization is left on this editpart.
247 	 * @see EditPart#setSelected(EditPart.SELECTED)
248 	 * 
249 	 * @param editpart EditPart that is going to be selected
250 	 */
251 	@Override
252 	public void select(EditPart editpart){
253 		//super.select(editpart);
254 		editpart.setSelected(EditPart.SELECTED);
255 		
256 		if (editpart instanceof ITextPieceKeeper)
257 			((ITextPieceKeeper)editpart).select();
258 			
259 		
260 		if (!(getSelectedEditParts().contains(editpart))){
261 			getSelectedEditParts().add(editpart);
262 			//fireSelectionChanged();
263 		}			
264 			
265 	}
266 	
267 	
268 	/***
269 	 * Deselecting whole EditPart. Alwas fires selection change
270 	 * 
271 	 * If <code>editpart</code> is ITextPieceKeeper then visualization is left on 
272 	 * @see ITextPieceKeeper#deselect()
273 	 * If <code>editpart</code> is not ITextPieceKeeper then visualization is left on this editpart.
274 	 * @see EditPart#setSelected(EditPart.SELECTED_NONE)
275 	 * 
276 	 * @param editpart EditPart that is going to be deselected
277 	 */
278 	@Override
279 	public void deselect(EditPart editpart){
280 		editpart.setSelected(EditPart.SELECTED_NONE);
281 		
282 		if (editpart instanceof ITextPieceKeeper)
283 			((ITextPieceKeeper)editpart).deselect();
284 		
285 		if (getSelectedEditParts().contains(editpart)){
286 			getSelectedEditParts().remove(editpart);
287 			//fireSelectionChanged();
288 		}
289 			
290 	}
291 	
292 	/***
293 	 * Deselects all selected editparts.
294 	 * At the end fires selection change
295 	 */
296 	@Override
297 	public void deselectAll(){
298 		super.deselectAll();
299 		List<EditPart> list = new ArrayList<EditPart>();
300 		list.addAll(getSelectedEditParts());
301 		
302 		this.selection.clear();
303 		
304 		for(EditPart editpart : list){
305 			editpart.setSelected(EditPart.SELECTED_NONE);
306 			
307 			if (editpart instanceof ITextPieceKeeper)
308 				((ITextPieceKeeper)editpart).deselect();
309 		}
310 		
311 		getSelectedEditParts().clear();
312 				
313 		fireSelectionChanged();
314 	}
315 	
316 	/***
317 	 * This tells to DOMSelectionChangeListeners(probably only TextEditor), about new
318 	 * selection. Local selection of this GraphiclViewer becomes a globalSelction
319 	 *
320 	 * Call this method when selction ends - mouse up, Shift key up, etc.
321 	 */
322 	public void commitSelection(){
323 		fireSelectionChanged();
324 	}
325 	
326 	public List getSelectedEditParts(){
327 		return super.getSelectedEditParts();
328 	}
329 	
330 
331     private IDManager getIDManager(){
332         return ((XMLEditDomain)getEditDomain()).getXMLEditor().getXMLAccess().getIdManager();
333     }
334 
335     /***
336      * @return global selection
337      */
338 	public DOMIntervalSet getDOMSelection() {
339 		return this.editor.getDOMSelection();
340 	}
341 
342 }