1// BEGIN LICENSE BLOCK
2// Version: CMPL 1.1
3//
4// The contents of this file are subject to the Cisco-style Mozilla Public
5// License Version 1.1 (the "License"); you may not use this file except
6// in compliance with the License.  You may obtain a copy of the License
7// at www.eclipse-clp.org/license.
8//
9// Software distributed under the License is distributed on an "AS IS"
10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11// the License for the specific language governing rights and limitations
12// under the License.
13//
14// The Original Code is  The ECLiPSe Constraint Logic Programming System.
15// The Initial Developer of the Original Code is  Cisco Systems, Inc.
16// Portions created by the Initial Developer are
17// Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18//
19// Contributor(s):
20//
21// END LICENSE BLOCK
22
23package com.parctechnologies.eclipse.visualisation;
24
25import com.parctechnologies.eclipse.*;
26import java.util.*;
27import javax.swing.*;
28import java.awt.event.*;
29import java.awt.Component;
30
31/**
32 * A ContainerViewer is a Viewer which contains zero or more "Viewlets" per
33 * viewable element. A Viewlet is an object, representing the data stored in a ViewletStore, which contains information about the viewable element. The ContainerViewer class does not commit itself to how many
34 * viewlets per element there are, what kind they are or how to store/access the
35 * viewlets. These decisions are left to subclasses. <p>
36 *
37 * The way this is done is that the protected abstract methods
38 * getViewletsAtIndex(List index) and getAllViewlets() must be implemented by
39 * the subclass, and should return the relevant Collection of Viewlets.<p>
40 *
41 * However, ContainerViewer <em>is</em> responsible for mediating between
42 * the event ViewerManager and the viewlets it contains. These responsibilities
43 * are as follows:<p>
44 * <ul>
45 * <li>For CreateEvents and ExpandEvents, the subclass of ContainerViewer may
46 * have created new viewlets during the invocation of the prepareForEvent
47 * method. In the collectPreEventGoals method, it is the responsibility of
48 * ContainerViewer to marshall these new
49 * viewlets and collect from each a goal using its
50 * collectPreBuildGoal method. All such goals are collected together in a batch
51 * goal and returned.
52 * <li>Similarly, for UpdateEvents, during the collectPreEventGoals,
53 * ContainerViewer must marshall all the
54 * Viewlets whose viewable elements are updating and collect a goal from each
55 * using its collectPreUpdateGoal method. These goals are batched together in a
56 * BatchGoal which is then returned.
57 * <li>Following on from the above, during startEvent, the ContainerViewer is
58 * responsible for distributing the results of the collected goals to the
59 * viewlets who generated the goals, using their startBuild methods in the case
60 * of CreateEvents and ExpandEvents and their startUpdate methods in the case of
61 * UpdateEvents.
62 * <li>The ContainerViewlet's implementation of stopEvent should invoke
63 * the stopBuild methods of all newly created viewlets at the end of a
64 * CreateEvent or an ExpandEvent and it should invoke the stopUpdate methods at
65 * the end of an UpdateEvent.
66 * <li>Between the execution of startEvent and the execution of stopEvent,
67 * ContainerViewer is also responsible for providing protected access to
68 * Collections of the indices of created/expanded/updating viewable elements,
69 * and to Collections of created/expanded/updating viewlets.
70 * <li>Each ContainerViewer also has a subset of its viewlets which are
71 * currently "selected" in the sense that the next user action will apply to
72 * them. The ContainerViewer is responsible for managing this collection. At
73 * present this means having a protected selection member, initialising
74 * the selection and remembering the selection during periods when the viewer
75 * loses focus. However, I intend to move actions such as "select all" and
76 * "select updating" up into this class along with other selection-related
77 * functionality where possible.
78 * </ul>
79 * ContainerViewer is also responsible for keeping track of the Location names.
80 */
81
82public abstract class ContainerViewer extends ViewerImpl
83{
84  private ViewletRange createdElementIndices;
85  private ViewletRange updatingElementIndices;
86  private ViewletRange expandingElementIndices;
87  //private Collection createdViewlets;
88  //private Collection updatingViewlets;
89  //private Collection expandingViewlets;
90  private List size;
91  private boolean trackUpdates = false;
92
93  protected ViewletType viewletType;
94
95    protected ViewletDataStore viewletDataStore;
96
97  /**
98   * Action to select all updating viewlets
99   */
100  private SelectUpdatingAction selectUpdatingAction;
101
102  /**
103   * The menu entry specifying whether to track updates or not
104   */
105  protected JCheckBoxMenuItem trackUpdatesMenuItem;
106
107  private static final Atom vcSupportAtom = new Atom("vc_support");
108    //protected Collection selectionCopy = new LinkedList();
109    //protected ViewletRange selection = new ViewletRangeCollection();
110
111  /**
112   * Array of Lists of Strings. Each element in the array relates to a
113   * dimension. Each List is a list of strings: location names for the
114   * corresponding dimension. <p>
115   * locationNames[0] is a List of location names for dimension 1 in the
116   * viewable,
117   * locationNames[1] is for dimension 2 etc.
118   */
119  private List[] locationNames;
120
121
122  /**
123   * Returns the mnemonic to use for a given menuTitle
124   */
125  protected int getMenuMnemonic(String menuTitle) {
126    if ("Select".equals(menuTitle)) return KeyEvent.VK_S;
127    if ("View".equals(menuTitle)) return KeyEvent.VK_V;
128    return super.getMenuMnemonic(menuTitle);
129  }
130
131  public ContainerViewer(VisClientStateModel stateModel,
132                         Viewable viewable,
133			 ViewletType viewletType)
134  {
135    super(stateModel, viewable);
136    this.viewletType = viewletType;
137    viewletType.setSymRef(new SymRef(viewletType,
138                                     this.getSymRef(),
139                                     viewletType.getClass().getName()));
140    trackUpdatesMenuItem = new JCheckBoxMenuItem("Track updates");
141    trackUpdatesMenuItem.
142      setModel(new BooleanPropertyModel("trackUpdates",
143					this, getPropertyChangeSupport()));
144    addMenuItem("Options", trackUpdatesMenuItem);
145
146    addMenuAndPopupMenuItem("Select", new SelectAllAction());
147    selectUpdatingAction = new SelectUpdatingAction();
148    addMenuAndPopupMenuItem("Select", selectUpdatingAction);
149    addMenuAndPopupMenuItem("Select", new ClearSelectionAction());
150    addMenuAndPopupMenuItem("View", getZoomInAction(this, 0.5f));
151    addMenuAndPopupMenuItem("View", getZoomInAction(this, 2.0f));
152    addMenuAndPopupMenuItem("View", null);
153    addMenuAndPopupMenuItem("View", getZoomAction(this, 4.0f));
154    addMenuAndPopupMenuItem("View", getZoomAction(this, 2.0f));
155    addMenuAndPopupMenuItem("View", getZoomAction(this, 1.5f));
156    addMenuAndPopupMenuItem("View", getZoomNormalAction(this));
157    addMenuAndPopupMenuItem("View", getZoomAction(this, 0.75f));
158    addMenuAndPopupMenuItem("View", getZoomAction(this, 0.5f));
159    addMenuAndPopupMenuItem("View", getZoomAction(this, 0.25f));
160    addMenuAndPopupMenuItem("View", getZoomToFitWidthAction());
161    addMenuAndPopupMenuItem("View", getZoomToFitHeightAction());
162  }
163
164    public ViewletDataStore getViewletDataStore() {
165	return viewletDataStore;
166    }
167
168  protected abstract Action getZoomToFitWidthAction();
169
170  protected abstract Action getZoomToFitHeightAction();
171
172  protected List getSize()
173  {
174    return(size);
175  }
176
177  public boolean getTrackUpdates()
178  {
179    return(trackUpdates);
180  }
181
182
183  public void setTrackUpdates(boolean newValue)
184  {
185    (new ViewerSetBooleanPropertyCommand(this, "trackUpdates", newValue)).issue();
186  }
187
188  public void setTrackUpdatesPrivate(boolean newValue)
189  {
190    boolean oldValue = trackUpdates;
191    trackUpdates = newValue;
192    this.getPropertyChangeSupport().
193      firePropertyChange("trackUpdates", oldValue, newValue);
194  }
195
196
197  public BatchGoal collectPreEventGoals(VisEvent event)
198  {
199    BatchGoal result = new BatchGoal();
200
201    if(event instanceof UpdateEvent)
202    {
203      result.add(super.collectPreEventGoals(event));
204      setUpdatingElementIndices((UpdateEvent) event);
205      result.add(collectPreUpdateGoals(updatingElementIndices,
206                                          ((UpdateEvent) event)));
207      return(result);
208    }
209
210    if(event instanceof ExpandEvent)
211    {
212      result.add(super.collectPreEventGoals(event));
213      ExpandEvent expandEvent = (ExpandEvent) event;
214      int expandingDimension = expandEvent.getExpandingDimension();
215      Integer newLocation =
216          (Integer) expandEvent.getViewableSize().get(expandingDimension - 1);
217      // add a goal to get the name of the new location in the expanded dimension
218      result.add(getAddLocationNameGoal(expandingDimension,
219                                        newLocation.intValue()));
220      setExpandingElementIndices(expandEvent);
221      result.add(collectPreBuildGoals(expandingElementIndices));
222      return(result);
223    }
224
225    if(event instanceof CreateEvent)
226    {
227      result.add(super.collectPreEventGoals(event));
228      CreateEvent createEvent = (CreateEvent) event;
229      // add a location names goal for each dimension.
230      for(int i = 1 ; i <= createEvent.getViewableSize().size() ; i++)
231      {
232        result.add(getLocationNamesGoal(i));
233      }
234      setCreatedElementIndices(createEvent);
235      DebuggingSupport.logMessage(this,"collectPreEventGoal fooee");
236      result.add(collectPreBuildGoals(createdElementIndices));
237      return(result);
238    }
239    return(super.collectPreEventGoals(event));
240  }
241
242  public void clearSelection()
243  {
244    setSelection(new ViewletRangeCollection());
245  }
246
247  public void setSelection(ViewletRange newSelection)
248  {
249      (new ViewerSetSelectionCommand(this, newSelection)).issue();
250  }
251
252//    public void addAllToSelection(Collection newViewlets)
253//    {
254//  //      HashSet newSelection = new HashSet(selection);
255//  //      newSelection.addAll(newViewlets);
256//  //      setSelection(newViewlets);
257//    }
258
259//    public void removeAllFromSelection(Collection viewletsToRemove)
260//    {
261//  //      HashSet newSelection = new HashSet(selection);
262//  //      newSelection.removeAll(viewletsToRemove);
263//  //      setSelection(newSelection);
264//    }
265
266//  //    public void addToSelection(Viewlet viewlet)
267//  //    {
268//  //  //      LinkedList single = new LinkedList();
269//  //  //      single.add(viewlet);
270//  //  //      addAllToSelection(single);
271//  //    }
272
273//  //    public void removeFromSelection(Viewlet viewlet)
274//  //    {
275//  //  //      LinkedList single = new LinkedList();
276//  //  //      single.add(viewlet);
277//  //  //      removeAllFromSelection(single);
278//  //    }
279
280    protected void setSelectionPrivate(ViewletRange newSelection) {
281        // default to doing nothing
282        // must be overidden by subclasses
283
284        //      Collection viewletsToAdd = new LinkedList();
285        //      Collection viewletsToRemove = new LinkedList();
286        //      Iterator i1 = selection.iterator();
287        //      Viewlet current;
288        //      while(i1.hasNext())
289        //      {
290        //        current = (Viewlet) i1.next();
291        //        if(!newSelection.contains(current))
292        //        {
293        //          viewletsToRemove.add(current);
294        //        }
295        //      }
296        //      Iterator i2 = newSelection.iterator();
297        //      while(i2.hasNext())
298        //      {
299        //        current = (Viewlet) i2.next();
300        //        if(!selection.contains(current))
301        //        {
302        //          viewletsToAdd.add(current);
303        //        }
304        //      }
305        //      addAllToSelectionPrivate(viewletsToAdd);
306        //      removeAllFromSelectionPrivate(viewletsToRemove);
307    }
308
309//    private void addAllToSelectionPrivate(Collection all)
310//    {
311//  //      Iterator i = all.iterator();
312//  //      while(i.hasNext())
313//  //      {
314//  //        addToSelectionPrivate((Viewlet) i.next());
315//  //      }
316//    }
317
318//    private void removeAllFromSelectionPrivate(Collection all)
319//    {
320//      Iterator i = all.iterator();
321//      while(i.hasNext())
322//      {
323//        removeFromSelectionPrivate((Viewlet) i.next());
324//      }
325//    }
326
327//    private void addToSelectionPrivate(Viewlet viewlet)
328//    {
329//  //      selection.add(viewlet);
330//  //      viewlet.setSelected(true);
331//    }
332
333//    private void removeFromSelectionPrivate(Viewlet viewlet)
334//    {
335//  //      selection.remove(viewlet);
336//  //      viewlet.setSelected(false);
337//    }
338
339    public ViewletRange getSelection()
340    {
341        //return selection;
342      return null;
343    }
344
345  private Collection collectPreBuildGoals(ViewletRange indexList)
346  {
347      //List goals =  new LinkedList();
348      //goals.add(viewletType.collectPreBuildGoal(this,new ViewletRangeCollection(indexList)));
349      List goals = viewletType.collectPreBuildGoal(this,
350                                                   viewletDataStore,
351                                                   indexList);
352      DebuggingSupport.logMessage(this,"PreBuildGoals="+goals);
353      return goals;
354  }
355
356
357  private Collection collectPreUpdateGoals(ViewletRange indexList, UpdateEvent event)
358  {
359      //List goals =  new LinkedList();
360      //goals.add(viewletType.collectPreUpdateGoal(this,new ViewletRangeCollection(indexList), event));
361      List goals = viewletType.collectPreUpdateGoal(this,
362                                                    viewletDataStore,
363                                                    indexList,
364                                                    event);
365      DebuggingSupport.logMessage(this,"PreUpdateGoals="+goals);
366      return goals;
367//      BatchGoal result = new BatchGoal();
368//      Iterator indexListIterator = indexList.iterator();
369//      List currentIndex;
370//      Collection viewlets;
371
372//      while(indexListIterator.hasNext())
373//      {
374//        currentIndex = (List) indexListIterator.next();
375//        viewlets = getViewletDataAt(currentIndex);
376//        result.add(composeElementUpdateGoal(viewlets, currentIndex, event));
377//      }
378//      return(result);
379  }
380
381//    private BatchGoal composeElementBuildGoal(Collection viewlets, List index)
382//    {
383//      BatchGoal result = new BatchGoal();
384//      Object elementReference = new CompoundTermImpl("element", index);
385//      Iterator viewletsIterator = viewlets.iterator();
386//      ViewletData currentViewlet;
387//      CompoundTerm viewletGoal;
388//      Object viewableName = getViewable().getNameAtom();
389
390//      while(viewletsIterator.hasNext())
391//      {
392//        currentViewlet = (ViewletData) viewletsIterator.next();
393//        //viewletGoal = currentViewlet.collectPreBuildGoal();
394//        //result.add(composeElementGoal(elementReference,
395//        //                              viewletGoal));
396//      }
397//      return(result);
398//    }
399
400//    private BatchGoal composeElementUpdateGoal(Collection viewlets, List index, UpdateEvent event)
401//    {
402//      BatchGoal result = new BatchGoal();
403//      Object elementReference = new CompoundTermImpl("element", index);
404//      Iterator viewletsIterator = viewlets.iterator();
405//      ViewletData currentViewlet;
406//      CompoundTerm viewletGoal;
407
408//      while(viewletsIterator.hasNext())
409//      {
410//        currentViewlet = (ViewletData) viewletsIterator.next();
411//        //      viewletGoal = currentViewlet.collectPreUpdateGoal(event);
412//        //      result.add(composeElementGoal(elementReference,
413//        //                                    viewletGoal));
414//      }
415//      return(result);
416//    }
417
418//    protected CompoundTerm composeElementGoal(Object elementReference,
419//  					    CompoundTerm viewletGoal)
420//    {
421//      return(new CompoundTermImpl(":", vcSupportAtom,
422//                    new CompoundTermImpl("viewable_element_execute",
423//                      getViewable().getNameAtom(), elementReference, viewletGoal)));
424//    }
425
426  private void setCreatedElementIndices(CreateEvent event)
427  {
428    List size = event.getViewableSize();
429    // create an index representing the first element in the viewable
430    List start = new ArrayList(size.size());
431    Integer one = new Integer(1);
432    for(int i = 0; i < size.size(); i++) {
433        start.add(one);
434    }
435    //    createdElementIndices = allCombinations(size);
436    createdElementIndices = viewletDataStore.createRange(start,size);
437    if (DebuggingSupport.logMessages) {
438        DebuggingSupport.logMessage(this,
439                                    "setCreatedElementIndices event="+event+
440                                    " start=" + start + " size=" +size +
441                                    "createdElementIndices=" +
442                                    createdElementIndices);
443    }
444  }
445
446  private void setExpandingElementIndices(ExpandEvent event)
447  {
448    int expandingDimension = event.getExpandingDimension();
449    List size = event.getViewableSize();
450    Integer newDimensionSize
451      = (Integer) size.get(expandingDimension-1);//list indices start at 0
452
453    // create an index representing the first element in the newly
454    // expanded dimension
455    List start = new ArrayList(size.size());
456    Integer one = new Integer(1);
457    for(int i = 0; i < size.size(); i++) {
458        start.add(one);
459    }
460    start.set(expandingDimension-1, newDimensionSize);
461    expandingElementIndices = viewletDataStore.createRange(start, size);
462  }
463
464  private void setUpdatingElementIndices(UpdateEvent event)
465  {
466    updatingElementIndices =
467        viewletDataStore.createRange(event.getElementsUpdating());
468    if (DebuggingSupport.logMessages) {
469      DebuggingSupport.logMessage(this, "setUpdatingElementIndices "+
470                                  "event="+event+
471                                  "event.getElementsUpdating()="+event.getElementsUpdating()+
472                                  "updatingElementIndices="+updatingElementIndices);
473    }
474  }
475
476
477  protected ViewletRange getCreatedElementIndices()
478  {
479    return createdElementIndices;
480  }
481
482  protected ViewletRange getUpdatingElementIndices()
483  {
484    return updatingElementIndices;
485  }
486
487  protected ViewletRange getExpandingElementIndices()
488  {
489    return expandingElementIndices;
490  }
491
492  public void gainFocus()
493  {
494    super.gainFocus();
495    //    this.setSelection(selectionCopy);
496    getComponent().repaint();
497
498    if (DebuggingSupport.logMessages) {
499	DebuggingSupport.logMessage(this, "focus gained");
500    }
501
502  }
503
504  public void loseFocus()
505  {
506    super.loseFocus();
507//      try {
508//  	selectionCopy = (ViewletSelection)(getSelection().clone());
509//      } catch(CloneNotSupportedException e) {
510//        if (DebuggingSupport.logMessages) {
511//  	DebuggingSupport.logMessage(this, "clone not supported");
512//  	e.printStackTrace(System.err);
513//        }
514//        //selectionCopy = new LinkedList(getSelection());
515//      }
516    clearSelection();
517
518    getComponent().repaint();
519
520    if (DebuggingSupport.logMessages) {
521	DebuggingSupport.logMessage(this, "focus lost");
522    }
523
524  }
525
526    //protected abstract ViewletTracker getViewletTracker();
527
528  private void scrollToTrackUpdate(Collection updatingViewlets)
529  {
530//      ViewletTracker viewletTracker = getViewletTracker();
531//      viewletTracker.setViewlets(getUpdatingViewlets());
532//      try {
533//        SwingUtilities.invokeAndWait(viewletTracker);
534//      } catch(Exception e) { throw new RuntimeException("Exception "+e+" thrown "+
535//            "while executing viewletTracker");}
536  }
537
538  public void startEvent(VisEvent event, java.util.List goalResults)
539  {
540    if(event instanceof UpdateEvent)
541    {
542      super.startEvent(event, (List) goalResults.get(0));
543      distributeUpdateResults((List) goalResults.get(1), updatingElementIndices,
544                                ((UpdateEvent) event));
545      // When starting an update event, enable the selectUpdating action
546      // and track the update if this is switched on.
547      selectUpdatingAction.setEnabled(true);
548//        if(trackUpdates)
549//        {
550//          scrollToTrackUpdate(getUpdatingViewlets());
551//        }
552
553      return;
554    }
555    else
556    {
557      // can't select updating viewlets unless update event is in progress
558      // this line is possibly unnecessary (why would the action be enabled?).
559      selectUpdatingAction.setEnabled(false);
560    }
561
562
563    if(event instanceof ExpandEvent)
564    {
565      size = ((ExpandEvent) event).getViewableSize();
566      super.startEvent(event, (List) goalResults.get(0));
567      String newLocationName =
568        locationNameFromGoalResult((CompoundTermImpl) goalResults.get(1));
569      int dimNumber = ((ExpandEvent) event).getExpandingDimension();
570      locationNames[dimNumber - 1].add(newLocationName);
571
572      if (DebuggingSupport.logMessages) {
573	  DebuggingSupport.logMessage(this, "Added location name "+
574                                      newLocationName+
575                                      " to dimension "+dimNumber);
576      }
577
578      distributeBuildResults((List) goalResults.get(2), expandingElementIndices);
579      return;
580    }
581
582
583    if(event instanceof ContractEvent)
584    {
585      size = ((ContractEvent) event).getViewableSize();
586      shrinkLocationNamesTo(size);
587    }
588
589    if(event instanceof CreateEvent)
590    {
591      size = ((CreateEvent) event).getViewableSize();
592      super.startEvent(event, (List) goalResults.get(0));
593      // extract the results of the "getDimension Location names" goals
594      int nDims = size.size();
595      locationNames = new List[nDims];
596      List locationNamesList;
597      int i;
598      for(i = 1 ; i <= nDims ; i++)
599      {
600        locationNamesList =
601          locationNamesFromGoalResult((CompoundTermImpl) goalResults.get(i));
602        locationNames[i-1] = locationNamesList;
603      }
604      // distribute the "preBuild" goal results
605      distributeBuildResults((List) goalResults.get(i), createdElementIndices);
606      return;
607    }
608    super.startEvent(event, goalResults);
609  }
610
611  public Collection getCreatedViewlets()
612  {
613//      if(createdViewlets == null)
614//      {
615//        createdViewlets = getViewletsAtIndexList(getCreatedElementIndices());
616//      }
617//      return(createdViewlets);
618      return null;
619  }
620
621  public Collection getUpdatingViewlets()
622  {
623//      if(updatingViewlets == null)
624//      {
625//        updatingViewlets = getViewletsAtIndexList(getUpdatingElementIndices());
626//      }
627//      return(updatingViewlets);
628      return null;
629  }
630
631  public Collection getExpandingViewlets()
632  {
633//      if(expandingViewlets == null)
634//      {
635//        expandingViewlets = getViewletsAtIndexList(getExpandingElementIndices());
636//      }
637//      return(expandingViewlets);
638      return null;
639  }
640
641  private Collection getViewletDataAtIndexList(Collection indexList)
642  {
643    Iterator indexListIterator = indexList.iterator();
644    List currentIndex;
645    Collection viewlets;
646    Collection result = new LinkedList();
647    while(indexListIterator.hasNext())
648    {
649      currentIndex = (List) indexListIterator.next();
650      viewlets = getViewletDataAt(currentIndex);
651      result.addAll(viewlets);
652    }
653    return(result);
654  }
655
656  public boolean shouldHold()
657  {
658    if(super.shouldHold())
659    {
660      return(true);
661    }
662    if(getCurrentEvent() instanceof UpdateEvent)
663    {
664	//      Collection updatingViewlets = getUpdatingViewlets();
665      Iterator updatingViewletsIterator =
666	  viewletDataStore.getViewletDataIterator(new ViewletRangeCollection(updatingElementIndices));
667      ViewletData currentViewlet;
668      while(updatingViewletsIterator.hasNext())
669      {
670        currentViewlet = (ViewletData) updatingViewletsIterator.next();
671        if(currentViewlet.getHoldsOnUpdates())
672        {
673          return(true);
674        }
675      }
676    }
677    return(false);
678  }
679
680  private void distributeBuildResults(List results, ViewletRange indexList)
681  {
682      viewletType.startBuild(this, viewletDataStore, indexList, results);
683      /*
684    Iterator indexListIterator = indexList.iterator();
685    Iterator resultsIterator = results.iterator();
686    List elementResult;
687    Collection viewlets;
688    List currentIndex;
689    while(indexListIterator.hasNext())
690    {
691      currentIndex = (List) indexListIterator.next();
692      viewlets = getViewletDataAt(currentIndex);
693      elementResult = (List) resultsIterator.next();
694      distributeBuildResult(elementResult, viewlets);
695    }
696      */
697  }
698
699//    private void distributeBuildResult(List elementResults, ViewletRange viewlets)
700//    {
701//      Iterator elementResultsIterator = elementResults.iterator();
702//      Iterator viewletsIterator = viewlets.iterator();
703//      ViewletData currentViewlet;
704//      CompoundTermImpl currentResult;
705//      Object next;
706//      while(elementResultsIterator.hasNext())
707//      {
708//        currentViewlet = (ViewletData) viewletsIterator.next();
709//        next = elementResultsIterator.next();
710//        //
711//        if (DebuggingSupport.logMessages) {
712//  	  DebuggingSupport.logMessage(this, "currentViewlet:"+currentViewlet);
713//  	  DebuggingSupport.logMessage(this, "next:"+next);
714//        }
715
716//        //currentResult = (CompoundTermImpl) next;
717//        //currentViewlet.startBuild((CompoundTerm) (currentResult.argCT(2).arg(3)));
718//      }
719//    }
720
721  private void distributeUpdateResults(List results,
722                                       ViewletRange indexList,
723                                       UpdateEvent event)
724  {
725      viewletType.startUpdate(this,
726                              viewletDataStore,
727                              indexList,
728                              results,
729                              event);
730      /*
731    Iterator indexListIterator = indexList.iterator();
732    Iterator resultsIterator = results.iterator();
733    List elementResult;
734    Collection viewlets;
735    List currentIndex;
736    while(indexListIterator.hasNext())
737    {
738      currentIndex = (List) indexListIterator.next();
739      viewlets = getViewletDataAt(currentIndex);
740      elementResult = (List) resultsIterator.next();
741      distributeUpdateResult(elementResult, viewlets, event);
742    }
743      */
744  }
745
746//    private void distributeUpdateResult(List elementResults, Collection viewlets,
747//                                        UpdateEvent event)
748//    {
749//      Iterator elementResultsIterator = elementResults.iterator();
750//      Iterator viewletsIterator = viewlets.iterator();
751//      ViewletData currentViewlet;
752//      CompoundTermImpl currentResult;
753//      while(elementResultsIterator.hasNext())
754//      {
755//        currentViewlet = (ViewletData) viewletsIterator.next();
756//        currentResult = (CompoundTermImpl) elementResultsIterator.next();
757//        //currentViewlet.startUpdate(event, (CompoundTerm) currentResult.argCT(2).arg(3));
758//      }
759//    }
760
761  public void stopEvent()
762  {
763    if(getCurrentEvent() instanceof CreateEvent)
764    {
765      stopBuild(createdElementIndices);
766    }
767
768    if(getCurrentEvent() instanceof ExpandEvent)
769    {
770      stopBuild(expandingElementIndices);
771    }
772
773    if(getCurrentEvent() instanceof UpdateEvent)
774    {
775      stopUpdate(updatingElementIndices);
776      selectUpdatingAction.setEnabled(false);
777    }
778
779    createdElementIndices = null;
780    updatingElementIndices = null;
781    expandingElementIndices = null;
782    //createdViewlets = null;
783    //updatingViewlets = null;
784    //expandingViewlets = null;
785    super.stopEvent();
786  }
787
788  private void stopBuild(ViewletRange indexList)
789  {
790    Iterator indexListIterator = indexList.iterator();
791    List currentIndex;
792    Iterator viewletIterator;
793    ViewletData currentViewlet;
794
795    while(indexListIterator.hasNext())
796    {
797      currentIndex = (List) indexListIterator.next();
798      viewletIterator = getViewletDataAt(currentIndex).iterator();
799      while(viewletIterator.hasNext())
800      {
801        currentViewlet = (ViewletData) viewletIterator.next();
802        //currentViewlet.stopBuild();
803      }
804    }
805  }
806
807  private void stopUpdate(ViewletRange indexList)
808  {
809      viewletType.stopUpdate(this, viewletDataStore, indexList);
810//      Iterator indexListIterator = indexList.iterator();
811//      List currentIndex;
812//      Iterator viewletIterator;
813//      ViewletData currentViewlet;
814
815//      while(indexListIterator.hasNext())
816//      {
817//        currentIndex = (List) indexListIterator.next();
818//        viewletIterator = getViewletDataAt(currentIndex).iterator();
819//        while(viewletIterator.hasNext())
820//        {
821//          currentViewlet = (ViewletData) viewletIterator.next();
822//          //currentViewlet.stopUpdate();
823//        }
824//      }
825  }
826
827  protected abstract Collection getViewletDataAt(List index);
828  protected abstract ViewletRange getAllViewletData();
829
830
831  /**
832   * dimNumber starts from 1.
833   */
834  protected List getLocationNames(int dimNumber)
835  {
836    return(locationNames[dimNumber - 1]);
837  }
838
839  /**
840   * dimNumber & locNumber start from 1.
841   */
842  protected String getLocationName(int dimNumber, int locNumber)
843  {
844    return((String) getLocationNames(dimNumber).get(locNumber - 1));
845  }
846
847  private void shrinkLocationNamesTo(List newSize)
848  {
849    for(int i = 0; i < locationNames.length; i++)
850    {
851      int newDimSize = ((Integer) newSize.get(i)).intValue();
852      List newLocationNames = locationNames[i].subList(0, newDimSize);
853      locationNames[i] = newLocationNames;
854
855      if (DebuggingSupport.logMessages) {
856	  DebuggingSupport.logMessage(this, "location names of dimension "+(i+1)+
857				      " shrunk to "+newLocationNames);
858      }
859
860    }
861  }
862
863
864  private CompoundTerm getLocationNamesGoal(int dimNumber)
865  {
866    CompoundTerm locationNamesGoal =
867        new CompoundTermImpl(":", vcSupportAtom,
868          new CompoundTermImpl("viewable_get_location_names",
869                                 getViewable().getNameAtom(),
870                                 new Integer(dimNumber), null));
871    return(locationNamesGoal);
872  }
873
874  private CompoundTerm getAddLocationNameGoal(int dimNumber, int newLocation)
875  {
876    CompoundTerm addLocationNameGoal =
877        new CompoundTermImpl(":", vcSupportAtom,
878          new CompoundTermImpl("viewable_get_location_name",
879                                 getViewable().getNameAtom(),
880                                 new Integer(dimNumber),
881                                 new Integer(newLocation),
882                                 null));
883    return(addLocationNameGoal);
884  }
885
886  private List locationNamesFromGoalResult(CompoundTermImpl result)
887  {
888    return((List) result.argCT(2).arg(3));
889  }
890
891  private String locationNameFromGoalResult(CompoundTermImpl result)
892  {
893    return((String) result.argCT(2).arg(4));
894  }
895
896  private abstract class ViewletSelectionAction extends AbstractAction
897  {
898    protected abstract ViewletRange newSelection();
899
900    ViewletSelectionAction(String text)
901    {
902      super(text);
903    }
904    public void actionPerformed(ActionEvent event)
905    {
906      clearSelection();
907      //addAllToSelection(newSelection());
908      setSelection(newSelection());
909      getComponent().repaint();
910    }
911  }
912
913  private class SelectAllAction extends ViewletSelectionAction
914  {
915    SelectAllAction()
916    {
917      super("Select all viewlets");
918    }
919    protected ViewletRange newSelection()
920    {
921      return(viewletDataStore.getEntireViewletRange());
922    }
923  }
924
925  private class SelectUpdatingAction extends ViewletSelectionAction
926  {
927    SelectUpdatingAction()
928    {
929      super("Select updating viewlet(s)");
930      setEnabled(false);
931    }
932    protected ViewletRange newSelection()
933    {
934      return getUpdatingElementIndices();
935    }
936  }
937
938  private class ClearSelectionAction extends ViewletSelectionAction
939  {
940    ClearSelectionAction()
941    {
942      super("Clear selection");
943    }
944    protected ViewletRange newSelection()
945    {
946      return new ViewletRangeCollection();
947    }
948  }
949
950  protected Action getZoomInAction(Viewer viewer, float ratio)
951  {
952    return(new ZoomInAction(viewer, ratio));
953  }
954
955  protected Action getZoomAction(Viewer viewer, float zoomRatio)
956  {
957    return(new ZoomAction(viewer, zoomRatio));
958  }
959
960  protected Action getZoomNormalAction(Viewer viewer)
961  {
962    return(new ZoomNormalAction(viewer));
963  }
964
965  private class ZoomAction extends AbstractAction
966  {
967    private float zoomRatio;
968    private Viewer viewer;
969
970    ZoomAction(Viewer viewer, float zoomRatio)
971    {
972      super("Zoom to "+((int)(zoomRatio*100))+"%");
973      this.zoomRatio = zoomRatio;
974      this.viewer = viewer;
975    }
976    public void actionPerformed(ActionEvent event)
977    {
978      (new ViewerZoomCommand(viewer, zoomRatio)).issue();
979    }
980  }
981
982  private class ZoomInAction extends AbstractAction
983  {
984    private float zoomRatio;
985    private Viewer viewer;
986
987    ZoomInAction(Viewer viewer, float zoomRatio)
988    {
989      super("Zoom "+((zoomRatio<1)?"out":"in")+" by "+
990            ((int)(((zoomRatio<1)?(1/zoomRatio):zoomRatio)*100))+"%");
991      this.zoomRatio = zoomRatio;
992      this.viewer = viewer;
993    }
994    public void actionPerformed(ActionEvent event)
995    {
996      (new ViewerZoomInCommand(viewer, zoomRatio)).issue();
997    }
998  }
999
1000  private class ZoomNormalAction extends ZoomAction
1001  {
1002    ZoomNormalAction(Viewer viewer)
1003    {
1004      super(viewer, 1.0f);
1005      this.putValue(Action.NAME, "Zoom to normal size");
1006    }
1007  }
1008
1009  /** Returns any actions/menu items that should be available via a
1010      right-click popup menu */
1011  public Collection getViewerPopupMenuCollection() {
1012    Collection result = new LinkedList();
1013    result.add(getPopupMenu("Select"));
1014    result.add(getPopupMenu("View"));
1015    return result;
1016  }
1017
1018
1019  /** Access the context sensitive popup menu */
1020  public JPopupMenu getPopupMenu() {
1021    JPopupMenu menu = super.getPopupMenu();
1022    // Add action specific to the current selection
1023    ViewletRange range = getSelection();
1024    if (range != null) {
1025      for(Iterator it = viewletType.getActions(viewletDataStore, range).iterator();
1026          it.hasNext();) {
1027        menu.add((Action)(it.next()));
1028      }
1029    }
1030    // Add actions specific to this viewer
1031    menu.addSeparator();
1032    for(Iterator it = getViewerPopupMenuCollection().iterator();
1033        it.hasNext();) {
1034      Object item = it.next();
1035      if (item instanceof Action) {
1036        menu.add((Action)(item));
1037      } else if (item instanceof JMenuItem) {
1038        menu.add((JMenuItem)(item));
1039      } else if (item instanceof Component) {
1040        menu.add((Component)(item));
1041      } else if (item instanceof String) {
1042        menu.add((String)(item));
1043      } else if (item instanceof JMenu) {
1044        menu.add((JMenu)item);
1045      }
1046    }
1047    return menu;
1048  }
1049}
1050