Lines 28-33
Link Here
|
28 |
import javax.swing.table.TableColumn; |
28 |
import javax.swing.table.TableColumn; |
29 |
import javax.swing.plaf.basic.BasicTableUI; |
29 |
import javax.swing.plaf.basic.BasicTableUI; |
30 |
import java.util.EventObject; |
30 |
import java.util.EventObject; |
|
|
31 |
import java.beans.PropertyEditor; |
31 |
import javax.swing.plaf.TableUI; |
32 |
import javax.swing.plaf.TableUI; |
32 |
import javax.swing.table.JTableHeader; |
33 |
import javax.swing.table.JTableHeader; |
33 |
import javax.swing.table.TableCellEditor; |
34 |
import javax.swing.table.TableCellEditor; |
Lines 35-40
Link Here
|
35 |
import org.openide.nodes.Node.Property; |
36 |
import org.openide.nodes.Node.Property; |
36 |
import org.openide.nodes.Node; |
37 |
import org.openide.nodes.Node; |
37 |
import org.openide.ErrorManager; |
38 |
import org.openide.ErrorManager; |
|
|
39 |
import org.openide.explorer.propertysheet.PropertyPanel; |
38 |
import org.openide.util.NbBundle; |
40 |
import org.openide.util.NbBundle; |
39 |
import org.openide.awt.MouseUtils; |
41 |
import org.openide.awt.MouseUtils; |
40 |
|
42 |
|
Lines 43-49
Link Here
|
43 |
* |
45 |
* |
44 |
* @author Jan Rojcek |
46 |
* @author Jan Rojcek |
45 |
*/ |
47 |
*/ |
46 |
class TreeTable extends JTable { |
48 |
class TreeTable extends JTable implements Runnable { |
47 |
/** A subclass of JTree. */ |
49 |
/** A subclass of JTree. */ |
48 |
private TreeTableCellRenderer tree; |
50 |
private TreeTableCellRenderer tree; |
49 |
private NodeTableModel tableModel; |
51 |
private NodeTableModel tableModel; |
Lines 73-80
Link Here
|
73 |
this.tree = new TreeTableCellRenderer(treeModel); |
75 |
this.tree = new TreeTableCellRenderer(treeModel); |
74 |
this.tableModel = new TreeTableModelAdapter(tree, tableModel); |
76 |
this.tableModel = new TreeTableModelAdapter(tree, tableModel); |
75 |
|
77 |
|
76 |
NodeRenderer rend = NodeRenderer.sharedInstance (); |
78 |
tree.setCellRenderer(new NodeRenderer()); |
77 |
tree.setCellRenderer(rend); |
|
|
78 |
|
79 |
|
79 |
// Install a tableModel representing the visible rows in the tree. |
80 |
// Install a tableModel representing the visible rows in the tree. |
80 |
setModel(this.tableModel); |
81 |
setModel(this.tableModel); |
Lines 158-169
Link Here
|
158 |
false), "beginEdit"); |
159 |
false), "beginEdit"); |
159 |
getActionMap().put("beginEdit", new EditAction()); |
160 |
getActionMap().put("beginEdit", new EditAction()); |
160 |
|
161 |
|
161 |
imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, |
162 |
imp2.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, |
162 |
false), "cancelEdit"); |
163 |
false), "cancelEdit"); |
163 |
getActionMap().put("cancelEdit", new CancelEditAction()); |
164 |
getActionMap().put("cancelEdit", new CancelEditAction()); |
164 |
|
165 |
|
165 |
imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, |
166 |
imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, |
166 |
false), "enter"); |
167 |
false), "enter"); |
167 |
getActionMap().put("enter", new EnterAction()); |
168 |
getActionMap().put("enter", new EnterAction()); |
168 |
|
169 |
|
169 |
imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "next"); |
170 |
imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "next"); |
Lines 273-302
Link Here
|
273 |
private void calcRowHeight(Graphics g) { |
274 |
private void calcRowHeight(Graphics g) { |
274 |
Font f = getFont(); |
275 |
Font f = getFont(); |
275 |
FontMetrics fm = g.getFontMetrics(f); |
276 |
FontMetrics fm = g.getFontMetrics(f); |
276 |
int rowHeight = fm.getHeight() + 4; |
277 |
int rowHeight = fm.getHeight() + fm.getMaxDescent(); |
277 |
needCalcRowHeight = false; |
278 |
needCalcRowHeight = false; |
278 |
rowHeight = Math.min(20, rowHeight); |
279 |
rowHeight = Math.max(20, rowHeight); |
279 |
setRowHeight (rowHeight); |
280 |
tree.setRowHeight (rowHeight); |
|
|
281 |
setRowHeight(rowHeight); |
280 |
} |
282 |
} |
281 |
|
283 |
|
282 |
/* |
|
|
283 |
* Overridden to pass the new rowHeight to the tree. |
284 |
*/ |
285 |
public void setRowHeight(int rowHeight) { |
286 |
super.setRowHeight(rowHeight); |
287 |
if (tree != null && tree.getRowHeight() != rowHeight) { |
288 |
tree.setRowHeight(getRowHeight()); |
289 |
} |
290 |
} |
291 |
|
292 |
/** |
284 |
/** |
293 |
* Returns the tree that is being shared between the model. |
285 |
* Returns the tree that is being shared between the model. |
294 |
*/ |
286 |
*/ |
295 |
JTree getTree() { |
287 |
JTree getTree() { |
296 |
return tree; |
288 |
return tree; |
297 |
} |
289 |
} |
298 |
|
290 |
|
299 |
/** |
291 |
/** |
300 |
* Returns table column index of the column displaying the tree. |
292 |
* Returns table column index of the column displaying the tree. |
301 |
*/ |
293 |
*/ |
302 |
int getTreeColumnIndex() { |
294 |
int getTreeColumnIndex() { |
Lines 351-357
Link Here
|
351 |
|
343 |
|
352 |
//Bypass standard tab and escape handling, and use our registered |
344 |
//Bypass standard tab and escape handling, and use our registered |
353 |
//actions instead |
345 |
//actions instead |
354 |
if ((e.getKeyCode() != e.VK_TAB && e.getKeyCode() != e.VK_ESCAPE) || (e.getModifiers() & e.CTRL_MASK) != 0) { |
346 |
if (!isEditing() || ((e.getKeyCode() != e.VK_TAB && e.getKeyCode() != e.VK_ESCAPE) || (e.getModifiers() & e.CTRL_MASK) != 0)) { |
355 |
super.processKeyEvent(e); |
347 |
super.processKeyEvent(e); |
356 |
} else { |
348 |
} else { |
357 |
processKeyBinding(KeyStroke.getKeyStroke( |
349 |
processKeyBinding(KeyStroke.getKeyStroke( |
Lines 386-392
Link Here
|
386 |
inEditRequest =false; |
378 |
inEditRequest =false; |
387 |
return false; |
379 |
return false; |
388 |
} |
380 |
} |
389 |
|
381 |
|
390 |
if (isEditing()) { |
382 |
if (isEditing()) { |
391 |
inEditorChangeRequest = true; |
383 |
inEditorChangeRequest = true; |
392 |
try { |
384 |
try { |
Lines 396-402
Link Here
|
396 |
inEditorChangeRequest = false; |
388 |
inEditorChangeRequest = false; |
397 |
} |
389 |
} |
398 |
} |
390 |
} |
399 |
|
391 |
|
400 |
//Treat a keyEvent request to edit on a non-editable |
392 |
//Treat a keyEvent request to edit on a non-editable |
401 |
//column as a request to edit the nearest column that is |
393 |
//column as a request to edit the nearest column that is |
402 |
//editable |
394 |
//editable |
Lines 407-434
Link Here
|
407 |
editable = false; |
399 |
editable = false; |
408 |
column = 1; |
400 |
column = 1; |
409 |
} |
401 |
} |
410 |
|
402 |
|
|
|
403 |
boolean columnShifted = false; |
411 |
if (!editable && (e instanceof KeyEvent || e == null)) { |
404 |
if (!editable && (e instanceof KeyEvent || e == null)) { |
412 |
for (int i=column; i < getColumnCount(); i++) { |
405 |
for (int i=column; i < getColumnCount(); i++) { |
413 |
if (getModel().isCellEditable(row, i)) { |
406 |
if (getModel().isCellEditable(row, i)) { |
|
|
407 |
columnShifted = i != column; |
414 |
column = i; |
408 |
column = i; |
415 |
changeSelection(row, column, false, false); |
409 |
changeSelection(row, column, false, false); |
416 |
break; |
410 |
break; |
417 |
} |
411 |
} |
418 |
} |
412 |
} |
419 |
} |
413 |
} |
420 |
|
414 |
|
421 |
|
415 |
final Rectangle r = getCellRect (row, column, true); |
|
|
416 |
//#44226 - Provide a way to invoke the custom editor on disabled cells |
417 |
boolean canTryCustomEditor = !columnShifted && e instanceof MouseEvent ? |
418 |
((MouseEvent) e).getX() > r.x + r.width - 24 && ((MouseEvent) e).getX() < r.x + r.width : |
419 |
true; |
422 |
try { |
420 |
try { |
423 |
canEdit = (lastRow == row); |
421 |
canEdit = (lastRow == row); |
424 |
Object o = getValueAt(row, column); |
422 |
Object o = getValueAt(row, column); |
425 |
if (o instanceof Property) { // && (e == null || e instanceof KeyEvent)) { |
423 |
if (o instanceof Property) { // && (e == null || e instanceof KeyEvent)) { |
426 |
//Toggle booleans without instantiating an editor |
424 |
//Toggle booleans without instantiating an editor |
427 |
Property p = (Property) o; |
425 |
Property p = (Property) o; |
428 |
if (p.getValueType() == Boolean.class || p.getValueType() == Boolean.TYPE) { |
426 |
if (p.canWrite() && (p.getValueType() == Boolean.class || p.getValueType() == Boolean.TYPE)) { |
429 |
if (!p.canWrite()) { |
|
|
430 |
return false; |
431 |
} |
432 |
try { |
427 |
try { |
433 |
Boolean val = (Boolean) p.getValue(); |
428 |
Boolean val = (Boolean) p.getValue(); |
434 |
if (Boolean.FALSE.equals(val)) { |
429 |
if (Boolean.FALSE.equals(val)) { |
Lines 437-470
Link Here
|
437 |
//This covers null multi-selections too |
432 |
//This covers null multi-selections too |
438 |
p.setValue(Boolean.FALSE); |
433 |
p.setValue(Boolean.FALSE); |
439 |
} |
434 |
} |
440 |
Rectangle r = getCellRect (row, column, true); |
435 |
|
441 |
repaint (r.x, r.y, r.width, r.height); |
436 |
repaint (r.x, r.y, r.width, r.height); |
442 |
return false; |
437 |
return false; |
443 |
} catch (Exception e1) { |
438 |
} catch (Exception e1) { |
444 |
ErrorManager.getDefault().notify(ErrorManager.WARNING, e1); |
439 |
ErrorManager.getDefault().notify(ErrorManager.WARNING, e1); |
445 |
return false; |
440 |
return false; |
446 |
} |
441 |
} |
|
|
442 |
} else if (canTryCustomEditor && !Boolean.TRUE.equals(p.getValue("suppressCustomEditor"))) { //NOI18N |
443 |
PropertyPanel panel = new PropertyPanel (p); |
444 |
PropertyEditor ed = panel.getPropertyEditor(); |
445 |
if (ed != null && ed.supportsCustomEditor()) { |
446 |
Action act = panel.getActionMap().get("invokeCustomEditor"); //NOI18N |
447 |
if (act != null) { |
448 |
SwingUtilities.invokeLater (new Runnable(){ |
449 |
public void run() { |
450 |
r.x = 0; |
451 |
r.width = getWidth(); |
452 |
TreeTable.this.repaint (r); |
453 |
} |
454 |
}); |
455 |
act.actionPerformed(null); |
456 |
return false; |
457 |
} |
458 |
} |
459 |
} |
460 |
if (!p.canWrite()) { |
461 |
return false; |
447 |
} |
462 |
} |
448 |
} |
463 |
} |
449 |
|
464 |
|
450 |
|
465 |
|
451 |
boolean ret = super.editCellAt(row, column, e); |
466 |
boolean ret = super.editCellAt(row, column, e); |
452 |
if (ret) { |
467 |
if (ret) { |
453 |
editorComp.requestFocus(); |
468 |
//InvokeLater to get out of the way of anything the winsys is going to do |
454 |
} |
469 |
if (column == getTreeColumnIndex()) { |
455 |
|
|
|
456 |
if (ret && column == getTreeColumnIndex()) { |
457 |
ignoreScrolling = true; |
470 |
ignoreScrolling = true; |
458 |
tree.scrollRectToVisible(tree.getRowBounds(row)); |
471 |
tree.scrollRectToVisible(tree.getRowBounds(row)); |
459 |
ignoreScrolling = false; |
472 |
ignoreScrolling = false; |
|
|
473 |
} else { |
474 |
SwingUtilities.invokeLater (this); |
460 |
} |
475 |
} |
|
|
476 |
} |
477 |
|
461 |
return ret; |
478 |
return ret; |
462 |
} finally { |
479 |
} finally { |
463 |
inEditRequest = false; |
480 |
inEditRequest = false; |
464 |
} |
481 |
} |
465 |
} |
482 |
} |
466 |
|
483 |
|
467 |
/* |
484 |
/** |
|
|
485 |
* |
486 |
*/ |
487 |
public void run() { |
488 |
if (editorComp != null && editorComp.isShowing()) { |
489 |
editorComp.requestFocus(); |
490 |
} |
491 |
} |
492 |
|
493 |
/* |
468 |
*/ |
494 |
*/ |
469 |
public void valueChanged(ListSelectionEvent e) { |
495 |
public void valueChanged(ListSelectionEvent e) { |
470 |
if (getSelectedRowCount() == 1) |
496 |
if (getSelectedRowCount() == 1) |
Lines 578-584
Link Here
|
578 |
|
604 |
|
579 |
public TreeTableCellRenderer(TreeModel model) { |
605 |
public TreeTableCellRenderer(TreeModel model) { |
580 |
super(model); |
606 |
super(model); |
581 |
setRowHeight(getRowHeight()); |
|
|
582 |
setToggleClickCount(0); |
607 |
setToggleClickCount(0); |
583 |
putClientProperty("JTree.lineStyle", "None"); // NOI18N |
608 |
putClientProperty("JTree.lineStyle", "None"); // NOI18N |
584 |
} |
609 |
} |
Lines 599-618
Link Here
|
599 |
//do nothing |
624 |
//do nothing |
600 |
} |
625 |
} |
601 |
|
626 |
|
|
|
627 |
/** |
628 |
* Accessor so NodeRenderer can check if the tree table or its child has |
629 |
* focus and paint with the appropriate color. |
630 |
* |
631 |
* @see NodeRenderer#configureFrom |
632 |
* @return The tree table |
633 |
*/ |
634 |
TreeTable getTreeTable() { |
635 |
return TreeTable.this; |
636 |
} |
637 |
|
602 |
/** |
638 |
/** |
603 |
* Sets the row height of the tree, and forwards the row height to |
639 |
* Sets the row height of the tree, and forwards the row height to |
604 |
* the table. |
640 |
* the table. |
605 |
*/ |
641 |
*/ |
606 |
public void setRowHeight(int rowHeight) { |
642 |
public void setRowHeight(int rowHeight) { |
607 |
if (rowHeight > 0) { |
643 |
if (rowHeight > 0) { |
608 |
synchronized (getTreeLock()) { |
644 |
super.setRowHeight(rowHeight); |
609 |
super.setRowHeight(rowHeight); |
645 |
TreeTable.this.setRowHeight(rowHeight); |
610 |
if (TreeTable.this != null && |
646 |
} |
611 |
TreeTable.this.getRowHeight() != rowHeight) { |
|
|
612 |
TreeTable.this.setRowHeight(getRowHeight()); |
613 |
} |
614 |
} |
615 |
} |
616 |
} |
647 |
} |
617 |
|
648 |
|
618 |
/** |
649 |
/** |
Lines 701-714
Link Here
|
701 |
|
732 |
|
702 |
boolean tableHasFocus = focusOwner == this || |
733 |
boolean tableHasFocus = focusOwner == this || |
703 |
focusOwner == TreeTable.this |
734 |
focusOwner == TreeTable.this |
704 |
|| TreeTable.this.isAncestorOf(focusOwner); |
735 |
|| TreeTable.this.isAncestorOf(focusOwner) || |
|
|
736 |
focusOwner instanceof JRootPane; //RootPane == popup menu |
705 |
|
737 |
|
|
|
738 |
//TODO - it should be possible to simply set the correct |
739 |
//color in prepareRenderer for the tree's cell renderer, |
740 |
//rather than set it for the whole tree. Might fix a |
741 |
//couple problems. -Tim |
706 |
setBackground(tableHasFocus ? |
742 |
setBackground(tableHasFocus ? |
707 |
table.getSelectionBackground() : |
743 |
table.getSelectionBackground() : |
708 |
NodeRenderer.getNoFocusSelectionBackground()); |
744 |
getUnfocusedSelectedBackground()); |
709 |
setForeground(tableHasFocus ? |
745 |
setForeground(tableHasFocus ? |
710 |
table.getSelectionForeground() : |
746 |
table.getSelectionForeground() : |
711 |
NodeRenderer.getNoFocusSelectionForeground()); |
747 |
getUnfocusedSelectedForeground()); |
712 |
} else { |
748 |
} else { |
713 |
setBackground(table.getBackground()); |
749 |
setBackground(table.getBackground()); |
714 |
setForeground(table.getForeground()); |
750 |
setForeground(table.getForeground()); |
Lines 818-827
Link Here
|
818 |
if (isEditing() && editorComp != null) { |
854 |
if (isEditing() && editorComp != null) { |
819 |
editorComp.setBackground(focused ? |
855 |
editorComp.setBackground(focused ? |
820 |
getSelectionBackground() : |
856 |
getSelectionBackground() : |
821 |
NodeRenderer.getNoFocusSelectionBackground()); |
857 |
getUnfocusedSelectedBackground()); |
822 |
editorComp.setForeground(focused ? |
858 |
editorComp.setForeground(focused ? |
823 |
getSelectionForeground() : |
859 |
getSelectionForeground() : |
824 |
NodeRenderer.getNoFocusSelectionForeground()); |
860 |
getUnfocusedSelectedForeground()); |
825 |
} |
861 |
} |
826 |
} |
862 |
} |
827 |
|
863 |
|
Lines 1181-1187
Link Here
|
1181 |
int min = listSelectionModel.getMinSelectionIndex(); |
1217 |
int min = listSelectionModel.getMinSelectionIndex(); |
1182 |
int max = listSelectionModel.getMaxSelectionIndex(); |
1218 |
int max = listSelectionModel.getMaxSelectionIndex(); |
1183 |
|
1219 |
|
1184 |
this.clearSelection (); |
1220 |
boolean unset = true; |
1185 |
if(min != -1 && max != -1) { |
1221 |
if(min != -1 && max != -1) { |
1186 |
for(int counter = min; counter <= max; counter++) { |
1222 |
for(int counter = min; counter <= max; counter++) { |
1187 |
if(listSelectionModel.isSelectedIndex(counter)) { |
1223 |
if(listSelectionModel.isSelectedIndex(counter)) { |
Lines 1189-1199
Link Here
|
1189 |
(counter); |
1225 |
(counter); |
1190 |
|
1226 |
|
1191 |
if(selPath != null) { |
1227 |
if(selPath != null) { |
1192 |
addSelectionPath(selPath); |
1228 |
if (unset) { |
|
|
1229 |
setSelectionPath(selPath); |
1230 |
unset = false; |
1231 |
} else { |
1232 |
addSelectionPath(selPath); |
1233 |
} |
1193 |
} |
1234 |
} |
1194 |
} |
1235 |
} |
1195 |
} |
1236 |
} |
1196 |
} |
1237 |
} |
|
|
1238 |
if (unset) { |
1239 |
clearSelection(); |
1240 |
} |
1197 |
} |
1241 |
} |
1198 |
finally { |
1242 |
finally { |
1199 |
updatingListSelectionModel = false; |
1243 |
updatingListSelectionModel = false; |
Lines 1323-1329
Link Here
|
1323 |
setDispatchComponent(e); |
1367 |
setDispatchComponent(e); |
1324 |
repostEvent(e); |
1368 |
repostEvent(e); |
1325 |
} |
1369 |
} |
1326 |
else { |
1370 |
|
|
|
1371 |
if (e.getID() == MouseEvent.MOUSE_PRESSED) { |
1327 |
table.requestFocus(); |
1372 |
table.requestFocus(); |
1328 |
} |
1373 |
} |
1329 |
|
1374 |
|
Lines 1547-1554
Link Here
|
1547 |
} |
1592 |
} |
1548 |
|
1593 |
|
1549 |
public boolean isEnabled() { |
1594 |
public boolean isEnabled() { |
1550 |
// return isEditing(); |
1595 |
return isEditing(); |
1551 |
return true; |
|
|
1552 |
} |
1596 |
} |
1553 |
} |
1597 |
} |
1554 |
|
1598 |
|
Lines 1611-1614
Link Here
|
1611 |
} |
1655 |
} |
1612 |
} |
1656 |
} |
1613 |
} |
1657 |
} |
|
|
1658 |
|
1659 |
private static Color unfocusedSelBg = null; |
1660 |
private static Color unfocusedSelFg = null; |
1661 |
|
1662 |
/** Get the system-wide unfocused selection background color */ |
1663 |
static Color getUnfocusedSelectedBackground() { |
1664 |
if (unfocusedSelBg == null) { |
1665 |
//allow theme/ui custom definition |
1666 |
unfocusedSelBg = |
1667 |
UIManager.getColor("nb.explorer.unfocusedSelBg"); //NOI18N |
1668 |
if (unfocusedSelBg == null) { |
1669 |
//try to get standard shadow color |
1670 |
unfocusedSelBg = UIManager.getColor("controlShadow"); //NOI18N |
1671 |
if (unfocusedSelBg == null) { |
1672 |
//Okay, the look and feel doesn't suport it, punt |
1673 |
unfocusedSelBg = Color.lightGray; |
1674 |
} |
1675 |
//Lighten it a bit because disabled text will use controlShadow/ |
1676 |
//gray |
1677 |
unfocusedSelBg = unfocusedSelBg.brighter(); |
1678 |
} |
1679 |
} |
1680 |
return unfocusedSelBg; |
1681 |
} |
1682 |
|
1683 |
/** Get the system-wide unfocused selection foreground color */ |
1684 |
static Color getUnfocusedSelectedForeground() { |
1685 |
if (unfocusedSelFg == null) { |
1686 |
//allow theme/ui custom definition |
1687 |
unfocusedSelFg = |
1688 |
UIManager.getColor("nb.explorer.unfocusedSelFg"); //NOI18N |
1689 |
if (unfocusedSelFg == null) { |
1690 |
//try to get standard shadow color |
1691 |
unfocusedSelFg = UIManager.getColor("textText"); //NOI18N |
1692 |
if (unfocusedSelFg == null) { |
1693 |
//Okay, the look and feel doesn't suport it, punt |
1694 |
unfocusedSelFg = Color.BLACK; |
1695 |
} |
1696 |
} |
1697 |
} |
1698 |
return unfocusedSelFg; |
1699 |
} |
1614 |
} |
1700 |
} |