001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Anton Avtamonov
019: * @version $Revision$
020: */package javax.swing.plaf.basic;
021:
022: import java.awt.Component;
023: import java.awt.Cursor;
024: import java.awt.Dimension;
025: import java.awt.Graphics;
026: import java.awt.Point;
027: import java.awt.Rectangle;
028: import java.awt.event.MouseEvent;
029:
030: import javax.swing.CellRendererPane;
031: import javax.swing.JComponent;
032: import javax.swing.LookAndFeel;
033: import javax.swing.event.MouseInputListener;
034: import javax.swing.plaf.ComponentUI;
035: import javax.swing.plaf.TableHeaderUI;
036: import javax.swing.table.JTableHeader;
037: import javax.swing.table.TableCellRenderer;
038: import javax.swing.table.TableColumn;
039: import javax.swing.table.TableColumnModel;
040:
041: import org.apache.harmony.x.swing.Utilities;
042:
043: public class BasicTableHeaderUI extends TableHeaderUI {
044: public class MouseInputHandler implements MouseInputListener {
045: private final Cursor HEADER_RESIZING_CURSOR = new Cursor(
046: Cursor.E_RESIZE_CURSOR);
047:
048: private Cursor originalHeaderCursor;
049: private int initialMousePosition;
050: private int initialColumnWidth;
051:
052: public void mouseClicked(final MouseEvent e) {
053: }
054:
055: public void mousePressed(final MouseEvent e) {
056: initialMousePosition = e.getX();
057: TableColumn processedColumn = getResizingColumn(e);
058: if (processedColumn != null) {
059: header.setResizingColumn(processedColumn);
060: initialColumnWidth = processedColumn.getWidth();
061: return;
062: }
063: processedColumn = getReorderingColumn(e);
064: if (processedColumn != null) {
065: header.setDraggedColumn(processedColumn);
066: dragColumn(e);
067: }
068: }
069:
070: public void mouseReleased(final MouseEvent e) {
071: if (header.getResizingColumn() != null) {
072: header.setResizingColumn(null);
073: header.setCursor(originalHeaderCursor);
074: } else if (header.getDraggedColumn() != null) {
075: header.setDraggedDistance(0);
076: int draggingColumnIndex = getColumnIndex(header
077: .getDraggedColumn());
078: header.getColumnModel().moveColumn(draggingColumnIndex,
079: draggingColumnIndex);
080: header.setDraggedColumn(null);
081: }
082: }
083:
084: public void mouseMoved(final MouseEvent e) {
085: updateCursor(e);
086: }
087:
088: public void mouseDragged(final MouseEvent e) {
089: if (header.getResizingColumn() != null) {
090: int increment;
091: if (header.getTable().getComponentOrientation()
092: .isLeftToRight()) {
093: increment = e.getX() - initialMousePosition;
094: } else {
095: increment = initialMousePosition - e.getX();
096: }
097: header.setCursor(HEADER_RESIZING_CURSOR);
098: header.getResizingColumn().setWidth(
099: initialColumnWidth + increment);
100: } else if (header.getDraggedColumn() != null) {
101: dragColumn(e);
102: }
103: }
104:
105: public void mouseEntered(final MouseEvent e) {
106: if (header != null) {
107: updateCursor(e);
108: }
109: }
110:
111: public void mouseExited(final MouseEvent e) {
112: if (header != null) {
113: header.setCursor(originalHeaderCursor);
114: }
115: }
116:
117: private void dragColumn(final MouseEvent e) {
118: int increment = e.getX() - initialMousePosition;
119: int draggingColumnIndex = getColumnIndex(header
120: .getDraggedColumn());
121: Rectangle draggingColumnRect = header
122: .getHeaderRect(draggingColumnIndex);
123: if (increment > 0) {
124: int draggingFront = draggingColumnRect.x
125: + draggingColumnRect.width + increment;
126: int swappingColumnIndex = header
127: .columnAtPoint(new Point(draggingFront, 0));
128: if (swappingColumnIndex == -1) {
129: swappingColumnIndex = header.getColumnModel()
130: .getColumnCount() - 1;
131: }
132: Rectangle swappingColumnRect = header
133: .getHeaderRect(swappingColumnIndex);
134: int swappingColumnCenter = swappingColumnRect.x
135: + swappingColumnRect.width / 2;
136: if (draggingColumnIndex != swappingColumnIndex
137: && draggingFront >= swappingColumnCenter) {
138: int distance = increment - swappingColumnRect.width;
139: header.setDraggedDistance(distance);
140: initialMousePosition = e.getX() - distance;
141: header.getColumnModel().moveColumn(
142: draggingColumnIndex, swappingColumnIndex);
143: } else {
144: header.setDraggedDistance(increment);
145: header.getColumnModel().moveColumn(
146: draggingColumnIndex, draggingColumnIndex);
147: }
148: } else {
149: int draggingFront = draggingColumnRect.x + increment;
150: int swappingColumnIndex = header
151: .columnAtPoint(new Point(draggingFront, 0));
152: if (swappingColumnIndex == -1) {
153: swappingColumnIndex = 0;
154: }
155: Rectangle swappingColumnRect = header
156: .getHeaderRect(swappingColumnIndex);
157: int swappingColumnCenter = swappingColumnRect.x
158: + swappingColumnRect.width / 2;
159: if (draggingColumnIndex != swappingColumnIndex
160: && draggingFront <= swappingColumnCenter) {
161: int distance = swappingColumnRect.width + increment;
162: header.setDraggedDistance(distance);
163: initialMousePosition = e.getX() - distance;
164: header.getColumnModel().moveColumn(
165: draggingColumnIndex, swappingColumnIndex);
166: } else {
167: header.setDraggedDistance(increment);
168: header.getColumnModel().moveColumn(
169: draggingColumnIndex, draggingColumnIndex);
170: }
171: }
172: }
173:
174: private TableColumn getResizingColumn(final MouseEvent e) {
175: if (!header.getResizingAllowed()) {
176: return null;
177: }
178:
179: int column = header.columnAtPoint(e.getPoint());
180: if (column == -1) {
181: return null;
182: }
183:
184: Rectangle columnBounds = header.getHeaderRect(column);
185: if (header.getTable().getComponentOrientation()
186: .isLeftToRight()) {
187: if (column == 0
188: && columnBounds.x + MOUSE_TOLERANCE > e.getX()) {
189: return null;
190: }
191:
192: if (columnBounds.x + MOUSE_TOLERANCE > e.getX()) {
193: TableColumn result = header.getColumnModel()
194: .getColumn(column - 1);
195: return result.getResizable() ? result : null;
196: }
197: if (columnBounds.x + columnBounds.width
198: - MOUSE_TOLERANCE < e.getX()) {
199: TableColumn result = header.getColumnModel()
200: .getColumn(column);
201: return result.getResizable() ? result : null;
202: }
203: } else {
204: if (column == 0
205: && columnBounds.x + columnBounds.width
206: - MOUSE_TOLERANCE < e.getX()) {
207: return null;
208: }
209:
210: if (columnBounds.x + columnBounds.width
211: - MOUSE_TOLERANCE < e.getX()) {
212: TableColumn result = header.getColumnModel()
213: .getColumn(column - 1);
214: return result.getResizable() ? result : null;
215: }
216: if (columnBounds.x + MOUSE_TOLERANCE > e.getX()) {
217: TableColumn result = header.getColumnModel()
218: .getColumn(column);
219: return result.getResizable() ? result : null;
220: }
221: }
222:
223: return null;
224: }
225:
226: private TableColumn getReorderingColumn(final MouseEvent e) {
227: if (!header.getReorderingAllowed()) {
228: return null;
229: }
230:
231: int column = header.columnAtPoint(e.getPoint());
232: if (column == -1) {
233: return null;
234: }
235:
236: return header.getColumnModel().getColumn(column);
237: }
238:
239: private void updateCursor(final MouseEvent e) {
240: if (e == null || e.getButton() > 0
241: || e.getModifiersEx() > 0) {
242: return;
243: }
244:
245: if (header.getCursor() != HEADER_RESIZING_CURSOR) {
246: originalHeaderCursor = header.getCursor();
247: }
248: header
249: .setCursor(getResizingColumn(e) != null
250: && header.getDraggedColumn() == null ? HEADER_RESIZING_CURSOR
251: : originalHeaderCursor);
252: }
253: }
254:
255: protected JTableHeader header;
256: protected CellRendererPane rendererPane;
257: protected MouseInputListener mouseInputListener;
258:
259: private static final int MOUSE_TOLERANCE = 3;
260:
261: private static final SizeInfo MINIMUM_WIDTH_INFO = new SizeInfo() {
262: public int getWidth(final TableColumn column) {
263: return column.getMinWidth();
264: }
265:
266: public int getHeight(final TableColumn column,
267: final JTableHeader header, final int columnIndex) {
268: Component renderingComponent = getRenderingComponent(
269: column, header, columnIndex);
270: return renderingComponent != null ? renderingComponent
271: .getMinimumSize().height : 0;
272: }
273: };
274: private static final SizeInfo MAXIMUM_WIDTH_INFO = new SizeInfo() {
275: public int getWidth(final TableColumn column) {
276: return column.getMaxWidth();
277: }
278:
279: public int getHeight(final TableColumn column,
280: final JTableHeader header, final int columnIndex) {
281: Component renderingComponent = getRenderingComponent(
282: column, header, columnIndex);
283: return renderingComponent != null ? renderingComponent
284: .getMaximumSize().height : 0;
285: }
286: };
287: private static final SizeInfo PREFERRED_WIDTH_INFO = new SizeInfo() {
288: public int getWidth(final TableColumn column) {
289: return column.getPreferredWidth();
290: }
291:
292: public int getHeight(final TableColumn column,
293: final JTableHeader header, final int columnIndex) {
294: Component renderingComponent = getRenderingComponent(
295: column, header, columnIndex);
296: return renderingComponent != null ? renderingComponent
297: .getPreferredSize().height : 0;
298: }
299: };
300:
301: public static ComponentUI createUI(final JComponent c) {
302: return new BasicTableHeaderUI();
303: }
304:
305: public void installUI(final JComponent c) {
306: header = (JTableHeader) c;
307: rendererPane = new CellRendererPane();
308: rendererPane.setVisible(false);
309: header.add(rendererPane);
310:
311: installDefaults();
312: installListeners();
313: installKeyboardActions();
314: }
315:
316: public void uninstallUI(final JComponent c) {
317: uninstallKeyboardActions();
318: uninstallListeners();
319: uninstallDefaults();
320:
321: rendererPane = null;
322: header = null;
323: }
324:
325: public void paint(final Graphics g, final JComponent c) {
326: Rectangle clipRect = g.getClipBounds();
327: for (int i = 0; i < header.getColumnModel().getColumnCount(); i++) {
328: TableColumn column = header.getColumnModel().getColumn(i);
329: Rectangle columnRect = header.getHeaderRect(i);
330: if (header.getDraggedColumn() != column) {
331: paintColumn(g, column, clipRect, columnRect, i);
332: }
333: }
334:
335: if (header.getDraggedColumn() != null) {
336: int draggedIndex = getColumnIndex(header.getDraggedColumn());
337: Rectangle columnRect = header.getHeaderRect(draggedIndex);
338: paintBackgroundUnderDraggedCell(g, columnRect);
339: columnRect.translate(header.getDraggedDistance(), 0);
340: paintColumn(g, header.getDraggedColumn(), clipRect,
341: columnRect, draggedIndex);
342: }
343: }
344:
345: public Dimension getMinimumSize(final JComponent c) {
346: return getColumnSize(MINIMUM_WIDTH_INFO);
347: }
348:
349: public Dimension getMaximumSize(final JComponent c) {
350: return getColumnSize(MAXIMUM_WIDTH_INFO);
351: }
352:
353: public Dimension getPreferredSize(final JComponent c) {
354: return getColumnSize(PREFERRED_WIDTH_INFO);
355: }
356:
357: protected void installDefaults() {
358: LookAndFeel.installColorsAndFont(header,
359: "TableHeader.background", "TableHeader.foreground",
360: "TableHeader.font");
361:
362: LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
363: }
364:
365: protected void uninstallDefaults() {
366: if (header != null) {
367: Utilities.uninstallColorsAndFont(header);
368: }
369: }
370:
371: protected void installListeners() {
372: mouseInputListener = createMouseInputListener();
373: if (mouseInputListener != null) {
374: header.addMouseListener(mouseInputListener);
375: header.addMouseMotionListener(mouseInputListener);
376: }
377: }
378:
379: protected void uninstallListeners() {
380: header.removeMouseListener(mouseInputListener);
381: header.removeMouseMotionListener(mouseInputListener);
382: mouseInputListener = null;
383: }
384:
385: protected void installKeyboardActions() {
386: }
387:
388: protected void uninstallKeyboardActions() {
389: }
390:
391: protected MouseInputListener createMouseInputListener() {
392: return new MouseInputHandler();
393: }
394:
395: private void paintColumn(final Graphics g,
396: final TableColumn column, final Rectangle clipRect,
397: final Rectangle columnRect, final int columnIndex) {
398: if (clipRect != null && !clipRect.intersects(columnRect)) {
399: return;
400: }
401:
402: TableCellRenderer renderer = column.getHeaderRenderer() != null ? column
403: .getHeaderRenderer()
404: : header.getDefaultRenderer();
405:
406: Component renderingComponent = renderer
407: .getTableCellRendererComponent(header.getTable(),
408: column.getHeaderValue(), false, false, -1,
409: columnIndex);
410: rendererPane.paintComponent(g, renderingComponent, header,
411: columnRect);
412: }
413:
414: private void paintBackgroundUnderDraggedCell(final Graphics g,
415: final Rectangle columnRect) {
416: g.setColor(header.getParent().getBackground());
417: g.fillRect(columnRect.x, columnRect.y, columnRect.width,
418: columnRect.height);
419: }
420:
421: private Dimension getColumnSize(final SizeInfo info) {
422: int width = 0;
423: int height = 0;
424: TableColumnModel model = header.getColumnModel();
425: for (int i = 0; i < model.getColumnCount(); i++) {
426: TableColumn column = model.getColumn(i);
427: width += info.getWidth(column);
428: int columnHeight = info.getHeight(column, header, i);
429: if (height < columnHeight) {
430: height = columnHeight;
431: }
432: }
433:
434: return new Dimension(width, height);
435: }
436:
437: private int getColumnIndex(final TableColumn column) {
438: for (int i = 0; i < header.getColumnModel().getColumnCount(); i++) {
439: if (header.getColumnModel().getColumn(i) == column) {
440: return i;
441: }
442: }
443: return -1;
444: }
445:
446: private static abstract class SizeInfo {
447: protected Component getRenderingComponent(
448: final TableColumn column, final JTableHeader header,
449: final int columnIndex) {
450: if (column.getHeaderValue() == null) {
451: return null;
452: }
453:
454: TableCellRenderer renderer = column.getHeaderRenderer() != null ? column
455: .getHeaderRenderer()
456: : header.getDefaultRenderer();
457:
458: return renderer.getTableCellRendererComponent(header
459: .getTable(), column.getHeaderValue(), false, false,
460: -1, columnIndex);
461: }
462:
463: public abstract int getWidth(TableColumn column);
464:
465: public abstract int getHeight(TableColumn column,
466: JTableHeader header, int columnIndex);
467: }
468: }
|