diff --git a/core.multiview/src/org/netbeans/core/multiview/ContextAwareDescription.java b/core.multiview/src/org/netbeans/core/multiview/ContextAwareDescription.java --- a/core.multiview/src/org/netbeans/core/multiview/ContextAwareDescription.java +++ b/core.multiview/src/org/netbeans/core/multiview/ContextAwareDescription.java @@ -51,5 +51,6 @@ */ @MimeLocation(subfolderName="MultiView") public interface ContextAwareDescription extends MultiViewDescription { - public ContextAwareDescription createContextAwareDescription(Lookup context); + public ContextAwareDescription createContextAwareDescription(Lookup context, boolean isSplitDescription); + public boolean isSplitDescription(); } diff --git a/core.multiview/src/org/netbeans/core/multiview/EditorsAction.java b/core.multiview/src/org/netbeans/core/multiview/EditorsAction.java --- a/core.multiview/src/org/netbeans/core/multiview/EditorsAction.java +++ b/core.multiview/src/org/netbeans/core/multiview/EditorsAction.java @@ -142,8 +142,10 @@ if (thisPers.getDisplayName().equals(handler.getSelectedPerspective().getDisplayName())) { item.setSelected(true); } - group.add(item); - add(item); + if (!((ContextAwareDescription) Accessor.DEFAULT.extractDescription(thisPers)).isSplitDescription()) { + group.add(item); + add(item); + } } } else { // handler == null //No reason to enable action on any TC because now it was enabled even for Welcome page diff --git a/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java b/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java @@ -106,7 +106,7 @@ private void setDeserializedMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc, Map existingElements) { - peer.setDeserializedMultiViewDescriptions(descriptions, defaultDesc, existingElements); + peer.setDeserializedMultiViewDescriptions(-1, descriptions, defaultDesc, null, existingElements); } MultiViewModel getModel() { @@ -173,9 +173,10 @@ Action[] superActions = super.getActions(); Action[] acts = peer.peerGetActions(superActions); - Action[] myActions = new Action[acts.length + 2]; + Action[] myActions = new Action[acts.length + 3]; System.arraycopy(acts, 0, myActions, 0, acts.length); myActions[acts.length + 1] = new EditorsAction(); + myActions[acts.length + 2] = new SplitAction(true); return myActions; } @@ -198,11 +199,25 @@ @Override protected CloneableTopComponent createClonedObject() { MultiViewCloneableTopComponent tc = new MultiViewCloneableTopComponent(); - tc.setMultiViewDescriptions(peer.model.getDescriptions(), peer.model.getActiveDescription());; + tc.setMultiViewDescriptions(peer.model.getDescriptions(), peer.model.getActiveDescription()); tc.setCloseOperationHandler(peer.closeHandler); tc.peer.copyMimeContext(peer); return tc; } + + public TopComponent splitComponent(int orientation) { + peer.peerSplitComponent(orientation); + return this; + } + + public TopComponent clearSplit() { + peer.peerClearSplit(); + return this; + } + + public int getSplitOrientation() { + return peer.getSplitOrientation(); + } /** Serialize this top component. * Subclasses wishing to store state must call the super method, then write to the stream. diff --git a/core.multiview/src/org/netbeans/core/multiview/MultiViewModel.java b/core.multiview/src/org/netbeans/core/multiview/MultiViewModel.java --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewModel.java +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewModel.java @@ -73,6 +73,7 @@ // private Map nestedPerspectiveComponents; //key=description, value mull or perspectiveComponent private MultiViewDescription[] descriptions; private ButtonGroup group; + private ButtonGroup groupSplit; private Collection shownElements; private ArrayList listeners; private ActionRequestObserverFactory observerFactory; @@ -108,6 +109,7 @@ } currentEditor = (defaultDescr == null || !nestedElements.containsKey(defaultDescr) ? descriptions[0] : defaultDescr); group = new BtnGroup(); + groupSplit = new BtnGroup(); } @@ -196,6 +198,13 @@ return group; } + /** + * The button group where the togglebuttons for the split descriptions are put into. + */ + ButtonGroup getButtonGroupSplit() { + return groupSplit; + } + MultiViewElement getElementForDescription(MultiViewDescription description) { return getElementForDescription(description, true); } diff --git a/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java b/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java @@ -71,6 +71,7 @@ import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JEditorPane; +import javax.swing.JSplitPane; import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -130,6 +131,7 @@ private final PreferenceChangeListener editorSettingsListener = new PreferenceChangeListenerImpl(); private final PropertyChangeListener propListener; private DelegateUndoRedo delegateUndoRedo; + private int splitOrientation = -1; MultiViewPeer(TopComponent pr, ActionRequestObserverFactory fact) { selListener = new SelectionListener(); @@ -152,7 +154,9 @@ List arr = new ArrayList(); final Lookup lkp = MimeLookup.getLookup(mimeType); for (ContextAwareDescription d : lkp.lookupAll(ContextAwareDescription.class)) { - d = d.createContextAwareDescription(context.getLookup()); + d = d.createContextAwareDescription(context.getLookup(), false); + arr.add(d); + d = d.createContextAwareDescription(context.getLookup(), true); arr.add(d); } if (arr.isEmpty()) { @@ -187,14 +191,21 @@ closeHandler = handler; } - void setDeserializedMultiViewDescriptions(MultiViewDescription[] descriptions, - MultiViewDescription defaultDesc, Map existingElements) { + void setDeserializedMultiViewDescriptions(int splitOrientation, MultiViewDescription[] descriptions, + MultiViewDescription defaultDesc, MultiViewDescription defaultDescSplit, Map existingElements) { if (model != null) { model.removeElementSelectionListener(selListener); } + // if Design view was active before closing, set default to Source view + defaultDesc = defaultDesc.getDisplayName().startsWith("&Design") ? descriptions[0] : defaultDesc; //NOI18N + defaultDescSplit = defaultDescSplit.getDisplayName().startsWith("&Design") ? descriptions[1] : defaultDescSplit; //NOI18N model = new MultiViewModel(descriptions, defaultDesc, factory, existingElements); model.addElementSelectionListener(selListener); - tabs.setModel(model); + tabs.setModel(model); + this.splitOrientation = splitOrientation; + if(splitOrientation != -1) { + tabs.peerSplitComponent(splitOrientation, this, defaultDesc, defaultDescSplit); + } } /** @@ -257,6 +268,47 @@ } }); } + if(peer instanceof MultiViewTopComponent || peer instanceof MultiViewCloneableTopComponent) { + delegatingMap.put("splitWindowHorizantally", new javax.swing.AbstractAction() { // NOI18N + @Override + public void actionPerformed(ActionEvent evt) { + TopComponent split; + if(peer instanceof MultiViewTopComponent || peer instanceof MultiViewCloneableTopComponent) { + split = ((MultiViewTopComponent) peer).splitComponent(JSplitPane.HORIZONTAL_SPLIT); + } else { + split = ((MultiViewCloneableTopComponent) peer).splitComponent(JSplitPane.HORIZONTAL_SPLIT); + } + split.open(); + split.requestActive(); + } + }); + delegatingMap.put("splitWindowVertically", new javax.swing.AbstractAction() { // NOI18N + @Override + public void actionPerformed(ActionEvent evt) { + TopComponent split; + if(peer instanceof MultiViewTopComponent || peer instanceof MultiViewCloneableTopComponent) { + split = ((MultiViewTopComponent) peer).splitComponent(JSplitPane.VERTICAL_SPLIT); + } else { + split = ((MultiViewCloneableTopComponent) peer).splitComponent(JSplitPane.VERTICAL_SPLIT); + } + split.open(); + split.requestActive(); + } + }); + delegatingMap.put("clearSplit", new javax.swing.AbstractAction() { // NOI18N + @Override + public void actionPerformed(ActionEvent evt) { + TopComponent original; + if(peer instanceof MultiViewTopComponent || peer instanceof MultiViewCloneableTopComponent) { + original = ((MultiViewTopComponent) peer).clearSplit(); + } else { + original = ((MultiViewCloneableTopComponent) peer).clearSplit(); + } + original.open(); + original.requestActive(); + } + }); + } delegatingMap.put("closeWindow", new javax.swing.AbstractAction() { // NOI18N public void actionPerformed(ActionEvent evt) { peer.close(); @@ -283,7 +335,7 @@ JComponent jc = el.getToolbarRepresentation(); assert jc != null : "MultiViewElement " + el.getClass() + " returns null as toolbar component."; //NOI18N jc.setOpaque(false); - tabs.setInnerToolBar(jc); + tabs.setInnerToolBar(jc, ((ContextAwareDescription)model.getActiveDescription()).isSplitDescription()); tabs.setToolbarBarVisible(isToolbarVisible()); if (editorSettingsPreferences != null) { editorSettingsPreferences.addPreferenceChangeListener(editorSettingsListener); @@ -315,6 +367,22 @@ showCurrentElement(true); tabs.setToolbarBarVisible(isToolbarVisible()); } + + void peerSplitComponent(int orientation) { + splitOrientation = orientation; + tabs.peerSplitComponent(orientation, this, null, null); + } + + void peerClearSplit() { + tabs.peerClearSplit(); + showCurrentElement(); + model.fireActivateCurrent(); + splitOrientation = -1; + } + + int getSplitOrientation() { + return splitOrientation; + } boolean requestFocusInWindow() { // somehow this may be called when model is null @@ -335,6 +403,17 @@ * hides the old element when switching elements. */ void hideElement(MultiViewDescription desc) { + if (desc != null && splitOrientation != -1) { + MultiViewDescription topDesc = tabs.getTopComponentDescription(); + MultiViewDescription bottomDesc = tabs.getBottomComponentDescription(); + if (tabs.isHiddenTriggeredByMultiViewButton() + && (!topDesc.getDisplayName().equals(desc.getDisplayName()) + || !bottomDesc.getDisplayName().equals(desc.getDisplayName()))) { + MultiViewElement el = model.getElementForDescription(desc); + el.componentHidden(); + } + return; + } if (desc != null) { MultiViewElement el = model.getElementForDescription(desc); el.componentHidden(); @@ -358,7 +437,7 @@ // also consider a usecase where multiple elements point to a single visual component. //. eg. property sheet uses same component and only changes model. // in this case we probably should not remove and add the component from awt hierarchy - tabs.switchToCard(el, desc.getDisplayName()); + tabs.switchToCard(el, desc.getDisplayName(), ((ContextAwareDescription)desc).isSplitDescription()); Image icon = desc.getIcon(); if( null == icon ) { //#204072 @@ -389,7 +468,7 @@ assignLookup(el); if (peer.isVisible()) { - tabs.setInnerToolBar(el.getToolbarRepresentation()); + tabs.setInnerToolBar(el.getToolbarRepresentation(), ((ContextAwareDescription)desc).isSplitDescription()); tabs.setToolbarBarVisible(isToolbarVisible()); } @@ -508,8 +587,11 @@ fromMime = false; } MultiViewDescription[] descs = model.getDescriptions(); - MultiViewDescription curr = model.getActiveDescription(); + MultiViewDescription curr = tabs.getTopComponentDescription(); + MultiViewDescription currSplit = tabs.getBottomComponentDescription(); int currIndex = 0; + int currIndexSplit = 0; + for (int i = 0; i < descs.length; i++) { if (!fromMime) { out.writeObject(descs[i]); @@ -526,8 +608,13 @@ if (descs[i] == curr) { currIndex = i; } + if (descs[i] == currSplit) { + currIndexSplit = i; + } } out.writeObject(new Integer(currIndex)); + out.writeObject(new Integer(currIndexSplit)); + out.writeObject(new Integer(splitOrientation)); } @@ -539,9 +626,12 @@ ArrayList descList = new ArrayList(); HashMap map = new HashMap(); int current = 0; + int currentSplit = 0; + int splitOrient = -1; CloseOperationHandler close = null; try { int counting = 0; + int intCounting = 0; MultiViewDescription lastDescription = null; while (true) { Object obj = in.readObject(); @@ -576,8 +666,16 @@ } else if (obj instanceof Integer) { Integer integ = (Integer)obj; - current = integ.intValue(); - break; + if(intCounting == 0) { + intCounting++; + current = integ.intValue(); + } else if (intCounting == 1) { + intCounting++; + currentSplit = integ.intValue(); + } else if (intCounting == 2) { + splitOrient = integ.intValue(); + break; + } } if (obj instanceof CloseOperationHandler) { close = (CloseOperationHandler)obj; @@ -597,10 +695,11 @@ descs = descList.toArray(descs); //the integer with current element was not read yet, fallback to zero. MultiViewDescription currDesc = descs[0]; + MultiViewDescription currDescSplit = descs[1]; //when error, ignore any deserialized elements.. map.clear(); - setDeserializedMultiViewDescriptions(descs, currDesc, map); + setDeserializedMultiViewDescriptions(1, descs, currDesc, currDescSplit, map); } throw exc; @@ -616,7 +715,8 @@ MultiViewDescription[] descs = new MultiViewDescription[descList.size()]; descs = descList.toArray(descs); MultiViewDescription currDesc = descs[current]; - setDeserializedMultiViewDescriptions(descs, currDesc, map); + MultiViewDescription currDescSplit = descs[currentSplit]; + setDeserializedMultiViewDescriptions(splitOrient, descs, currDesc, currDescSplit, map); } private Action[] getDefaultTCActions() { diff --git a/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java b/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java @@ -101,7 +101,7 @@ private void setDeserializedMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc, Map existingElements) { - peer.setDeserializedMultiViewDescriptions(descriptions, defaultDesc, existingElements); + peer.setDeserializedMultiViewDescriptions(-1, descriptions, defaultDesc, null, existingElements); } MultiViewModel getModel() { @@ -161,9 +161,10 @@ //TEMP don't delegate to element's actions.. Action[] superActions = superActions4Tests == null ? super.getActions() : superActions4Tests; Action[] acts = peer.peerGetActions(superActions); - Action[] myActions = new Action[acts.length + 2]; + Action[] myActions = new Action[acts.length + 3]; System.arraycopy(acts, 0, myActions, 0, acts.length); myActions[acts.length + 1] = new EditorsAction(); + myActions[acts.length + 2] = new SplitAction(true); return myActions; } @@ -292,16 +293,34 @@ SubComponent[] res = new SubComponent[perspectives.length]; for( int i=0; i alreadyAddedElements; + private Set alreadyAddedElementsSplit; private JToolBar bar; + private JToolBar barSplit; + + private JSplitPane splitPane; + private AWTEventListener awtEventListener; + private boolean isTopLeft = true; + private JPanel topLeftComponent; + private JPanel bottomRightComponent; + private Dimension barMinSize; + private Dimension panelMinSizep; + private MultiViewDescription[] topBottomDescriptions = null; + private PropertyChangeListener splitterPropertyChangeListener; + private boolean removeSplit = false; + private MultiViewPeer mvPeer; + private boolean hiddenTriggeredByMultiViewButton = false; private static final boolean AQUA = "Aqua".equals(UIManager.getLookAndFeel().getID()); //NOI18N @@ -124,17 +144,18 @@ int prefHeight = -1; int prefWidth = -1; for (int i = 0; i < descs.length; i++) { - JToggleButton button = createButton(descs[i]); - model.getButtonGroup().add(button); - GridBagConstraints cons = new GridBagConstraints(); - cons.anchor = GridBagConstraints.WEST; - prefHeight = Math.max(button.getPreferredSize().height, prefHeight); - bar.add(button, cons); - prefWidth = Math.max(button.getPreferredSize().width, prefWidth); - if (descs[i] == model.getActiveDescription()) { - active = button; - - } + if (descs[i] instanceof ContextAwareDescription && !((ContextAwareDescription)descs[i]).isSplitDescription()) { + JToggleButton button = createButton(descs[i]); + model.getButtonGroup().add(button); + GridBagConstraints cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.WEST; + prefHeight = Math.max(button.getPreferredSize().height, prefHeight); + bar.add(button, cons); + prefWidth = Math.max(button.getPreferredSize().width, prefWidth); + if (descs[i] == model.getActiveDescription()) { + active = button; + } + } } Enumeration en = model.getButtonGroup().getElements(); while (en.hasMoreElements()) { @@ -158,7 +179,296 @@ } - void switchToCard(MultiViewElement elem, String id) { + MultiViewDescription getTopComponentDescription() { + return topBottomDescriptions == null ? model.getActiveDescription() : topBottomDescriptions[0]; + } + + MultiViewDescription getBottomComponentDescription() { + return topBottomDescriptions == null ? model.getActiveDescription() : topBottomDescriptions[1]; + } + + void peerClearSplit() { + MultiViewDescription activeDescription = topBottomDescriptions[0]; + Toolkit.getDefaultToolkit().removeAWTEventListener(getAWTEventListener()); + splitPane.removePropertyChangeListener(splitterPropertyChangeListener); + removeAll(); + splitPane = null; + topBottomDescriptions = null; + isTopLeft = true; + topLeftComponent = null; + bottomRightComponent = null; + alreadyAddedElementsSplit = null; + awtEventListener = null; + barSplit = null; + cardLayoutSplit = null; + componentPanelSplit = null; + toolbarPanelSplit = null; + splitterPropertyChangeListener = null; + mvPeer = null; + + add(bar, BorderLayout.NORTH); + add(componentPanel, BorderLayout.CENTER); + model.setActiveDescription(activeDescription); + } + + private void setupSplit() { + topLeftComponent = new JPanel(new BorderLayout()); + barMinSize = bar.getMinimumSize(); + panelMinSizep = componentPanel.getMinimumSize(); + topLeftComponent.add(bar, BorderLayout.NORTH); + topLeftComponent.add(componentPanel, BorderLayout.CENTER); + + bottomRightComponent = new JPanel(); + barSplit = new JToolBar(); + Border b = (Border)UIManager.get("Nb.Editor.Toolbar.border"); //NOI18N + barSplit.setBorder(b); + barSplit.setFloatable(false); + barSplit.setFocusable(true); + if( "Windows".equals( UIManager.getLookAndFeel().getID()) + && !isXPTheme()) { + barSplit.setRollover(true); + } else if( AQUA ) { + barSplit.setBackground(UIManager.getColor("NbExplorerView.background")); + } + + bottomRightComponent.setLayout(new BorderLayout()); + bottomRightComponent.add(barSplit, BorderLayout.NORTH); + startTogglingSplit(); + setToolbarBarVisibleSplit(bar.isVisible()); + + componentPanelSplit = new JPanel(); + cardLayoutSplit = new CardLayout(); + componentPanelSplit.setLayout(cardLayoutSplit); + bottomRightComponent.add(componentPanelSplit, BorderLayout.CENTER); + alreadyAddedElementsSplit = new HashSet(); + + MultiViewDescription[] descs = model.getDescriptions(); + MultiViewDescription def = model.getActiveDescription(); + GridBagLayout grid = new GridBagLayout(); + barSplit.setLayout(grid); + JToggleButton activeSplit = null; + int prefHeight = -1; + int prefWidth = -1; + for (int i = 0; i < descs.length; i++) { + if (descs[i] instanceof ContextAwareDescription && ((ContextAwareDescription)descs[i]).isSplitDescription()) { + JToggleButton button = createButton(descs[i]); + model.getButtonGroupSplit().add(button); + GridBagConstraints cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.WEST; + prefHeight = Math.max(button.getPreferredSize().height, prefHeight); + barSplit.add(button, cons); + prefWidth = Math.max(button.getPreferredSize().width, prefWidth); + if (descs[i].getDisplayName().startsWith(def.getDisplayName())) { + activeSplit = button; + } + } + } + Enumeration en = model.getButtonGroupSplit().getElements(); + while (en.hasMoreElements()) { + JToggleButton but = (JToggleButton)en.nextElement(); + Insets ins = but.getBorder().getBorderInsets(but); + but.setPreferredSize(new Dimension(prefWidth + 10, prefHeight)); + but.setMinimumSize(new Dimension(prefWidth + 10, prefHeight)); + + } + if (activeSplit != null) { + activeSplit.setSelected(true); + } + + toolbarPanelSplit = getEmptyInnerToolBar(); + GridBagConstraints cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.EAST; + cons.fill = GridBagConstraints.BOTH; + cons.gridwidth = GridBagConstraints.REMAINDER; + cons.weightx = 1; + + barSplit.add(toolbarPanelSplit, cons); + } + + void peerSplitComponent(int orientation, MultiViewPeer mvPeer, MultiViewDescription defaultDesc, MultiViewDescription defaultDescClone) { + MultiViewDescription[] descriptions = model.getDescriptions(); + this.mvPeer = mvPeer; + + MultiViewDescription activeDescription = model.getActiveDescription(); + if (splitPane == null) { + splitPane = new JSplitPane(); + topBottomDescriptions = new MultiViewDescription[2]; + if (defaultDesc != null && defaultDescClone != null) {// called during deserialization + topBottomDescriptions[0] = defaultDesc; + topBottomDescriptions[1] = defaultDescClone; + } else { + int activeDescIndex = 0; + for (int i = 0; i < descriptions.length; i++) { + MultiViewDescription multiViewDescription = descriptions[i]; + if (multiViewDescription.getDisplayName().equals(activeDescription.getDisplayName())) { + activeDescIndex = i; + break; + } + } + topBottomDescriptions[0] = descriptions[activeDescIndex]; + topBottomDescriptions[1] = descriptions[activeDescIndex + 1]; + } + + setupSplit(); + splitPane.setOneTouchExpandable(true); + splitPane.setContinuousLayout(true); + splitPane.setResizeWeight(0.5); + + removeAll(); + Toolkit.getDefaultToolkit().addAWTEventListener(getAWTEventListener(), MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); + add(splitPane, BorderLayout.CENTER); + + + MultiViewDescription bottomDescription = topBottomDescriptions[1]; + isTopLeft = false; + model.setActiveDescription(bottomDescription); + if (defaultDesc != null && defaultDescClone != null) {// called during deserialization + selecteAppropriateButton(); + } + + MultiViewDescription topDescription = topBottomDescriptions[0]; + isTopLeft = true; + model.setActiveDescription(topDescription); + if (defaultDesc != null && defaultDescClone != null) {// called during deserialization + selecteAppropriateButton(); + } + } else { + topLeftComponent = (JPanel) splitPane.getTopComponent(); + bottomRightComponent = (JPanel) splitPane.getBottomComponent(); + } + if(orientation != splitPane.getOrientation()) { + splitPane.removePropertyChangeListener(splitterPropertyChangeListener); + splitterPropertyChangeListener = null; + } + splitPane.setOrientation(orientation); + splitPane.setTopComponent(topLeftComponent); + splitPane.setBottomComponent(bottomRightComponent); + splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, getSplitterPropertyChangeListener(orientation)); + topLeftComponent.setMinimumSize(new Dimension(0, 0)); + bottomRightComponent.setMinimumSize(new Dimension(0, 0)); + } + + private void selecteAppropriateButton() { + Enumeration en = model.getButtonGroupSplit().getElements(); + while (en.hasMoreElements()) { + JToggleButton but = (JToggleButton) en.nextElement(); + MultiViewDescription buttonsDescription = ((TabsButtonModel) but.getModel()).getButtonsDescription(); + if (buttonsDescription == (isTopLeft ? topBottomDescriptions[0] : topBottomDescriptions[1])) { + but.setSelected(true); + } + } + } + + private PropertyChangeListener getSplitterPropertyChangeListener(final int orientation) { + if (splitterPropertyChangeListener == null) { + splitterPropertyChangeListener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent pce) { + if (splitPane != null) { + int current = Integer.parseInt(pce.getNewValue().toString()); + int dividerSize = splitPane.getDividerSize(); + int splitSize; + int topMinSize; + int bottomMinSize; + if (orientation == JSplitPane.VERTICAL_SPLIT) { + splitSize = splitPane.getHeight(); + topMinSize = (int) topLeftComponent.getMinimumSize().getHeight(); + bottomMinSize = (int) bottomRightComponent.getMinimumSize().getHeight(); + } else { + splitSize = splitPane.getWidth(); + topMinSize = (int) topLeftComponent.getMinimumSize().getWidth(); + bottomMinSize = (int) bottomRightComponent.getMinimumSize().getWidth(); + } + int min = topMinSize; + int max = splitSize - bottomMinSize - dividerSize; + if (current <= min || current >= max) { + removeSplit = true; + } else { + removeSplit = false; + } + } + } + }; + } + return splitterPropertyChangeListener; + } + + + @NbBundle.Messages({"LBL_ClearAllSplitsDialogMessage=Do you really want to clear the split?", + "LBL_ClearAllSplitsDialogTitle=Clear Split"}) + private AWTEventListener getAWTEventListener() { + if (awtEventListener == null) { + awtEventListener = new AWTEventListener() { + @Override + public void eventDispatched(AWTEvent event) { + MouseEvent e = (MouseEvent) event; + if (splitPane != null && e.getID() == MouseEvent.MOUSE_PRESSED) { + MultiViewDescription activeDescription = null; + Point locationOnScreen = e.getLocationOnScreen(); + SwingUtilities.convertPointFromScreen(locationOnScreen, splitPane); + Component component = e.getComponent(); + while(component != null && component != splitPane) { + component = component.getParent(); + } + if (component == splitPane && splitPane.getTopComponent().getBounds().contains(locationOnScreen)) { + isTopLeft = true; + activeDescription = topBottomDescriptions[0]; + } else if (component == splitPane && splitPane.getBottomComponent().getBounds().contains(locationOnScreen)) { + isTopLeft = false; + activeDescription = topBottomDescriptions[1]; + } + if (activeDescription != null) { + if (!model.getActiveDescription().equals(activeDescription) || + ((ContextAwareDescription)model.getActiveDescription()).isSplitDescription() != ((ContextAwareDescription)activeDescription).isSplitDescription()) { + model.setActiveDescription(activeDescription); + } + } + } else if (splitPane != null && e.getID() == MouseEvent.MOUSE_RELEASED) { + if (removeSplit) { + if (e.getClickCount() != 0) { + return; + } + if (mvPeer != null) { + mvPeer.peerClearSplit(); + bar.setMinimumSize(barMinSize); + componentPanel.setMinimumSize(panelMinSizep); + } + removeSplit = false; + } + } + } + }; + } + return awtEventListener; + } + + private void changeSplitOrientation(int orientation) { + splitPane.removePropertyChangeListener(splitterPropertyChangeListener); + splitterPropertyChangeListener = null; + splitPane.setOrientation(orientation); + splitPane.setDividerLocation(0.5); + splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, getSplitterPropertyChangeListener(orientation)); + } + + boolean isHiddenTriggeredByMultiViewButton() { + return hiddenTriggeredByMultiViewButton; + } + + boolean isShowing(MultiViewDescription descr) { + if(descr == null) { + return false; + } + if(splitPane == null) { + return model.getActiveDescription() == descr; + } + return isTopLeft ? topBottomDescriptions[1] == descr : topBottomDescriptions[0] == descr; + } + + void switchToCard(MultiViewElement elem, String id, boolean isSplitElement) { + if (isSplitElement) { + switchToCardSplit(elem, id); + return; + } if (! alreadyAddedElements.contains(elem)) { componentPanel.add(elem.getVisualRepresentation(), id); alreadyAddedElements.add(elem); @@ -166,6 +476,14 @@ cardLayout.show(componentPanel, id); } + private void switchToCardSplit(MultiViewElement elem, String id) { + if (!alreadyAddedElementsSplit.contains(elem)) { + componentPanelSplit.add(elem.getVisualRepresentation(), id); + alreadyAddedElementsSplit.add(elem); + } + cardLayoutSplit.show(componentPanelSplit, id); + } + /** Part of 130919 fix - don't hold visual representations after close */ void peerComponentClosed() { if (componentPanel != null) { @@ -174,19 +492,44 @@ if (alreadyAddedElements != null) { alreadyAddedElements.clear(); } + if (componentPanelSplit != null) { + componentPanelSplit.removeAll(); + } + if (alreadyAddedElementsSplit != null) { + alreadyAddedElementsSplit.clear(); + } } void changeActiveManually(MultiViewDescription desc) { Enumeration en = model.getButtonGroup().getElements(); + MultiViewDescription activeDescription = model.getActiveDescription(); + if (((ContextAwareDescription) activeDescription).isSplitDescription()) { + en = model.getButtonGroupSplit().getElements(); + } while (en.hasMoreElements()) { JToggleButton obj = (JToggleButton)en.nextElement(); if (obj.getModel() instanceof TabsComponent.TabsButtonModel) { TabsButtonModel btnmodel = (TabsButtonModel)obj.getModel(); - if (btnmodel.getButtonsDescription().equals(desc)) { - obj.setSelected(true); - MultiViewElement elem = model.getElementForDescription(desc); - elem.getVisualRepresentation().requestFocus(); + if (btnmodel.getButtonsDescription().getDisplayName().equals(desc.getDisplayName())) { + if (splitPane != null) { + TabsComponent.this.hiddenTriggeredByMultiViewButton = true; + if (((ContextAwareDescription) activeDescription).isSplitDescription()) { + model.getButtonGroupSplit().setSelected(obj.getModel(), true); + TabsComponent.this.isTopLeft = false; + TabsComponent.this.topBottomDescriptions[1] = btnmodel.getButtonsDescription(); + } else { + model.getButtonGroup().setSelected(obj.getModel(), true); + TabsComponent.this.isTopLeft = true; + TabsComponent.this.topBottomDescriptions[0] = btnmodel.getButtonsDescription(); + } + model.fireActivateCurrent(); + TabsComponent.this.hiddenTriggeredByMultiViewButton = false; + } else { + obj.setSelected(true); + MultiViewElement elem = model.getElementForDescription(desc); + elem.getVisualRepresentation().requestFocus(); + } break; } } @@ -195,6 +538,10 @@ void changeVisibleManually(MultiViewDescription desc) { Enumeration en = model.getButtonGroup().getElements(); + if (((ContextAwareDescription) model.getActiveDescription()).isSplitDescription()) { + en = model.getButtonGroupSplit().getElements(); + desc = model.getActiveDescription(); + } while (en.hasMoreElements()) { JToggleButton obj = (JToggleButton)en.nextElement(); @@ -232,7 +579,11 @@ return button; } - void setInnerToolBar(JComponent innerbar) { + void setInnerToolBar(JComponent innerbar, boolean isSplitElement) { + if (isSplitElement) { + setInnerToolBarSplit(innerbar); + return; + } synchronized (getTreeLock()) { if (toolbarPanel != null) { bar.remove(toolbarPanel); @@ -264,6 +615,39 @@ bar.repaint(); } } + + private void setInnerToolBarSplit(JComponent innerbar) { + synchronized (getTreeLock()) { + if (toolbarPanelSplit != null) { + barSplit.remove(toolbarPanelSplit); + } + if (innerbar == null) { + innerbar = getEmptyInnerToolBar(); + } + innerbar.putClientProperty(TOOLBAR_MARKER, "X"); //NOI18N + // need to set it to null, because CloneableEditor set's the border for the editor bar part only.. + if (!AQUA) { + innerbar.setBorder(null); + } else { + innerbar.setBorder (BorderFactory.createEmptyBorder(2, 0, 2, 0)); + } + toolbarPanelSplit = innerbar; + GridBagConstraints cons = new GridBagConstraints(); + cons.anchor = GridBagConstraints.EAST; + cons.fill = GridBagConstraints.BOTH; + cons.gridwidth = GridBagConstraints.REMAINDER; + cons.weightx = 1; + toolbarPanelSplit.setMinimumSize(new Dimension(10, 10)); +// cons.gridwidth = GridBagConstraints.REMAINDER; + + barSplit.add(toolbarPanelSplit, cons); + + // rootcycle is the tabscomponent.. +// toolbarPanel.setFocusCycleRoot(false); + barSplit.revalidate(); + barSplit.repaint(); + } + } void setToolbarBarVisible(boolean visible) { if (toolbarVisible == visible) { @@ -272,6 +656,14 @@ toolbarVisible = visible; bar.setVisible(visible); } + + void setToolbarBarVisibleSplit(boolean visible) { + if (toolbarVisible == visible) { + return; + } + toolbarVisible = visible; + barSplit.setVisible(visible); + } @@ -338,6 +730,25 @@ input.put(stroke, "TogglesGoDown");//NOI18N } + void startTogglingSplit() { + ActionMap map = barSplit.getActionMap(); + Action act = new TogglesGoEastAction(); + // JToolbar action name + map.put("navigateRight", act);//NOI18N + InputMap input = barSplit.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + act = new TogglesGoWestAction(); + // JToolbar action name + map.put("navigateLeft", act);//NOI18N + + act = new TogglesGoDownAction(); + map.put("TogglesGoDown", act);//NOI18N + // JToolbar action name + map.put("navigateUp", act);//NOI18N + KeyStroke stroke = KeyStroke.getKeyStroke("ESCAPE"); //NOI18N + input.put(stroke, "TogglesGoDown");//NOI18N + } + private class TogglesGoWestAction extends AbstractAction { @@ -421,6 +832,25 @@ AbstractButton b = (AbstractButton)e.getComponent(); MultiViewModel model = TabsComponent.this.model; if (model != null) { + if (TabsComponent.this.splitPane != null) { + ButtonModel buttonModel = b.getModel(); + if (buttonModel instanceof TabsButtonModel) { + MultiViewDescription buttonsDescription = ((TabsButtonModel) buttonModel).getButtonsDescription(); + TabsComponent.this.hiddenTriggeredByMultiViewButton = true; + if(((ContextAwareDescription)buttonsDescription).isSplitDescription()) { + model.getButtonGroupSplit().setSelected(b.getModel(), true); + TabsComponent.this.isTopLeft = false; + TabsComponent.this.topBottomDescriptions[1] = buttonsDescription; + } else { + model.getButtonGroup().setSelected(b.getModel(), true); + TabsComponent.this.isTopLeft = true; + TabsComponent.this.topBottomDescriptions[0] = buttonsDescription; + } + model.fireActivateCurrent(); + TabsComponent.this.hiddenTriggeredByMultiViewButton = false; + } + return; + } model.getButtonGroup().setSelected(b.getModel(), true); model.fireActivateCurrent(); } diff --git a/core.multiview/src/org/netbeans/core/multiview/resources/mf-layer.xml b/core.multiview/src/org/netbeans/core/multiview/resources/mf-layer.xml --- a/core.multiview/src/org/netbeans/core/multiview/resources/mf-layer.xml +++ b/core.multiview/src/org/netbeans/core/multiview/resources/mf-layer.xml @@ -43,7 +43,7 @@ Version 2 license, then the option applies only if the new code is made subject to such option by the copyright holder. --> - + @@ -51,7 +51,23 @@ + + + + + + + + + + + + + + + +