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
25
26import java.util.*;
27import java.awt.*;
28import java.beans.*;
29import java.awt.event.*;
30import javax.swing.*;
31import javax.swing.table.*;
32import com.parctechnologies.eclipse.*;
33import com.parctechnologies.eclipse.visualisation.*;
34
35
36/**
37 * A text table viewer based on JTable
38 */
39public class TableViewer
40    extends ViewletArrayViewer
41    implements ZoomableViewer
42{
43  protected static int DEFAULT_ROW_HEIGHT = 70;
44  protected static int DEFAULT_COLUMN_WIDTH = 100;
45
46  private SpreadSheet table;
47  private JScrollPane scrollpane;
48    //private ScrollingViewletGrid scrollingViewletGrid;
49  private boolean trackExpansions = false;
50    //  private ViewletTracker viewletTracker;
51
52
53    public TableViewer(//ViewletFactory viewletFactory,
54		ViewletType viewletType,
55		VisClientStateModel stateModel,
56		Viewable viewable)
57  {
58    super(viewletType, stateModel, viewable);
59    initialiseMenu();
60  }
61
62  private void initialiseMenu()
63  {
64    //JCheckBoxMenuItem trackExpansionsItem = new JCheckBoxMenuItem("Track expansions");
65    //trackExpansionsItem.setModel(new BooleanPropertyModel("trackExpansions",
66    //                          this, getPropertyChangeSupport()));
67    //addMenuItem("Options", trackExpansionsItem);
68  }
69
70  protected Action getZoomToFitWidthAction()
71  {
72    return(new ZoomToFitWidthAction(this));
73  }
74
75  protected Action getZoomToFitHeightAction()
76  {
77    return(new ZoomToFitHeightAction(this));
78  }
79
80  public void startEvent(VisEvent event, java.util.List goalResults)
81  {
82    if(event instanceof UpdateEvent)
83    {
84      super.startEvent(event, goalResults);
85      return;
86    }
87
88    // for create event, initialise the component
89    if(event instanceof CreateEvent)
90    {
91      super.startEvent(event, goalResults);
92
93      initialiseComponent();
94      return;
95    }
96
97    if(event instanceof ExpandEvent)
98    {
99      super.startEvent(event, goalResults);
100
101      // if the "track expansions" option is on, scroll to the expanded bit of
102      // the grid.
103      //if(trackExpansions)
104      //  scrollToTrackExpansion((ExpandEvent) event);
105      return;
106    }
107
108    super.startEvent(event, goalResults);
109  }
110
111  private void initialiseComponent()
112  {
113    // disable the "trackUpdates" feature
114    trackUpdatesMenuItem.setEnabled(false);
115    //table = new JTable(getViewletArray());
116    table = new SpreadSheet(getViewletDataStore(), null, null);
117    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
118    table.setAutoCreateColumnsFromModel(false);
119    table.setColumnSelectionAllowed(true);
120    table.setRowSelectionAllowed(true);
121    table.setCellSelectionEnabled(true);
122    // set the default cell renderer
123    table.setDefaultRenderer((new Object()).getClass(),
124			     viewletType.getTableCellRenderer());
125    scrollpane = new JScrollPane(table);
126    scrollpane.setPreferredSize(new Dimension(430, 200));
127    //scrollingViewletGrid =
128    //  new ScrollingViewletGrid(getViewletArray(), this);
129    //viewletTracker = new ViewletTracker(scrollingViewletGrid);
130    MouseViewletMenuUpPopper mouseViewletMenuUpPopper =
131        new MouseViewletMenuUpPopper(this, table);
132    // create the selection for this table
133    //selection = new ViewletSelectionSpreadSheet((SpreadSheet)table, this);
134    // set the row height to equal the column width
135    table.setColumnWidth(DEFAULT_COLUMN_WIDTH);
136    table.setRowHeight(DEFAULT_ROW_HEIGHT);
137  }
138
139
140  public Component getComponent()
141  {
142    return scrollpane;
143  }
144
145  public void setTrackExpansions(boolean newValue)
146  {
147    //(new ViewerSetBooleanPropertyCommand(this, "trackExpansions", newValue)).issue();
148  }
149
150  public void setTrackExpansionsPrivate(boolean newValue)
151  {
152    //boolean oldValue = trackExpansions;
153    //trackExpansions = newValue;
154    //this.getPropertyChangeSupport().
155    //  firePropertyChange("trackExpansions", oldValue, newValue);
156  }
157
158  public boolean getTrackExpansions()
159  {
160    return false;
161    //return(trackExpansions);
162  }
163
164
165  public void zoomToLevel(float zoomLevel)
166  {
167    // scale the column widths and row heights
168    table.setColumnWidth((int)(DEFAULT_COLUMN_WIDTH*zoomLevel));
169    table.setRowHeight((int)(DEFAULT_ROW_HEIGHT*zoomLevel));
170    table.revalidate();
171  }
172
173  public void zoomInByRatio(float zoomRatio)
174  {
175    // scale the column widths and row heights
176    final int col_count = table.getColumnCount();
177    final TableColumnModel col_model = table.getColumnModel();
178    for(int i = 0; i < col_count; i++) {
179      int w = col_model.getColumn(i).getPreferredWidth();
180      col_model.getColumn(i).setPreferredWidth((int)(w*zoomRatio));
181    }
182    table.setRowHeight((int)(table.getRowHeight()*zoomRatio));
183    table.revalidate();
184  }
185
186  // move the scrollbars so that the new row/column comes into view.
187  private void scrollToTrackExpansion(ExpandEvent event)
188  {
189    //scrollingViewletGrid.scrollToTrackExpansion(event.getExpandingDimension());
190  }
191
192//    protected ViewletTracker getViewletTracker()
193//    {
194//      return(viewletTracker);
195//    }
196
197
198  private class ZoomToFitWidthAction extends AbstractAction
199  {
200    private TableViewer viewer;
201    ZoomToFitWidthAction(TableViewer viewer)
202    {
203      super("Zoom to fit width");
204      this.viewer = viewer;
205    }
206
207    public void actionPerformed(ActionEvent event)
208    {
209      (new ZoomableViewerZoomToFitWidthCommand(viewer)).issue();
210    }
211  }
212
213  public void zoomToFitWidth()
214  {
215    table.fitWidth();
216    table.revalidate();
217  }
218
219  private class ZoomToFitHeightAction extends AbstractAction
220  {
221    private TableViewer viewer;
222    ZoomToFitHeightAction(TableViewer viewer)
223    {
224      super("Zoom to fit height");
225      this.viewer = viewer;
226    }
227
228    public void actionPerformed(ActionEvent event)
229    {
230      (new ZoomableViewerZoomToFitHeightCommand(viewer)).issue();
231    }
232  }
233
234  public void zoomToFitHeight()
235  {
236    table.fitHeight();
237    table.revalidate();
238  }
239
240    //  public void setSelection(ViewletRange newSelection) {
241      //(new ViewerSetSelectionCommand(this, newSelection)).issue();
242    //  }
243
244  Rectangle rangeToBounds(ViewletRange range) {
245    if (((ViewableType.ArrayType)getViewable().getType()).getNDimensions() == 1) {
246      int min=Integer.MAX_VALUE;
247      int max=-1;
248      for(Iterator it = range.iterator(); it.hasNext(); ) {
249        java.util.List index = (java.util.List)it.next();
250        int i = ((Integer)index.get(0)).intValue();
251        if (i < min) {
252          min = i;
253        }
254        if (i > max) {
255          max = i;
256        }
257      }
258      return new Rectangle(0,min-1,1,(max-min)+1);
259    }
260    int minCol=Integer.MAX_VALUE;
261    int maxCol=-1;
262    int minRow=Integer.MAX_VALUE;
263    int maxRow=-1;
264    for(Iterator it = range.iterator(); it.hasNext(); ) {
265      java.util.List index = (java.util.List)it.next();
266      int row = ((Integer)index.get(0)).intValue();
267      int col = ((Integer)index.get(1)).intValue();
268      if (col < minCol) {
269        minCol = col;
270      }
271      if (col > maxCol) {
272        maxCol = col;
273      }
274      if (row < minRow) {
275        minRow = row;
276      }
277      if (row > maxRow) {
278        maxRow = row;
279      }
280    }
281    return new Rectangle(minCol-1,minRow-1,(maxCol-minCol)+1,(maxRow-minRow)+1);
282  }
283
284  /**
285   * Called by the ViewerSetSelectionCommand
286   */
287  protected void setSelectionPrivate(ViewletRange newSelection) {
288    DebuggingSupport.
289	logMessage(this,
290		   "setSelectionPrivate called with newSelection=" +
291		   newSelection);
292    if (newSelection.isEmpty()) {
293      table.clearSelection();
294      return;
295    }
296    // Find the bounding box for these viewlets and select everything
297    // within that box
298    //    Rectangle box = table.findBoundingBox(newSelection);
299    Rectangle box = rangeToBounds(newSelection);
300    table.setColumnSelectionInterval(box.x, box.x + box.width - 1);
301    table.setRowSelectionInterval(box.y, box.y + box.height - 1);
302  }
303
304
305  /**
306   * Returns a copy of the current selection
307   */
308  public ViewletRange getSelection() {
309    return new SpreadSheetSelectionViewletRange(table);
310  }
311
312
313  /**
314   * Return a collection of actions which can be applied to viewlets
315   * in this table
316   */
317  public Collection getCompoundActions(ViewletRange selected) {
318    return viewletType.getActions(viewletDataStore,selected);
319    //    Collection ll = new LinkedList();
320    //    ll.add((new ToggleHoldAction()).createCompoundAction(selected));
321    //    return ll;
322  }
323
324//    private class ToggleHoldAction extends ViewletAction
325//      {
326//        ToggleHoldAction()
327//        {
328//          super("Hold on updates");
329//          putValue(Action.NAME, "Hold on updates");
330//          putValue(Action.LONG_DESCRIPTION,
331//                   "Change whether control is held by the visualisation client during element updates");
332//          putValue(Action.SHORT_DESCRIPTION,
333//                   "Change whether control is held on updates");
334//          putValue(Action.SMALL_ICON, new HoldIcon(20, 20));
335
336//        }
337
338//        public void actionPerformed(ActionEvent e)
339//        {
340//  	// do nothing
341//        }
342
343//        /**
344//         * If all viewlets in the collection have hold set to true, then the
345//         * compound version sets it to false. If any of them have it set to false
346//         * then the compound version sets all to true.
347//         */
348//        public ViewletAction createCompoundAction(Collection viewlets)
349//        {
350//          boolean allHold = true;
351//          ViewletImpl currentViewlet;
352//          Iterator viewletsIterator = viewlets.iterator();
353//          while(viewletsIterator.hasNext())
354//          {
355//            currentViewlet = (ViewletImpl) viewletsIterator.next();
356//            if(!currentViewlet.getHoldsOnUpdates())
357//            {
358//              allHold = false;
359//              break;
360//            }
361//          }
362//          return(new CompoundToggleHoldAction(!allHold, viewlets));
363//        }
364//      }
365
366//      private class CompoundToggleHoldAction extends ToggleHoldAction
367//      {
368//        private boolean newValue;
369//        private Collection viewlets;
370//        CompoundToggleHoldAction(boolean newValue, Collection viewlets)
371//        {
372//          super();
373//          this.newValue = newValue;
374//          this.viewlets = viewlets;
375//        }
376
377//        public void actionPerformed(ActionEvent e)
378//        {
379//          ViewletImpl currentViewlet;
380//          Iterator viewletsIterator = viewlets.iterator();
381//          while(viewletsIterator.hasNext())
382//          {
383//            currentViewlet = (ViewletImpl) viewletsIterator.next();
384//            currentViewlet.setHoldsOnUpdates(newValue);
385//          }
386//  	// trigger the jtable to update as a whole bunch of viewlets have just
387//  	// changed
388//  	((AbstractTableModel)table.getModel()).fireTableDataChanged();
389//        }
390
391//      }
392
393  /**
394   * The default text cell render
395   */
396//    private class MyRenderer extends DefaultTableCellRenderer {
397//      public MyRenderer() {
398//        super();
399//        setHorizontalAlignment(SwingConstants.CENTER);
400//      }
401
402//      public Component getTableCellRendererComponent(JTable table,
403//  						   Object value,
404//  						   boolean isSelected,
405//  						   boolean hasFocus,
406//  						   int row,
407//  						   int column) {
408//        JLabel result =
409//  	(JLabel)(super.getTableCellRendererComponent(table,
410//  						     value,
411//  						     isSelected,
412//  						     hasFocus,
413//  						     row,
414//  						     column));
415//        ViewletImpl viewlet = (ViewletImpl)value;
416//        String updating = viewlet.getUpdating();
417//        Color col = Color.white;
418//        if ("no".equals(updating)) {
419//  	// do nothing
420//        } else if ("updatingForward".equals(updating)) {
421//  	col = Color.green;
422//        } else /* updatingBack */ {
423//  	col = Color.red;
424//        }
425//        if (viewlet.getHoldsOnUpdates()) {
426//  	col = col.darker();
427//        }
428//        if (isSelected) {
429//  	col = col.darker().darker();
430//        }
431//        result.setBackground(col);
432//        return result;
433//      }
434
435
436//      public void setValue(Object value) {
437//        super.setValue(value);
438//        ViewletImpl viewlet = (ViewletImpl)value;
439//        setToolTipText(viewlet.getToolTipText());
440//      }
441//    }
442
443
444}
445