KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > xam > ui > column > BasicColumnView


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.xam.ui.column;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Container JavaDoc;
25 import java.awt.Dimension JavaDoc;
26 import java.awt.EventQueue JavaDoc;
27 import java.awt.Point JavaDoc;
28 import java.awt.Rectangle JavaDoc;
29 import java.awt.event.ComponentAdapter JavaDoc;
30 import java.awt.event.ComponentEvent JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.ListIterator JavaDoc;
34 import javax.swing.JComponent JavaDoc;
35 import javax.swing.JPanel JavaDoc;
36 import javax.swing.JViewport JavaDoc;
37 import javax.swing.Scrollable JavaDoc;
38 import org.netbeans.modules.xml.xam.ui.layout.JSplitterBar;
39 import org.netbeans.modules.xml.xam.ui.layout.SplitterLayout;
40
41 /**
42  * A Swing widget with a horizontal splitter layout. The split bars can
43  * be moved right and left.
44  *
45  * @author Jeri Lockhart
46  * @author Nathan Fiedler
47  */

48 public class BasicColumnView extends JPanel JavaDoc implements ColumnView {
49     private static final String JavaDoc COLUMN_WEIGHT_1 = "1"; // NOI18N
50
private static final int SCROLL_DELAY = 20;
51     static final long serialVersionUID = 1L;
52     /** columns in order from left to right */
53     private List JavaDoc<Column> columnList;
54     /** JSplitterBars in order from left to right */
55     private List JavaDoc<JSplitterBar> splitterList;
56     /** Contains all of the columns and splitters. */
57     private JPanel JavaDoc mainParentPanel;
58
59     /**
60      * Creates new form BasicColumnView.
61      */

62     public BasicColumnView() {
63         initComponents();
64         columnList = new ArrayList JavaDoc<Column>();
65         splitterList = new ArrayList JavaDoc<JSplitterBar>();
66
67         mainParentPanel = new MainPanel();
68         mainParentPanel.setBackground(Color.WHITE);
69         mainParentPanel.setLayout(new SplitterLayout(false));
70         scrollPane.setViewportView(mainParentPanel);
71         scrollPane.setViewportBorder(null);
72         scrollPane.getViewport().setBackground(Color.WHITE);
73
74         addComponentListener(new ComponentAdapter JavaDoc(){
75             public void componentResized(ComponentEvent JavaDoc e) {
76                 super.componentResized(e);
77                 validate();
78                 revalidate();
79             }
80
81         });
82     }
83
84     /**
85      * Appends the column to the list, without revalidating or scrolling.
86      *
87      * @param column the Column to add.
88      */

89     protected void appendColumnToList(Column column) {
90         if (column == null) {
91             return;
92         }
93         JComponent JavaDoc comp = column.getComponent();
94         if (comp == null) {
95             return;
96         }
97         columnList.add(column);
98         mainParentPanel.add(COLUMN_WEIGHT_1, comp);
99         JSplitterBar bar = new JSplitterBar();
100         mainParentPanel.add(bar);
101         splitterList.add(bar);
102     }
103
104     public void appendColumn(Column column) {
105         appendColumnToList(column);
106         // Call validate() which calls SplitterLayout layoutContainer()
107
// layoutContainer() will set a new preferredSize on the
108
// mainParentPanel that will be used by the scroll pane.
109
validate();
110         mainParentPanel.revalidate();
111         scrollToColumn(column, false);
112     }
113
114     public void appendColumns(Column[] columns) {
115         for (Column column : columns) {
116             appendColumnToList(column);
117         }
118         validate();
119         mainParentPanel.revalidate();
120         scrollToColumn(columns[columns.length - 1], false);
121     }
122
123     public void clearColumns(){
124         mainParentPanel.removeAll();
125         columnList.clear();
126         splitterList.clear();
127         mainParentPanel.revalidate();
128         mainParentPanel.repaint();
129     }
130
131     public void removeColumnsAfter(Column column) {
132         if (column == null) {
133             return;
134         }
135
136         if (!isLastColumn(column)) {
137             // We have to scroll the view (synchronously) before removing
138
// the column, because as soon as we remove it, the table resizes
139
// and revalidates (shrinks).
140
scrollToColumn(getNextColumn(column), true);
141         }
142
143         // Remove the columns and splitters from the lists and the panel.
144
int loc = columnList.indexOf(column);
145         for (int ii = columnList.size() - 1; ii > loc; ii--) {
146             Column col = columnList.remove(ii);
147             Component JavaDoc comp = col.getComponent();
148             mainParentPanel.remove(comp);
149         }
150         for (int ii = splitterList.size() - 1; ii > loc; ii--) {
151             JSplitterBar bar = splitterList.remove(ii);
152             mainParentPanel.remove(bar);
153         }
154         mainParentPanel.revalidate();
155         mainParentPanel.repaint();
156     }
157
158     public void scrollToColumn(final Column column, boolean synchronous) {
159         if (column == null) {
160             return;
161         }
162         if (synchronous) {
163             if (!EventQueue.isDispatchThread()) {
164                 try {
165                     // Invoke ourselves immediately on the event thread
166
EventQueue.invokeAndWait(new Runnable JavaDoc() {
167                         public void run() {
168                             scrollToColumn(column);
169                         }
170                     });
171                 } catch (Exception JavaDoc e) {
172                     return;
173                 }
174             } else {
175                 // This is the event thread. Invoke the actual scrolling code.
176
scrollToColumn(column);
177             }
178         } else {
179             // Return now and let the invokeLater() do the scrolling
180
EventQueue.invokeLater(new Runnable JavaDoc() {
181                 public void run() {
182                     // Invoke ourselves later
183
scrollToColumn(column);
184                 }
185             });
186         }
187     }
188
189     /**
190      * Scrolls the viewport to make the specified column the last column
191      * visible. This method must be invoked on the AWT/Swing thread.
192      *
193      * @throws IllegalStateException
194      * if this method is invoked on a non-AWT thread.
195      */

196     protected void scrollToColumn(Column column) {
197         if (!EventQueue.isDispatchThread()) {
198             throw new IllegalStateException JavaDoc("This method can only be " +
199                     "invoked on the AWT event processing thread");
200         }
201
202         // If this column isn't in the table, return immediately.
203
// Likewise, don't scroll if there is only one column.
204
int columnIndex = columnList.indexOf(column);
205         if (columnIndex == -1 || columnList.size() <= 1) {
206             return;
207         }
208
209         // This is the bounds of the column: the x,y is the coordinate
210
// of the left side of the column relative to the left side of
211
// the viewport, and width, height is the size of the column.
212
Rectangle JavaDoc viewBounds = column.getComponent().getBounds();
213         viewBounds.width += 5;
214
215         // This is the bounds of the viewport
216
JViewport JavaDoc viewport = scrollPane.getViewport();
217         Rectangle JavaDoc viewportBounds = viewport.getViewRect();
218
219         // Calculate the distance we need to move the viewport
220
final int DELTA = (int) ((viewportBounds.getX() +
221                 viewportBounds.getWidth()) - (viewBounds.getX() +
222                 viewBounds.getWidth()));
223         if (DELTA == 0) {
224             return;
225         }
226
227         // Calculate the number of columns we need to move so we can have
228
// a basically constant per-column scroll rate.
229
// Get the number of columns between the specified column and the
230
// last showing column. We check a point relative (-10,10) to the
231
// upper-rightmost point of the viewport so that we don't
232
// accidentally hit any non-column JTable pixels.
233
int deltaColumns = Math.abs(lastShowingColumnIndex() - columnIndex);
234
235         Point JavaDoc position = viewport.getViewPosition();
236
237         final int STEPS = 5 * (deltaColumns == 0 ? 1 : deltaColumns);
238         final int INCREMENT = DELTA / STEPS;
239
240         for (int step = 0; step < STEPS; step++) {
241             int newX = (int) position.getX() - INCREMENT;
242             if (newX <= 0) {
243                 break;
244             }
245             // Add a fudge factor of 1 pixel to insulate against roundoff
246
// errors that cause the view not to scroll fully to the right
247
newX += 1;
248
249             try {
250                 // Pause briefly to perform the synchronous animation.
251
// Using a Timer simply will not work, as this method
252
// must return only after the animation is complete.
253
Thread.currentThread().sleep(SCROLL_DELAY);
254             } catch (InterruptedException JavaDoc ie) {
255                 // Do nothing
256
}
257
258             position = new Point JavaDoc(newX, (int) position.getY());
259             viewport.setViewPosition(position);
260         }
261     }
262
263     /**
264      * Indicates if the given Column is the last one in the view.
265      *
266      * @return true if last column, false otherwise.
267      */

268     protected boolean isLastColumn(Column column){
269         if (column == null){
270             return false;
271         }
272         return columnList.indexOf(column) == columnList.size()-1;
273
274     }
275
276     public int getColumnCount() {
277         return columnList.size();
278     }
279
280     public Column getFirstColumn() {
281         if (columnList.size() > 0) {
282             return columnList.get(0);
283         } else {
284             return null;
285         }
286     }
287
288     public Column getNextColumn(Column column){
289         if (column == null) {
290             return null;
291         }
292         if (isLastColumn(column)) {
293             return null;
294         }
295         return columnList.get(columnList.indexOf(column) + 1);
296     }
297
298     @Override JavaDoc
299     public void requestFocus() {
300         super.requestFocus();
301         int index = lastShowingColumnIndex();
302         if (index > -1) {
303             Column column = columnList.get(index);
304             column.getComponent().requestFocus();
305         }
306     }
307
308     @Override JavaDoc
309     public boolean requestFocusInWindow() {
310         boolean retVal = super.requestFocusInWindow();
311         int index = lastShowingColumnIndex();
312         if (index > -1) {
313             Column column = columnList.get(index);
314             return column.getComponent().requestFocusInWindow();
315         }
316         return retVal;
317     }
318
319     /**
320      * Determine the index of the right-most visible column.
321      *
322      * @return index of last visible column (-1 if no columns).
323      */

324     private int lastShowingColumnIndex() {
325         int index = -1;
326         for (int ii = columnList.size() - 1; ii > -1; ii--){
327             if (columnList.get(ii).getComponent().isShowing()) {
328                 index = ii;
329                 break;
330             }
331         }
332         return index;
333     }
334
335     /**
336      * Convert a point in view coordinates to the closest index of the
337      * column at that location.
338      *
339      * @param location the coordinates of the column, relative to the
340      * scrollpane viewport.
341      * @param direction less than zero for left, greater than zero for right.
342      * @return the index of the column at the given location, or -1.
343      */

344     private int locationToIndex(Point JavaDoc location, int direction) {
345         int index = -1;
346         Component JavaDoc comp = mainParentPanel.getComponentAt(location);
347         if (comp instanceof JSplitterBar) {
348             // The columns and splitters have a 1:1 relationship, so the
349
// index into the splitter list is equal to the index into
350
// the column list for the splitter's paired column.
351
index = splitterList.indexOf(comp);
352             if (direction > 0) {
353                 // Moving to the right, favor the column to the right
354
// of the splitter.
355
index++;
356             }
357         } else {
358             Component JavaDoc[] comps = mainParentPanel.getComponents();
359             // Components consist of column/splitter pairs.
360
for (int ii = 0; ii < comps.length; ii += 2) {
361                 if (comps[ii] == comp) {
362                     index = ii / 2;
363                     break;
364                 }
365             }
366         }
367         return index;
368     }
369
370     public int getColumnIndex(Column column) {
371         return columnList.indexOf(column);
372     }
373
374     public void addNotify() {
375         super.addNotify();
376         Container JavaDoc parent = getParent();
377         assert !(parent instanceof JViewport JavaDoc) :
378             "BasicColumnView has its own scrollpane. " +
379                 "Do not place BasicColumnView in a scrollpane.";
380     }
381
382     /**
383      * Panel that manages the scrolling behavior of the column view.
384      */

385     private class MainPanel extends JPanel JavaDoc implements Scrollable JavaDoc {
386         /** silence compiler warnings */
387         private static final long serialVersionUID = 1L;
388
389         public Dimension JavaDoc getPreferredScrollableViewportSize() {
390             return getPreferredSize();
391         }
392
393         public int getScrollableBlockIncrement(Rectangle JavaDoc visibleRect,
394                 int orientation, int direction) {
395             // If all else fails, default to the view width.
396
int inc = visibleRect.width;
397             if (direction > 0) {
398                 // Scroll to the right.
399
int last = locationToIndex(new Point JavaDoc(visibleRect.x +
400                         visibleRect.width - 1, visibleRect.y), direction);
401                 if (last >= 0 && last < columnList.size()) {
402                     Column col = columnList.get(last);
403                     Rectangle JavaDoc lastRect = col.getComponent().getBounds();
404                     if (lastRect != null) {
405                         inc = lastRect.x - visibleRect.x;
406                         if (inc < 0) {
407                             inc += lastRect.width;
408                         } else if (inc == 0 && last < columnList.size() - 1) {
409                             inc = lastRect.width;
410                         }
411                     }
412                 }
413             } else {
414                 // Scroll to the left.
415
int first = locationToIndex(new Point JavaDoc(visibleRect.x -
416                         visibleRect.width, visibleRect.y), direction);
417                 if (first >= 0 && first < columnList.size()) {
418                     Column col = columnList.get(first);
419                     Rectangle JavaDoc firstRect = col.getComponent().getBounds();
420                     if (firstRect != null) {
421                         if (firstRect.x < visibleRect.x - visibleRect.width) {
422                             if (firstRect.x + firstRect.width >= visibleRect.x) {
423                                 inc = visibleRect.x - firstRect.x;
424                             } else {
425                                 inc = visibleRect.x - firstRect.x - firstRect.width;
426                             }
427                         } else {
428                             inc = visibleRect.x - firstRect.x;
429                         }
430                     }
431                 }
432             }
433             return inc;
434         }
435
436         public boolean getScrollableTracksViewportHeight() {
437             return true;
438         }
439
440         public boolean getScrollableTracksViewportWidth() {
441             if (getParent() instanceof JViewport JavaDoc) {
442                 return (getParent().getWidth() > getPreferredSize().width);
443             }
444             return false;
445         }
446
447         public int getScrollableUnitIncrement(Rectangle JavaDoc visibleRect,
448                 int orientation, int direction) {
449         int index = locationToIndex(visibleRect.getLocation(), direction);
450             if (index >= 0 && index < columnList.size()) {
451                 Column col = columnList.get(index);
452                 Rectangle JavaDoc bounds = col.getComponent().getBounds();
453                 if (bounds != null) {
454                     if (bounds.x != visibleRect.x) {
455                         if (direction < 0) {
456                             return Math.abs(bounds.x - visibleRect.x);
457                         }
458                         return bounds.width + bounds.x - visibleRect.x;
459                     }
460                     // Need to compensate for the width of the splitter.
461
// They are all same width, so first one is sufficient.
462
JSplitterBar bar = splitterList.get(0);
463                     return bounds.width + bar.getWidth();
464                 }
465             }
466             // If all else fails, return the default value.
467
return 1;
468         }
469     }
470
471     /** This method is called from within the constructor to
472      * initialize the form.
473      * WARNING: Do NOT modify this code. The content of this method is
474      * always regenerated by the Form Editor.
475      */

476     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
477
private void initComponents() {
478         scrollPane = new javax.swing.JScrollPane JavaDoc();
479
480         setLayout(new java.awt.BorderLayout JavaDoc());
481
482         setBackground(java.awt.Color.white);
483         scrollPane.setBackground(java.awt.Color.white);
484         scrollPane.setBorder(null);
485         scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
486         add(scrollPane, java.awt.BorderLayout.CENTER);
487
488     }// </editor-fold>//GEN-END:initComponents
489

490     // Variables declaration - do not modify//GEN-BEGIN:variables
491
private javax.swing.JScrollPane JavaDoc scrollPane;
492     // End of variables declaration//GEN-END:variables
493
}
494
Popular Tags