? core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/.DS_Store ? core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/resources/.DS_Store Index: core/swing/tabcontrol/demosrc/org/netbeans/swing/tabcontrol/demo/TestFrame.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/demosrc/org/netbeans/swing/tabcontrol/demo/TestFrame.java,v retrieving revision 1.5 diff -u -u -r1.5 TestFrame.java --- core/swing/tabcontrol/demosrc/org/netbeans/swing/tabcontrol/demo/TestFrame.java 10 Aug 2004 13:56:37 -0000 1.5 +++ core/swing/tabcontrol/demosrc/org/netbeans/swing/tabcontrol/demo/TestFrame.java 9 Sep 2004 23:34:59 -0000 @@ -63,10 +63,16 @@ */ try { - //UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel()); +// UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel()); } catch (Exception e) { } +// UIManager.put ("EditorTabDisplayerUI", "org.netbeans.swing.tabcontrol.plaf.WinClassicEditorTabDisplayerUI"); +// UIManager.put ("ViewTabDisplayerUI", "org.netbeans.swing.tabcontrol.plaf.WinClassicViewTabDisplayerUI"); +// UIManager.put ("EditorTabDisplayerUI", "org.netbeans.swing.tabcontrol.plaf.WinXPEditorTabDisplayerUI"); +// UIManager.put ("ViewTabDisplayerUI", "org.netbeans.swing.tabcontrol.plaf.WinXPViewTabDisplayerUI"); + + JLabel jb1 = new JLabel("Label 1"); final JButton jb2 = new JButton("Button 2 - Update UI"); JButton jb3 = new JButton("Click me to remove this tab"); @@ -90,6 +96,14 @@ JTA.setColumns(80); JTA.setLineWrap(true); + JButton jb7 = new JButton ("Remove non-contiguous tabs"); + JButton jb8 = new JButton ("Discontig add"); + + JButton jb9 = new JButton ("Contig add"); + JButton jb10 = new JButton ("Contig remove"); + + JButton jb11 = new JButton ("Discontig add and remove"); + TabData tab0 = new TabData(jtr, myIcon, "0 JTree", "0"); TabData tab1 = new TabData(jb1, myIcon, "1 Tab 1", "1"); @@ -107,17 +121,17 @@ "7"); TabData tab8 = new TabData(new JLabel("gioo"), myIcon, "8 something", "8"); - TabData tab9 = new TabData(new JButton("foo"), myIcon, "9 foob", + TabData tab9 = new TabData(jb7, myIcon, "9 Discontig remove", "9"); TabData tab10 = new TabData(new JLabel("gioo"), myIcon, "10 wiggle", "10"); - TabData tab11 = new TabData(new JButton("foo"), myIcon, "11 bumble", + TabData tab11 = new TabData(jb8, myIcon, "11 Discontig add", "11"); - TabData tab12 = new TabData(new JLabel("mooble"), myIcon, - "12 poodle", "12"); - TabData tab13 = new TabData(new JButton("fooble"), myIcon, - "13 hoover", "13"); - TabData tab14 = new TabData(new JLabel("gooble"), myIcon, "14 snip", + TabData tab12 = new TabData(jb9, myIcon, + "12 contig add", "12"); + TabData tab13 = new TabData(jb10, myIcon, + "13 contig remove", "13"); + TabData tab14 = new TabData(jb11, myIcon, "14 MUNGE", "14"); TabDataModel mdl = new DefaultTabDataModel(new TabData[]{ @@ -130,8 +144,10 @@ ); */ - final TabbedContainer tab = new TabbedContainer(mdl, TabbedContainer.TYPE_EDITOR); - tab.setActive(true); + final TabbedContainer tab = new TabbedContainer(mdl, TabbedContainer.TYPE_VIEW); + tab.setActive(true); + tab.requestAttention(5); + tab.requestAttention(3); jb6.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { @@ -161,6 +177,72 @@ tab.updateUI(); } }); + + jb7.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + tab.getModel().removeTabs(new int[] {1, 3, 7, 8}); + } + }); + + jb8.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + int[] idxs = new int [] { 1, 3, 6, 8}; + TabData[] td = new TabData[] { + new TabData(new JButton("inserted 1"), myIcon, "I-1", "tip"), + new TabData(new JButton("inserted 3"), myIcon, "I-3", "tip"), + new TabData(new JButton("inserted 6"), myIcon, "I-6", "tip"), + new TabData(new JButton("inserted 8"), myIcon, "I-8", "tip"), + + }; + tab.getModel().addTabs(idxs, td); + } + }); + + jb9.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + int[] idxs = new int [] { 1, 3, 6, 8}; + TabData[] td = new TabData[] { + new TabData(new JButton("inserted c 1"), myIcon, "Ic-1", "tip"), + new TabData(new JButton("inserted c 2"), myIcon, "Ic-2", "tip"), + new TabData(new JButton("inserted c 3"), myIcon, "Ic-3", "tip"), + new TabData(new JButton("inserted c 4"), myIcon, "Ic-4", "tip"), + + }; + tab.getModel().addTabs(1, td); + } + }); + + jb10.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + tab.getModel().removeTabs(1, 4); + } + }); + + jb11.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + TabData[] data = (TabData[]) tab.getModel().getTabs().toArray(new TabData[0]); + + TabData[] newData = new TabData [ data.length - 3]; + int ct = 0; + + //strip out some tabs + for (int i=0; i < data.length; i++) { + newData[ct] = data[i]; + if (i != 2 && i != 3 && i != 7) { + ct++; + } + } + + //replace one tab + newData[1] = new TabData (new JLabel ("Hi there"), myIcon, "New tab", "foo"); + //swap some tabs + TabData td = newData[8]; + newData[8] = newData[7]; + newData[7] = td; + + tab.getModel().setTabs(newData); + } + }); tab.setActive(true); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/DefaultTabDataModel.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/DefaultTabDataModel.java,v retrieving revision 1.2 diff -u -u -r1.2 DefaultTabDataModel.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/DefaultTabDataModel.java 22 Apr 2004 13:09:06 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/DefaultTabDataModel.java 9 Sep 2004 23:34:59 -0000 @@ -327,9 +327,17 @@ fireIntervalRemoved(lde); } + /** + * Remove a range of tabs from start up to and including + * finish. + */ public void removeTabs(int start, int end) { java.util.List affected = list.subList(start, end); - list.removeRange(start, end); + if (start == end) { + list.remove(start); + } else { + list.removeRange(start, end + 1); + } ComplexListDataEvent lde = new ComplexListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, start, end); @@ -343,7 +351,6 @@ m.put(new Integer(indices[i]), data[i]); } Arrays.sort(indices); -// for (int i=indices.length-1; i >= 0; i--) { for (int i = 0; i < indices.length; i++) { Integer key = new Integer(indices[i]); TabData currData = (TabData) m.get(key); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayer.java,v retrieving revision 1.8 diff -u -u -r1.8 TabDisplayer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayer.java 23 Aug 2004 12:22:15 -0000 1.8 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayer.java 9 Sep 2004 23:35:00 -0000 @@ -333,6 +333,19 @@ public final Dimension getMinimumSize() { return getUI().getMinimumSize(this); } + + public final void requestAttention (int tab) { + getUI().requestAttention(tab); + } + + public final boolean requestAttention (TabData data) { + int idx = getModel().indexOf(data); + boolean result = idx >= 0; + if (result) { + requestAttention (idx); + } + return result; + } /** * Accessor only for TabDisplayerUI when installing the UI Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayerUI.java,v retrieving revision 1.4 diff -u -u -r1.4 TabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayerUI.java 10 Aug 2004 13:56:37 -0000 1.4 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabDisplayerUI.java 9 Sep 2004 23:35:00 -0000 @@ -184,5 +184,7 @@ public abstract void registerShortcuts (JComponent comp); public abstract void unregisterShortcuts (JComponent comp); + + public abstract void requestAttention (int tab); } Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainer.java,v retrieving revision 1.9 diff -u -u -r1.9 TabbedContainer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainer.java 11 Aug 2004 13:43:22 -0000 1.9 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainer.java 9 Sep 2004 23:35:01 -0000 @@ -556,6 +556,27 @@ firePropertyChange(PROP_ACTIVE, !active, active); } } + + /** + * Cause the tab at the specified index to blink or otherwise suggest that + * the user should click it. + */ + public void requestAttention (int tab) { + getUI().requestAttention(tab); + } + + /** + * Cause the specified tab to blink or otherwisse suggest that the user should + * click it. + */ + public final boolean requestAttention (TabData data) { + int idx = getModel().indexOf(data); + boolean result = idx >= 0; + if (result) { + requestAttention (idx); + } + return result; + } /** * Determine if this component thinks it is "active", which Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainerUI.java,v retrieving revision 1.4 diff -u -u -r1.4 TabbedContainerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainerUI.java 10 Aug 2004 13:56:37 -0000 1.4 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/TabbedContainerUI.java 9 Sep 2004 23:35:01 -0000 @@ -199,4 +199,6 @@ */ public abstract int dropIndexOfPoint(Point p); + public abstract void requestAttention (int tab); + } Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabCellRenderer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabCellRenderer.java,v retrieving revision 1.4 diff -u -u -r1.4 AbstractTabCellRenderer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabCellRenderer.java 8 Sep 2004 22:48:58 -0000 1.4 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabCellRenderer.java 9 Sep 2004 23:35:02 -0000 @@ -190,6 +190,10 @@ protected final boolean isRightmost() { return (state & TabState.RIGHTMOST) != 0; } + + protected final boolean isAttention() { + return (state & TabState.ATTENTION) != 0; + } /** * Convenience getter to determine if the current state indicates Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabDisplayerUI.java,v retrieving revision 1.7 diff -u -u -r1.7 AbstractTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabDisplayerUI.java 11 Aug 2004 17:09:16 -0000 1.7 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractTabDisplayerUI.java 9 Sep 2004 23:35:03 -0000 @@ -401,7 +401,7 @@ * No-op implementation */ public void contentsChanged(ListDataEvent e) { - //do nothing + } /** Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractViewTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractViewTabDisplayerUI.java,v retrieving revision 1.15 diff -u -u -r1.15 AbstractViewTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractViewTabDisplayerUI.java 2 Sep 2004 13:43:09 -0000 1.15 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AbstractViewTabDisplayerUI.java 9 Sep 2004 23:35:04 -0000 @@ -13,6 +13,7 @@ package org.netbeans.swing.tabcontrol.plaf; +import javax.swing.event.ListDataEvent; import org.netbeans.swing.tabcontrol.TabData; import org.netbeans.swing.tabcontrol.TabDataModel; import org.netbeans.swing.tabcontrol.TabDisplayer; @@ -38,6 +39,8 @@ import java.util.Map; import org.netbeans.swing.tabcontrol.LocationInformer; import org.netbeans.swing.tabcontrol.TabbedContainer; +import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent; +import org.netbeans.swing.tabcontrol.event.ComplexListDataListener; /** * Basic UI class for view tabs - non scrollable tabbed displayer, which shows all @@ -83,6 +86,7 @@ dataModel = displayer.getModel(); layoutModel = new ViewTabLayoutModel(dataModel, displayer); dataModel.addChangeListener (controller); + dataModel.addComplexListDataListener(controller); displayer.addPropertyChangeListener (controller); selectionModel.addChangeListener (controller); displayer.addMouseListener(controller); @@ -106,6 +110,7 @@ ToolTipManager.sharedInstance().unregisterComponent(displayer); displayer.removePropertyChangeListener (controller); dataModel.removeChangeListener(controller); + dataModel.removeComplexListDataListener(controller); selectionModel.removeChangeListener(controller); displayer.removeMouseListener(controller); displayer.removeMouseMotionListener(controller); @@ -503,9 +508,12 @@ } public Rectangle getTabRect(int index, Rectangle destination) { + if (destination == null) { + destination = new Rectangle(); + } if (index < 0 || index > displayer.getModel().size()) { - throw new ArrayIndexOutOfBoundsException("Tab index out of " + - "bounds: " + index); + destination.setBounds (0,0,0,0); + return destination; } destination.x = layoutModel.getX(index); destination.width = layoutModel.getW(index); @@ -532,13 +540,50 @@ return -1; } + + protected int createRepaintPolicy () { + return TabState.REPAINT_SELECTION_ON_ACTIVATION_CHANGE + | TabState.REPAINT_ON_SELECTION_CHANGE + | TabState.REPAINT_ON_MOUSE_ENTER_TAB + | TabState.REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON + | TabState.REPAINT_ON_MOUSE_PRESSED; + } + + protected final TabState tabState = new ViewTabState(); + + private class ViewTabState extends TabState { + public int getRepaintPolicy(int tab) { + return createRepaintPolicy(); + } + + public void repaintAllTabs() { + displayer.repaint(); + } + + public void repaintTab (int tab) { + Rectangle r = getTabRect(tab, null); + displayer.repaint(r); + } + } + + /** + * Determine if the tab should be flashing + */ + protected boolean isAttention (int tab) { + return (tabState.getState(tab) & TabState.ATTENTION) != 0; + } + + + public void requestAttention (int tab) { + tabState.addAlarmTab(tab); + } /** * Listen to mouse events and handles selection behaviour and close icon * button behaviour. */ abstract class Controller extends MouseAdapter - implements MouseMotionListener, ChangeListener, PropertyChangeListener, ActionListener { + implements MouseMotionListener, ChangeListener, PropertyChangeListener, ActionListener, ComplexListDataListener { /** * index of tab whose close icon currently pressed, -1 otherwise @@ -596,11 +641,13 @@ public void mousePressed(MouseEvent e) { Point p = e.getPoint(); int i = getLayoutModel().indexOfPoint(p.x, p.y); + tabState.setPressed(i); SingleSelectionModel sel = getSelectionModel(); selectionChanged = i != sel.getSelectedIndex(); // invoke possible selection change if ((i != -1) || !selectionChanged) { getSelectionModel().setSelectedIndex(i); + tabState.setSelected(i); } // update pressed state if (shouldReact(e) && !selectionChanged) { @@ -632,6 +679,7 @@ public void mouseReleased(MouseEvent e) { // close button must not be active when selection change was // triggered by mouse press + tabState.setPressed(-1); if (shouldReact(e) && !selectionChanged) { setClosePressed(-1); Point point = e.getPoint(); @@ -721,6 +769,7 @@ // sync of indexes int oldValue = mouseInCloseButton; mouseInCloseButton = isNow; + tabState.setCloseButtonContainsMouse(isNow); if (isNow == -1) { // exit from close area TabLayoutModel tlm = getLayoutModel(); @@ -745,7 +794,44 @@ public void actionPerformed(ActionEvent e) { performPinAction(); } + + public void indicesAdded(ComplexListDataEvent e) { + tabState.indicesAdded(e); + } + + /** + * Elements have been removed at the indices specified by the event's + * getIndices() value + * + * @param e The event + */ + public void indicesRemoved(ComplexListDataEvent e) { + tabState.indicesRemoved(e); + } + + /** + * Elements have been changed at the indices specified by the event's + * getIndices() value. If the changed data can affect display width (such + * as a text change or a change in icon size), the event's + * isTextChanged() method will return true. + * + * @param e The event + */ + public void indicesChanged(ComplexListDataEvent e) { + tabState.indicesChanged(e); + } + + public void intervalAdded (ListDataEvent evt) { + tabState.intervalAdded(evt); + } + + public void intervalRemoved (ListDataEvent evt) { + tabState.intervalRemoved(evt); + } + public void contentsChanged(ListDataEvent evt) { + tabState.contentsChanged(evt); + } } // end of Controller Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaEditorTabCellRenderer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaEditorTabCellRenderer.java,v retrieving revision 1.3 diff -u -u -r1.3 AquaEditorTabCellRenderer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaEditorTabCellRenderer.java 15 Jun 2004 19:58:32 -0000 1.3 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaEditorTabCellRenderer.java 9 Sep 2004 23:35:04 -0000 @@ -140,6 +140,8 @@ boolean leftmost = ((AquaEditorTabCellRenderer) c).isLeftmost(); boolean closing = pressed && ((AquaEditorTabCellRenderer) c).inCloseButton(); + boolean attention = !pressed && !closing + && ((AquaEditorTabCellRenderer) c).isAttention(); //add in a pixel for rightmost/leftmost so we don't clip off //antialiasing of the curve @@ -161,6 +163,9 @@ } if (closing) { state |= GenericGlowingChiclet.STATE_CLOSING; + } + if (attention) { + state |= GenericGlowingChiclet.STATE_ATTENTION; } chiclet.setArcs(leftarc, rightarc, leftarc, rightarc); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaViewTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaViewTabDisplayerUI.java,v retrieving revision 1.9 diff -u -u -r1.9 AquaViewTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaViewTabDisplayerUI.java 1 Sep 2004 15:06:05 -0000 1.9 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/AquaViewTabDisplayerUI.java 9 Sep 2004 23:35:04 -0000 @@ -205,6 +205,9 @@ if (isSelected(index)) { state |= GenericGlowingChiclet.STATE_SELECTED; } + if (isAttention(index)) { + state |= GenericGlowingChiclet.STATE_ATTENTION; + } chiclet.setState(state); chiclet.setBounds(x, y, width, height); @@ -299,9 +302,13 @@ Point p = e.getPoint(); int i = getLayoutModel().indexOfPoint(p.x, p.y); int closeRectIdx = inCloseIconRect(p); + tabState.setPressed(i); + tabState.setCloseButtonContainsMouse(closeRectIdx); + tabState.setMousePressedInCloseButton(closeRectIdx); // invoke possible selection change if ((i != -1) && closeRectIdx == -1) { getSelectionModel().setSelectedIndex(i); + tabState.setSelected(i); } if (shouldReact(e) && closeRectIdx != -1) { setClosePressed(closeRectIdx); @@ -317,6 +324,8 @@ } public void mouseReleased(MouseEvent e) { + tabState.setMousePressedInCloseButton(-1); + tabState.setPressed(-1); // close button must not be active when selection change was // triggered by mouse press if (shouldReact(e)) { @@ -338,10 +347,12 @@ public void mouseEntered(MouseEvent me) { setContainsMouse(true); + tabState.setMouseInTabsArea(true); } public void mouseExited(MouseEvent me) { setContainsMouse(false); + tabState.setMouseInTabsArea(false); } } // end of OwnController Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicSlidingTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicSlidingTabDisplayerUI.java,v retrieving revision 1.2 diff -u -u -r1.2 BasicSlidingTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicSlidingTabDisplayerUI.java 22 Apr 2004 13:09:11 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicSlidingTabDisplayerUI.java 9 Sep 2004 23:35:05 -0000 @@ -127,6 +127,10 @@ return new MouseAdapter() {}; //XXX } + public void requestAttention (int tab) { + //not implemented + } + protected ChangeListener createSelectionListener() { return new ChangeListener() { private int lastKnownSelection = -1; Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicTabDisplayerUI.java,v retrieving revision 1.5 diff -u -u -r1.5 BasicTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicTabDisplayerUI.java 2 Sep 2004 13:43:09 -0000 1.5 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/BasicTabDisplayerUI.java 9 Sep 2004 23:35:06 -0000 @@ -12,6 +12,7 @@ */ package org.netbeans.swing.tabcontrol.plaf; +import javax.swing.event.ListDataEvent; import org.netbeans.swing.tabcontrol.TabData; import org.netbeans.swing.tabcontrol.TabDisplayer; import org.netbeans.swing.tabcontrol.TabbedContainer; @@ -24,6 +25,7 @@ import java.awt.geom.Area; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; +import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent; /** * Base class for tab displayer UIs which use cell renderers to display tabs. @@ -117,6 +119,11 @@ defaultRenderer = null; super.uninstall(); } + + /** Used by unit tests */ + TabState getTabState() { + return tabState; + } /** * Create a TabState instance. TabState manages the state of tabs - that is, which one @@ -218,6 +225,10 @@ if (rect == null) { rect = new Rectangle(); } + if (idx < 0 || idx >= displayer.getModel().size()) { + rect.x = rect.y = rect.width = rect.height = 0; + return rect; + } rect.x = layoutModel.getX(idx); rect.y = layoutModel.getY(idx); rect.width = layoutModel.getW(idx); @@ -449,6 +460,11 @@ protected void processMouseWheelEvent(MouseWheelEvent e) { //do nothing } + + public void requestAttention (int tab) { + tabState.addAlarmTab(tab); + } + protected void modelChanged() { tabState.clearTransientStates(); @@ -457,6 +473,7 @@ //sync int idx = selectionModel.getSelectedIndex(); tabState.setSelected(idx); + tabState.pruneAlarmTabs(displayer.getModel().size()); super.modelChanged(); } @@ -501,16 +518,10 @@ } protected void repaintAllTabs() { - getTabsVisibleArea(scratch); - if (scratch.height < displayer.getHeight()) { - //Ensure any gap at the bottom is repainted - scratch.y = 0; - scratch.height = displayer.getHeight(); - } -/* displayer.repaint(scratch.x, scratch.y, scratch.width, - scratch.height); - */ - //XXX optimize this + //XXX would be nicer to just repaint the tabs area, + //but we also need to repaint below all the tabs in the + //event of activated/deactivated. No actual reason to + //repaint the buttons here. displayer.repaint(); } @@ -530,6 +541,10 @@ scratch.height); } } + + protected ModelListener createModelListener() { + return new BasicModelListener(); + } private class BasicDisplayerPropertyChangeListener extends DisplayerPropertyChangeListener { @@ -722,10 +737,43 @@ assert e.getSource() == selectionModel : "Unknown event source: " + e.getSource(); int idx = selectionModel.getSelectedIndex(); - tabState.setSelected(idx); - if (idx != -1) { + tabState.setSelected(idx >= 0 ? idx : -1); + if (idx >= 0) { makeTabVisible (selectionModel.getSelectedIndex()); } } } + + /** + * Listener on data model which will pass modified indices to the + * TabState object, so it can update which tab indices are flashing in + * "attention" mode, if any. + */ + protected class BasicModelListener extends ModelListener { + public void contentsChanged(ListDataEvent e) { + super.contentsChanged(e); + tabState.contentsChanged(e); + } + + public void indicesAdded(ComplexListDataEvent e) { + super.indicesAdded(e); + tabState.indicesAdded(e); + } + + public void indicesChanged(ComplexListDataEvent e) { + tabState.indicesChanged(e); + } + + public void indicesRemoved(ComplexListDataEvent e) { + tabState.indicesRemoved(e); + } + + public void intervalAdded(ListDataEvent e) { + tabState.intervalAdded(e); + } + + public void intervalRemoved(ListDataEvent e) { + tabState.intervalRemoved(e); + } + } } Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabSelectionModel.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabSelectionModel.java,v retrieving revision 1.2 diff -u -u -r1.2 DefaultTabSelectionModel.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabSelectionModel.java 22 Apr 2004 13:09:13 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabSelectionModel.java 9 Sep 2004 23:35:06 -0000 @@ -88,7 +88,7 @@ } private void adjustSelectionForEvent(ListDataEvent e) { - if (e.getType() == e.CONTENTS_CHANGED) { + if (e.getType() == e.CONTENTS_CHANGED || sel == -1) { return; } int start = e.getIndex0(); @@ -140,6 +140,7 @@ } public void indicesAdded(ComplexListDataEvent e) { + if (sel < 0) return; int[] indices = e.getIndices(); java.util.Arrays.sort(indices); int offset = 0; @@ -157,6 +158,7 @@ } public void indicesRemoved(ComplexListDataEvent e) { + if (sel < 0) return; int[] indices = e.getIndices(); java.util.Arrays.sort(indices); int offset = -1; @@ -176,12 +178,13 @@ sel = -1; fireStateChanged(); } else if (offset != 0) { - sel += offset; + sel = Math.max( -1, Math.min (sel + offset, -1)); fireStateChanged(); } } public void indicesChanged(ComplexListDataEvent e) { + if (sel < 0) return; if (e instanceof VeryComplexListDataEvent) { //it always will be ArrayDiff dif = ((VeryComplexListDataEvent) e).getDiff(); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabbedContainerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabbedContainerUI.java,v retrieving revision 1.12 diff -u -u -r1.12 DefaultTabbedContainerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabbedContainerUI.java 11 Aug 2004 17:09:17 -0000 1.12 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/DefaultTabbedContainerUI.java 9 Sep 2004 23:35:08 -0000 @@ -182,8 +182,11 @@ //#41681, #44278, etc. FOCUS related. the UI needs to be the first listener to be notified // that the selection has changed. Otherwise strange focus effects kick in, eg. when the winsys snapshot gets undated beforehand.. tabDisplayer.getSelectionModel().addChangeListener(selectionListener); - - + } + + /** Used by unit tests */ + TabDisplayer getTabDisplayer() { + return tabDisplayer; } /** This method is final. Subclasses which need to provide additional initialization should override @@ -604,6 +607,10 @@ r.x += p.x; r.y += p.y; return r; + } + + public void requestAttention (int tab) { + tabDisplayer.requestAttention (tab); } /** Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/GenericGlowingChiclet.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/GenericGlowingChiclet.java,v retrieving revision 1.2 diff -u -u -r1.2 GenericGlowingChiclet.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/GenericGlowingChiclet.java 22 Apr 2004 13:09:13 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/GenericGlowingChiclet.java 9 Sep 2004 23:35:09 -0000 @@ -34,6 +34,7 @@ public static final int STATE_SELECTED = 2; public static final int STATE_ACTIVE = 4; public static final int STATE_CLOSING = 8; + public static final int STATE_ATTENTION = 16; //Basic apple colors. Package access so that GtkChiclet can install its own //defaults if the GTK classes it proxies for colors are not available or @@ -62,6 +63,10 @@ new Color(255, 238, 220), new Color(238, 137, 109), new Color(255, 50, 50), new Color(255, 237, 40)}; + static Color[] attention = new Color[]{ + new Color(255, 255, 220), new Color(238, 237, 109), + new Color(255, 255, 50), new Color(255, 237, 40)}; + private Color upperTop = selectedActive[0]; private Color upperBottom = selectedActive[1]; private Color lowerTop = selectedActive[2]; @@ -124,6 +129,8 @@ Color[] nue; if ((state & STATE_CLOSING) != 0) { nue = closing; + } else if ((state & STATE_ATTENTION) != 0) { + nue = attention; } else { switch (state) { case STATE_PRESSED | STATE_ACTIVE: Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalEditorTabCellRenderer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalEditorTabCellRenderer.java,v retrieving revision 1.2 diff -u -u -r1.2 MetalEditorTabCellRenderer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalEditorTabCellRenderer.java 22 Apr 2004 13:09:15 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalEditorTabCellRenderer.java 9 Sep 2004 23:35:09 -0000 @@ -31,6 +31,7 @@ private static final MetalRightClippedTabPainter rightBorder = new MetalRightClippedTabPainter(); private static final MetalLeftClippedTabPainter leftBorder = new MetalLeftClippedTabPainter(); + static final Color ATTENTION_COLOR = new Color(255, 238, 120); /** * Creates a new instance of MetalEditorTabCellRenderer */ @@ -129,6 +130,10 @@ public void paintInterior(Graphics g, Component c) { MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c; + if (mtr.isAttention()) { + g.setColor(ATTENTION_COLOR); + } + Polygon p = getInteriorPolygon(c); g.fillPolygon(p); Rectangle r = new Rectangle(); @@ -246,6 +251,11 @@ public void paintInterior(Graphics g, Component c) { Polygon p = getInteriorPolygon(c); + MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c; + if (mtr.isAttention()) { + g.setColor(ATTENTION_COLOR); + } + g.fillPolygon(p); } @@ -340,6 +350,10 @@ public void paintInterior(Graphics g, Component c) { Polygon p = getInteriorPolygon(c); + MetalEditorTabCellRenderer mtr = (MetalEditorTabCellRenderer) c; + if (mtr.isAttention()) { + g.setColor(ATTENTION_COLOR); + } g.fillPolygon(p); } Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalViewTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalViewTabDisplayerUI.java,v retrieving revision 1.9 diff -u -u -r1.9 MetalViewTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalViewTabDisplayerUI.java 1 Sep 2004 15:06:05 -0000 1.9 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/MetalViewTabDisplayerUI.java 9 Sep 2004 23:35:09 -0000 @@ -196,8 +196,12 @@ int width, int height) { boolean selected = isSelected(index); boolean highlighted = selected && isActive(); + boolean attention = isAttention (index); if (highlighted) { g.setColor(getActBgColor()); + g.fillRect(x, y, width, height - 3); + } else if (attention) { + g.setColor(MetalEditorTabCellRenderer.ATTENTION_COLOR); g.fillRect(x, y, width, height - 3); } else { g.setColor(getInactBgColor()); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/TabState.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/TabState.java,v retrieving revision 1.3 diff -u -u -r1.3 TabState.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/TabState.java 9 Sep 2004 00:08:45 -0000 1.3 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/TabState.java 9 Sep 2004 23:35:10 -0000 @@ -12,6 +12,22 @@ */ package org.netbeans.swing.tabcontrol.plaf; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.swing.Timer; +import javax.swing.event.ListDataEvent; +import org.netbeans.swing.tabcontrol.TabData; +import org.netbeans.swing.tabcontrol.event.ArrayDiff; +import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent; +import org.netbeans.swing.tabcontrol.event.VeryComplexListDataEvent; +import org.openide.util.Utilities; + /** * Used by BasicTabDisplayerUI and its subclasses. * Tracks and manages the state of tabs, mainly which one currently contains the @@ -142,7 +158,18 @@ */ public static final int MOUSE_IN_TABS_AREA = 4096; + /** + * Bitmask indicating that the mouse is inside the close button and has + * been pressed. + */ public static final int MOUSE_PRESSED_IN_CLOSE_BUTTON = 8192; + + /** + * Bitmask indicating that the tab is in "attention" mode - blinking or + * flashing to get the user's attention. + */ + public static final int ATTENTION = 16384; + /** * Indicates the last constant defined - renderers that wish to add their * own bitmasks should use multiples of this number @@ -224,6 +251,9 @@ if (tab == selectedIndex - 1) { result |= BEFORE_SELECTED; } + if (isAlarmTab(tab)) { + result |= ATTENTION; + } return result; } @@ -328,6 +358,7 @@ prev = selectedIndex; selectedIndex = i; curr = i; + removeAlarmTab(i); possibleChange(prev, curr, SELECTED); return prev; } @@ -358,6 +389,301 @@ possibleChange(prev, b, ACTIVE); return prev; } + + private boolean isAlarmTab (int tab) { + return attentionToggle && alarmTabs.contains(new Integer(tab)); + } + + private final HashSet alarmTabs = new HashSet(6); + + /** Add a tab to the list of those which should "flash" or otherwise give + * some notification to the user to get their attention */ + public final void addAlarmTab (int alarmTab) { + Integer in = new Integer(alarmTab); + boolean added = alarmTabs.contains(in); + boolean wasEmpty = alarmTabs.isEmpty(); + if (!added) { + alarmTabs.add (new Integer(alarmTab)); + repaintTab (alarmTab); + } + if (wasEmpty) { + startAlarmTimer(); + attentionToggle = true; + repaintTab (alarmTab); + } + } + + /** Remove a tab to the list of those which should "flash" or otherwise give + * some notification to the user to get their attention */ + public final void removeAlarmTab (int alarmTab) { + Integer in = new Integer(alarmTab); + boolean contained = alarmTabs.contains(in); + if (contained) { + alarmTabs.remove(in); + boolean empty = alarmTabs.isEmpty(); + boolean wasAttentionToggled = attentionToggle; + if (alarmTabs.isEmpty()) { + stopAlarmTimer(); + } + if (wasAttentionToggled) { + repaintTab(alarmTab); + } + } + } + + private Timer alarmTimer = null; + private boolean attentionToggle = false; + private final void startAlarmTimer() { + if (alarmTimer == null) { + ActionListener al = new ActionListener() { + public void actionPerformed (ActionEvent ae) { + attentionToggle = !attentionToggle; + Timer timer = (Timer) ae.getSource(); + for (Iterator i=alarmTabs.iterator(); i.hasNext();) { + repaintTab (((Integer) i.next()).intValue()); + } + } + }; + alarmTimer = new Timer (700, al); + alarmTimer.setRepeats(true); + } + alarmTimer.start(); + } + + private final void stopAlarmTimer() { + if (alarmTimer != null && alarmTimer.isRunning()) { + alarmTimer.stop(); + attentionToggle = false; + repaintAllTabs(); //XXX optimize + } + } + + boolean hasAlarmTabs() { + return alarmTabs != null && !alarmTabs.isEmpty(); + } + + void pruneAlarmTabs(int max) { + if (!hasAlarmTabs()) { + return; + } + for (Iterator i=alarmTabs.iterator(); i.hasNext();) { + if (((Integer) i.next()).intValue() >= max) { + i.remove(); + } + } + if (alarmTabs.isEmpty()) { + stopAlarmTimer(); + } + } + + int[] getAlarmTabs() { + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + Arrays.sort(alarms); + return alarms; + } + + //Handling of insertions/deletions where we'll need to update the + //list of blinking tabs here. + void intervalAdded (ListDataEvent evt) { + if (!hasAlarmTabs()) return; + int start = evt.getIndex0(); + int end = evt.getIndex1(); + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + boolean changed = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] >= start) { + alarms[i] += (end - start) + 1; + changed = true; + } + } + if (changed) { + alarmTabs.clear(); + for (int i=0; i < alarms.length; i++) { + addAlarmTab(alarms[i]); + } + } + } + + void intervalRemoved (ListDataEvent evt) { + if (!hasAlarmTabs()) return; + int start = evt.getIndex0(); + int end = evt.getIndex1(); + + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + Arrays.sort(alarms); + + if (end == start) { + //Faster to handle this case separately + boolean changed = true; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] > end) { + alarms[i]--; + } else if (alarms[i] == end) { + alarms[i] = -1; + } + } + if (changed) { + alarmTabs.clear(); + boolean added = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] != -1) { + addAlarmTab(alarms[i]); + added = true; + } + } + if (!added) { + stopAlarmTimer(); + } + } + return; + } + + boolean changed = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] >= start && alarms[i] <= end) { + alarms[i] = -1; + changed = true; + } + } + for (int i=0; i < alarms.length; i++) { + if (alarms[i] > end) { + alarms[i] -= (end - start) + 1; + changed = true; + } + } + if (changed) { + alarmTabs.clear(); + boolean added = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] != -1) { + addAlarmTab(alarms[i]); + added = true; + } + } + if (!added) { + stopAlarmTimer(); + } + } + } + + void indicesAdded (ComplexListDataEvent e) { + if (!hasAlarmTabs()) return; + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + java.util.Arrays.sort(alarms); + + int[] indices = e.getIndices(); + java.util.Arrays.sort(indices); + + boolean changed = false; + for (int i=0; i < indices.length; i++) { + for (int j=0; j < alarms.length; j++) { + if (alarms[j] >= indices[i]) { + alarms[j]++; + changed = true; + } + } + } + if (changed) { + alarmTabs.clear(); + for (int i=0; i < alarms.length; i++) { + if (alarms[i] != -1) { + addAlarmTab(alarms[i]); + } + } + } + } + + void indicesRemoved (ComplexListDataEvent e) { + if (!hasAlarmTabs()) return; + int[] indices = e.getIndices(); + java.util.Arrays.sort(indices); + + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + java.util.Arrays.sort(alarms); + + if (alarms[alarms.length -1] < indices[0]) { + //Some tab removed after the last blinking tab, don't care + return; + } + + boolean changed = false; + for (int i=0; i < alarms.length; i++) { + //First weed out all deleted alarm tabs + for (int j=0; j < indices.length; j++) { + if (alarms[i] == indices[j]) { + alarms[i] = -1; + changed = true; + } + } + } + for (int i=0; i < alarms.length; i++) { + //Now decrement those that remain that are affected + int alarm = alarms[i]; + for (int j=0; j < indices.length; j++) { + if (alarm > indices[j]) { + alarms[i]--; + changed = true; + } + } + } + + if (changed) { + alarmTabs.clear(); + boolean addedSome = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] >= 0) { + addAlarmTab(alarms[i]); + addedSome = true; + } + } + if (!addedSome) { + stopAlarmTimer(); + } + } + + repaintAllTabs(); + } + + void indicesChanged (ComplexListDataEvent e) { + if (!hasAlarmTabs()) return; + if (e instanceof VeryComplexListDataEvent) { //it always will be + VeryComplexListDataEvent ve = (VeryComplexListDataEvent) e; + + ArrayDiff dif = ((VeryComplexListDataEvent) e).getDiff(); + + List old = Arrays.asList(dif.getOldData()); + List nue = Arrays.asList(dif.getNewData()); + + int[] alarms = (int[]) Utilities.toPrimitiveArray((Integer[]) alarmTabs.toArray(new Integer[0])); + + boolean changed = false; + for (int i=0; i < alarms.length; i++) { + Object o = old.get(alarms[i]); + int idx = nue.indexOf(o); + changed |= idx != alarms[i]; + alarms[i] = nue.indexOf(o); + } + if (changed) { + alarmTabs.clear(); + boolean addedSome = false; + for (int i=0; i < alarms.length; i++) { + if (alarms[i] >= 0) { + addAlarmTab(alarms[i]); + addedSome = true; + } + } + if (!addedSome) { + stopAlarmTimer(); + } + } + } + } + + + void contentsChanged(ListDataEvent evt) { + if (!hasAlarmTabs()) return; + //Do nothing, just means some text or icons changed + } //Change types /** Change type indicating no change happened (i.e. calling setSelected() with the same value it was previously @@ -508,6 +834,9 @@ type = ALL_TABS; go = true; } + break; + case ATTENTION: + go = true; } if (go) { if (type == ALL_TABS) { Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/ToolbarTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/ToolbarTabDisplayerUI.java,v retrieving revision 1.1 diff -u -u -r1.1 ToolbarTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/ToolbarTabDisplayerUI.java 15 Jun 2004 00:37:46 -0000 1.1 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/ToolbarTabDisplayerUI.java 9 Sep 2004 23:35:11 -0000 @@ -102,7 +102,11 @@ } } return null; - } + } + + public void requestAttention (int tab) { + //not implemented + } protected ChangeListener createSelectionListener() { return new ChangeListener() { Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicEditorTabCellRenderer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicEditorTabCellRenderer.java,v retrieving revision 1.3 diff -u -u -r1.3 WinClassicEditorTabCellRenderer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicEditorTabCellRenderer.java 5 May 2004 18:50:27 -0000 1.3 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicEditorTabCellRenderer.java 9 Sep 2004 23:35:11 -0000 @@ -31,6 +31,8 @@ private static final TabPainter rightClip = new WinClassicRightClipPainter(); private static final TabPainter normal = new WinClassicPainter(); + static final Color ATTENTION_COLOR = new Color(255, 238, 120); + private static boolean isGenericUI = !"Windows".equals( UIManager.getLookAndFeel().getID()); @@ -135,9 +137,13 @@ ((Graphics2D) g).setPaint(ColorUtil.getGradientPaint(0, 0, getSelGradientColor(), ren.getWidth(), 0, UIManager.getColor( "TabbedPane.background")));//NOI18N } else { - g.setColor(ren.isSelected() ? - UIManager.getColor("TabbedPane.background") : - UIManager.getColor("tab_unsel_fill")); //NOI18N + if (!ren.isAttention()) { + g.setColor(ren.isSelected() ? + UIManager.getColor("TabbedPane.background") : + UIManager.getColor("tab_unsel_fill")); //NOI18N + } else { + g.setColor(ATTENTION_COLOR); + } } Polygon p = getInteriorPolygon(c); g.fillPolygon(p); @@ -260,9 +266,13 @@ ((Graphics2D) g).setPaint(ColorUtil.getGradientPaint(0, 0, getSelGradientColor(), ren.getWidth(), 0, UIManager.getColor( "TabbedPane.background")));//NOI18N } else { - g.setColor(ren.isSelected() ? + if (!ren.isAttention()) { + g.setColor(ren.isSelected() ? UIManager.getColor("TabbedPane.background") : UIManager.getColor("tab_unsel_fill")); //NOI18N + } else { + g.setColor(ATTENTION_COLOR); + } } Polygon p = getInteriorPolygon(c); g.fillPolygon(p); @@ -353,9 +363,13 @@ ((Graphics2D) g).setPaint(ColorUtil.getGradientPaint(0, 0, getSelGradientColor(), ren.getWidth(), 0, UIManager.getColor( "TabbedPane.background")));//NOI18N } else { - g.setColor(ren.isSelected() ? - UIManager.getColor("TabbedPane.background") : + if (!ren.isAttention()) { + g.setColor(ren.isSelected() ? + UIManager.getColor("TabbedPane.background") : //NOI18N UIManager.getColor("tab_unsel_fill")); //NOI18N + } else { + g.setColor(ATTENTION_COLOR); + } } Polygon p = getInteriorPolygon(c); Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicViewTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicViewTabDisplayerUI.java,v retrieving revision 1.10 diff -u -u -r1.10 WinClassicViewTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicViewTabDisplayerUI.java 2 Sep 2004 13:43:09 -0000 1.10 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinClassicViewTabDisplayerUI.java 9 Sep 2004 23:35:12 -0000 @@ -228,6 +228,8 @@ // background body, colored according to state boolean selected = isSelected(index); boolean focused = isFocused(index); + boolean attention = isAttention(index); + Paint result = null; if (focused) { result = @@ -238,6 +240,8 @@ "TabbedPane.background")); } else if (selected) { result = UIManager.getColor("TabbedPane.background"); //NOI18N + } else if (attention) { + result = WinClassicEditorTabCellRenderer.ATTENTION_COLOR; } else { result = UIManager.getColor("tab_unsel_fill"); } Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPEditorTabCellRenderer.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPEditorTabCellRenderer.java,v retrieving revision 1.2 diff -u -u -r1.2 WinXPEditorTabCellRenderer.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPEditorTabCellRenderer.java 22 Apr 2004 13:09:18 -0000 1.2 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPEditorTabCellRenderer.java 9 Sep 2004 23:35:13 -0000 @@ -252,7 +252,13 @@ private static final Paint getPaint(int xTop, int yTop, int xBot, int yBot, WinXPEditorTabCellRenderer ren) { - if (ren.isSelected() || (ren.isPressed() && !ren.inCloseButton())) { + + if (!ren.isSelected() && !ren.isPressed() && ren.isAttention()) { + Color a = new Color (255, 255, 128); + Color b = new Color (230, 200, 64); + return ColorUtil.getGradientPaint(xTop, yTop, a, xBot, + yBot, b); + } else if (ren.isSelected() || (ren.isPressed() && !ren.inCloseButton())) { if (ren.isActive()) { return ColorUtil.getGradientPaint(xTop, yTop, getTopActiveSelectedColor(), Index: core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPViewTabDisplayerUI.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPViewTabDisplayerUI.java,v retrieving revision 1.8 diff -u -u -r1.8 WinXPViewTabDisplayerUI.java --- core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPViewTabDisplayerUI.java 1 Sep 2004 15:06:05 -0000 1.8 +++ core/swing/tabcontrol/src/org/netbeans/swing/tabcontrol/plaf/WinXPViewTabDisplayerUI.java 9 Sep 2004 23:35:14 -0000 @@ -190,12 +190,18 @@ // background body, colored according to state boolean selected = isSelected(index); boolean focused = selected && isActive(); + boolean attention = isAttention(index); if (focused) { ColorUtil.xpFillRectGradient((Graphics2D) g, x, y, width, height, focusFillBrightC, focusFillDarkC); } else if (selected && isMoreThanOne()) { g.setColor(selFillC); g.fillRect(x, y, width, height); + } else if (attention && !selected) { + Color a = new Color (255, 255, 128); + Color b = new Color (230, 200, 64); + ColorUtil.xpFillRectGradient((Graphics2D) g, x, y, width, height, + a, b); } else { ColorUtil.xpFillRectGradient((Graphics2D) g, x, y, width, height, unselFillBrightC, unselFillDarkC); Index: core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/DataModelTest.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/DataModelTest.java,v retrieving revision 1.2 diff -u -u -r1.2 DataModelTest.java --- core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/DataModelTest.java 22 Apr 2004 13:09:27 -0000 1.2 +++ core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/DataModelTest.java 9 Sep 2004 23:35:14 -0000 @@ -200,8 +200,8 @@ public void doTestRemoveContiguous() { System.err.println("testRemoveContiguous"); int formerSize = mdl.size(); - mdl.removeTabs (10, 20); - int expectedSize=formerSize-10; + mdl.removeTabs (10, 19); + int expectedSize=formerSize - 10; assertPravda (mdl.size() == expectedSize, "Model size should be " + expectedSize + " after removing 10 items, but is " + mdl.size()); try { _testContentsValid(); Index: core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/AttentionAndModelChangesTest.java =================================================================== RCS file: core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/AttentionAndModelChangesTest.java diff -N core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/AttentionAndModelChangesTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/AttentionAndModelChangesTest.java 9 Sep 2004 23:35:15 -0000 @@ -0,0 +1,554 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.swing.tabcontrol.plaf; + +import java.awt.BorderLayout; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import junit.framework.*; +import org.netbeans.swing.tabcontrol.DefaultTabDataModel; +import org.netbeans.swing.tabcontrol.TabData; +import org.netbeans.swing.tabcontrol.TabDataModel; +import org.netbeans.swing.tabcontrol.TabDisplayer; +import org.netbeans.swing.tabcontrol.TabbedContainer; + +/** + * TabState stores a list of tabs which are blinking for attention. + * They are stored by index. This test ensures that when tabs are added + * or removed from the model, that the indices are updated correctly. + *

+ * This test also exercises the data model heavily. + * + * @author Tim Boudreau + */ +public class AttentionAndModelChangesTest extends TestCase { + + public AttentionAndModelChangesTest(java.lang.String testName) { + super(testName); + } + + public static Test suite() { + TestSuite suite = new TestSuite(AttentionAndModelChangesTest.class); + return suite; + } + + TabDataModel mdl = null; + TabData[] origData = null; + TabState state = null; + TabDisplayer displayer = null; + TabbedContainer tab = null; + public void setUp() { + origData = new TabData[13]; + for (int i=0; i < origData.length; i++) { + origData[i] = new TabData(new JLabel("TD " + i), null, "TD " + i, "tip"); + } + + mdl = new DefaultTabDataModel(origData); + + tab = new TabbedContainer(mdl, TabbedContainer.TYPE_EDITOR); + tab.setActive(true); + JFrame jf = new JFrame(); + jf.getContentPane().setLayout (new BorderLayout()); + jf.getContentPane().add (tab, BorderLayout.CENTER); + jf.setBounds (20, 20, 400, 200); + jf.show(); + jf.toFront(); + while (!jf.isShowing()) { + try { + Thread.currentThread().sleep(50); + } catch (InterruptedException e) { + fail (e.toString()); + } + } + displayer = ((DefaultTabbedContainerUI) tab.getUI()).getTabDisplayer(); + BasicTabDisplayerUI ui = (BasicTabDisplayerUI) displayer.getUI(); + state = ui.getTabState(); + } + + private void requestAttention (final int i) throws Exception { + SwingUtilities.invokeAndWait (new Runnable() { + public void run() { + tab.requestAttention(i); + } + }); + } + + private void assertAtt (final int[] i) throws Exception { + Arrays.sort (i); + int[] att = state.getAlarmTabs(); + assertTrue ("Expected attention tabs to be " + + a2s(i) + " but they are " + a2s(att), + Arrays.equals(i, att)); + } + + private void assertNotAtt (final int[] i) throws Exception { + SwingUtilities.invokeAndWait (new Runnable() { + public void run() { + Arrays.sort (i); + int[] att = state.getAlarmTabs(); + assertFalse ("Expected attention tabs NOT to be " + + a2s(i) + " but they are " + a2s(att), + Arrays.equals(i, att)); + } + }); + } + + private static String a2s (int[] ints) { + if (ints == null) { + return "null"; + } + if (ints.length == 0) { + return "[]"; + } + StringBuffer sb = new StringBuffer(); + for (int i=0; i < ints.length; i++) { + sb.append (ints[i]); + if (i != ints.length -1) { + sb.append(','); + } + } + return sb.toString(); + } + + public void testRequestAttention () throws Exception { + System.out.println("testRequestAttention"); + requestAttention (3); + requestAttention (5); + assertAtt(new int[] {3, 5}); + } + + public void testRemoveSingleInBetween() throws Exception { + System.out.println("testRemoveSingleInBetween"); + requestAttention(3); + requestAttention(5); + mdl.removeTab(4); + assertAtt(new int[] {3, 4}); + } + + public void testRemoveSingleBefore() throws Exception { + System.out.println("testRemoveSingleBefore"); + requestAttention(3); + requestAttention(5); + mdl.removeTab(2); + assertAtt(new int[] {2, 4}); + } + + + public void testRemoveSingleAfter() throws Exception { + System.out.println("testRemoveSingleAfter"); + requestAttention(3); + requestAttention(5); + mdl.removeTab(6); + assertAtt(new int[] {3, 5}); + mdl.removeTab(10); + assertAtt(new int[] {3, 5}); + } + + public void testRemoveSingleFirst() throws Exception { + System.out.println("testRemoveSingleFirst"); + requestAttention(3); + requestAttention(5); + mdl.removeTab(3); + assertAtt(new int[] {4}); + } + + + public void testRemoveSingleSecond() throws Exception { + System.out.println("testRemoveSingleSecond"); + requestAttention(3); + requestAttention(5); + mdl.removeTab(5); + assertAtt(new int[] {3}); + } + + public void testAddSingleBefore() throws Exception { + System.out.println("testAddSingleBefore"); + requestAttention(3); + requestAttention(5); + TabData td = new TabData (new JLabel("Added"), null, "Added", "tip"); + mdl.addTab(1, td); + assertAtt(new int[] {4, 6}); + } + + public void testAddSingleBetween() throws Exception { + System.out.println("testAddSingleBetween"); + requestAttention(3); + requestAttention(5); + TabData td = new TabData (new JLabel("Added"), null, "Added", "tip"); + mdl.addTab(4, td); + assertAtt(new int[] {3, 6}); + } + + public void testAddSingleAt() throws Exception { + System.out.println("testAddSingleAt"); + requestAttention(3); + requestAttention(5); + TabData td = new TabData (new JLabel("Added"), null, "Added", "tip"); + mdl.addTab(3, td); + assertAtt(new int[] {4, 6}); + } + + public void testAddSingleAfter() throws Exception { + System.out.println("testAddSingleAfter"); + requestAttention(3); + requestAttention(5); + TabData td = new TabData (new JLabel("Added"), null, "Added", "tip"); + mdl.addTab(7, td); + assertAtt(new int[] {3, 5}); + } + + public void testAddSingleAtEnd() throws Exception { + System.out.println("testAddSingleAtEnd"); + requestAttention(3); + requestAttention(5); + TabData td = new TabData (new JLabel("Added"), null, "Added", "tip"); + mdl.addTab(5, td); + assertAtt(new int[] {3, 6}); + } + + public void testAddMultipleBefore() throws Exception { + System.out.println("testAddMultipleBefore"); + requestAttention(3); + requestAttention(5); + TabData att1 = mdl.getTab(3); + TabData att2 = mdl.getTab(5); + + TabData td1 = new TabData (new JLabel("Added 1"), null, "Added 1", "tip"); + TabData td2 = new TabData (new JLabel("Added 2"), null, "Added 2", "tip"); + mdl.addTabs(1, new TabData[] {td1, td2}); + assertAtt(new int[] {5, 7}); + + int[] tabs = state.getAlarmTabs(); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + + public void testAddMultipleAfter() throws Exception { + System.out.println("testAddMultipleAfter"); + requestAttention(3); + requestAttention(5); + TabData td1 = new TabData (new JLabel("Added 1"), null, "Added 1", "tip"); + TabData td2 = new TabData (new JLabel("Added 2"), null, "Added 2", "tip"); + mdl.addTabs(7, new TabData[] {td1, td2}); + assertAtt(new int[] {3, 5}); + } + + public void testAddMultipleBetween() throws Exception { + System.out.println("testAddMultipleBetween"); + requestAttention(3); + requestAttention(5); + TabData att1 = mdl.getTab(3); + TabData att2 = mdl.getTab(5); + + TabData td1 = new TabData (new JLabel("Added 1"), null, "Added 1", "tip"); + TabData td2 = new TabData (new JLabel("Added 2"), null, "Added 2", "tip"); + mdl.addTabs(4, new TabData[] {td1, td2}); + assertAtt(new int[] {3, 7}); + + int[] tabs = state.getAlarmTabs(); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + + public void testRemoveMultipleBetween() throws Exception { + System.out.println("testRemoveMultipleBetween"); + requestAttention(3); + requestAttention(6); + TabData att1 = mdl.getTab(3); + TabData att2 = mdl.getTab(6); + + int sz = mdl.size(); + mdl.removeTabs(4, 5); + assertTrue ("After removing tabs 4 and 5, model size should be 2 smaller - was " + sz + " is " + mdl.size(), mdl.size() == sz-2); + + assertAtt (new int[] {3, 4}); + + int[] tabs = state.getAlarmTabs(); + System.out.println("Alarm tabs are " + tabs[0] + "," + tabs[1]); + System.err.println("First attention tab " + mdl.getTab(tabs[0])); + System.err.println("Second attention tab " + mdl.getTab(tabs[1])); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + public void testRemoveMultipleBefore() throws Exception { + System.out.println("testRemoveMultipleBefore"); + requestAttention(3); + requestAttention(6); + TabData att1 = mdl.getTab(3); + TabData att2 = mdl.getTab(6); + int sz = mdl.size(); + + mdl.removeTabs(1, 2); + + assertTrue ("After removing tabs 1 and 2, model size should be 2 smaller - was " + sz + " is " + mdl.size(), mdl.size() == sz-2); + assertAtt (new int[] {1, 4}); + + int[] tabs = state.getAlarmTabs(); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + public void testRemoveMultipleAfter() throws Exception { + System.out.println("testRemoveMultipleAfter"); + requestAttention(3); + requestAttention(6); + mdl.removeTabs(7, 10); + assertAtt (new int[] {3, 6}); + } + + public void testRemoveMultipleIncluding() throws Exception { + System.out.println("testRemoveMultipleIncluding"); + requestAttention(3); + requestAttention(6); + mdl.removeTabs(6, 10); + assertAtt (new int[] {3}); + } + + public void testRemoveMultipleInclusive() throws Exception { + System.out.println("testRemoveMultipleInclusive"); + requestAttention(3); + requestAttention(6); + mdl.removeTabs(2, 7); + assertAtt (new int[0]); + } + + public void testAddDiscontiguousBefore() throws Exception { + System.out.println("testAddDiscontiguousBefore"); + requestAttention(7); + requestAttention(9); + TabData td1 = new TabData (new JLabel("Added 1"), null, "Added 1", "tip"); + TabData td2 = new TabData (new JLabel("Added 2"), null, "Added 2", "tip"); + TabData td3 = new TabData (new JLabel("Added 3"), null, "Added 3", "tip"); + mdl.addTabs (new int[] { 1, 3, 5}, new TabData[] {td1, td2, td3}); + assertAtt (new int[] {10, 12}); + } + + public void testRemoveDiscontiguousBefore() throws Exception { + System.out.println("testRemoveDiscontiguousBefore"); + requestAttention(7); + requestAttention(9); + mdl.removeTabs (new int[] {1,3,5}); + assertAtt (new int[] {4, 6}); + } + + public void testRemoveDiscontiguousAfter() throws Exception { + System.out.println("testRemoveDiscontiguousAfter"); + requestAttention(5); + requestAttention(7); + mdl.removeTabs (new int[] {8,10,11}); + assertAtt (new int[] {5, 7}); + } + + + public void testAddDiscontiguousBeforeAndBetween() throws Exception { + System.out.println("testAddDiscontiguousBeforeAndBetween"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + + TabData td1 = new TabData (new JLabel("Added 1"), null, "Added 1", "tip"); + TabData td2 = new TabData (new JLabel("Added 2"), null, "Added 2", "tip"); + TabData td3 = new TabData (new JLabel("Added 3"), null, "Added 3", "tip"); + mdl.addTabs (new int[] {1, 3, 8}, new TabData[] {td1, td2, td3}); + assertAtt (new int[] {10, 12}); + + int[] tabs = state.getAlarmTabs(); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + public void testRemoveDiscontiguousBeforeAndBetween() throws Exception { + System.out.println("testRemoveDiscontiguousBeforeAndBetween"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + mdl.removeTabs (new int[] {1,3,8}); + assertAtt (new int[] {5, 6}); + int[] tabs = state.getAlarmTabs(); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + public void testRemoveDiscontiguousBeforeAndBetweenIncludingOne() throws Exception { + System.out.println("testRemoveDiscontiguousBeforeAndBetweenIncludingOne"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + mdl.removeTabs (new int[] {1,3,7}); + assertAtt (new int[] {6}); + } + + public void testReorderComplex() throws Exception { + System.out.println("testReorderComplex"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + + TabData[] data = (TabData[]) mdl.getTabs().toArray(new TabData[mdl.size()]); + TabData[] nue = new TabData[data.length]; + for (int i=data.length-1; i >=0; i--) { + nue [data.length-(i+1)] = data[i]; + } + mdl.setTabs(nue); + int[] tabs = state.getAlarmTabs(); + Arrays.sort(tabs); + assertSame ("First attention tab should be " + att2 + " not " + mdl.getTab(tabs[0]), att2, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att1 + " not " + mdl.getTab(tabs[1]), att1, mdl.getTab(tabs[1])); + } + + public void testReplaceComplex() throws Exception { + System.out.println("testReplaceComplex"); + requestAttention(7); + requestAttention(9); + + TabData[] data = (TabData[]) mdl.getTabs().toArray(new TabData[mdl.size()]); + data[7] = new TabData (new JLabel("foo"), null, "foo", "foo"); + mdl.setTabs(data); + + assertAtt(new int[] {9}); + + data[9] = new TabData (new JLabel("goo"), null, "goo", "goo"); + mdl.setTabs(data); + assertAtt(new int[0]); + } + + public void testRemoveComplex() throws Exception { + System.out.println("testRemoveComplex"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + + TabData[] data = (TabData[]) mdl.getTabs().toArray(new TabData[mdl.size()]); + TabData[] nue = new TabData[data.length-1]; + int ct = 0; + for (int i=0; i < data.length; i++) { + nue [ct] = data[i]; + if (i != 7) { + ct++; + } + } + mdl.setTabs(nue); + int[] tabs = state.getAlarmTabs(); + + assertTrue (tabs.length ==1); + assertTrue (tabs[0] == 8); + assertSame (mdl.getTab(tabs[0]), att2); + } + + + public void testAddComplex() throws Exception { + System.out.println("testAddComplex"); + requestAttention(7); + requestAttention(9); + TabData att1 = mdl.getTab(7); + TabData att2 = mdl.getTab(9); + + TabData[] data = (TabData[]) mdl.getTabs().toArray(new TabData[mdl.size()]); + + ArrayList al = new ArrayList (Arrays.asList(data)); + al.add (8, new TabData(new JLabel("boo"), null, "boo", "boo")); + al.add (2, new TabData(new JLabel("moo"), null, "moo", "moo")); + + TabData[] nue = (TabData[]) al.toArray(new TabData[0]); + + mdl.setTabs(nue); + int[] tabs = state.getAlarmTabs(); + Arrays.sort(tabs); + assertSame ("First attention tab should be " + att1 + " not " + mdl.getTab(tabs[0]), att1, mdl.getTab(tabs[0])); + assertSame ("Second attention tab should be " + att2 + " not " + mdl.getTab(tabs[1]), att2, mdl.getTab(tabs[1])); + } + + //Make sure (non)exceptional case of only 1 tab works + + private void makeSingle() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + TabData[] td = new TabData[] { + new TabData (new JLabel("Single"), null, "single", "single") + }; + mdl.setTabs(td); + state.addAlarmTab(0); + assertTrue (state.getAlarmTabs().length == 1); + } + }); + Thread.currentThread().sleep(50); + } + + public void testHandleSingle1() throws Exception { + System.out.println("testHandleSingle1"); + makeSingle(); + + mdl.removeTab(0); + assertAtt (new int[0]); + } + + public void testHandleSingle2() throws Exception { + System.out.println("testHandleSingle2"); + makeSingle(); + mdl.removeTabs(0, 0); + assertAtt (new int[0]); + } + + public void testHandleSingle3() throws Exception { + System.out.println("testHandleSingle3"); + makeSingle(); + mdl.removeTabs(new int[] {0}); + assertAtt (new int[0]); + } + + public void testAddSingle1() throws Exception { + System.out.println("testAddSingle1"); + makeSingle(); + mdl.addTab(0, new TabData(new JLabel("foo"), null, "foo", "foo")); + assertTrue ("Size should be 2", mdl.size() == 2); + assertAtt(new int[] {1}); + } + + public void testAddSingle2() throws Exception { + System.out.println("testAddSingle2"); + makeSingle(); + mdl.addTabs(0, new TabData[] {new TabData(new JLabel("foo"), null, "foo", "foo")}); + assertTrue ("Size should be 2", mdl.size() == 2); + assertAtt(new int[] {1}); + } + + public void testAddSingle3() throws Exception { + System.out.println("testAddSingle3"); + makeSingle(); + mdl.addTabs(new int[] {0}, new TabData[] {new TabData(new JLabel("foo"), null, "foo", "foo")}); + assertTrue ("Size should be 2", mdl.size() == 2); + assertAtt(new int[] {1}); + } + + public void testAddSingle4() throws Exception { + System.out.println("testAddSingle4"); + makeSingle(); + mdl.addTabs(new int[] {1}, new TabData[] {new TabData(new JLabel("foo"), null, "foo", "foo")}); + assertTrue ("Size should be 2", mdl.size() == 2); + assertAtt(new int[] {0}); + } +} Index: core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/TabStateTest.java =================================================================== RCS file: /cvs/core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/TabStateTest.java,v retrieving revision 1.2 diff -u -u -r1.2 TabStateTest.java --- core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/TabStateTest.java 22 Apr 2004 13:09:28 -0000 1.2 +++ core/swing/tabcontrol/test/unit/src/org/netbeans/swing/tabcontrol/plaf/TabStateTest.java 9 Sep 2004 23:35:16 -0000 @@ -323,11 +323,4 @@ } private int policy = 0; - - - // TODO add test methods here, they have to start with 'test' name. - // for example: - // public void testHello() {} - - }