Merge with default on May 25, 2011 multiview-registration-196810
authorJaroslav Tulach <jtulach@netbeans.org>
Wed, 25 May 2011 16:50:33 +0200
branchmultiview-registration-196810
changeset 199886fb50e84d55e8
parent 199259 4e4e0eea6cb1
parent 199885 1447c0424318
child 199887 c9752bf56e87
Merge with default on May 25, 2011
core.multiview/src/org/netbeans/core/spi/multiview/MultiViewCloneableEditor.java
     1.1 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml	Wed May 25 16:24:45 2011 +0200
     1.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml	Wed May 25 16:50:33 2011 +0200
     1.3 @@ -218,6 +218,9 @@
     1.4              <file name="templateDataNode.java" url="../wizard/loader/templateDataNode.javx"/>
     1.5              <file name="templateDataObject.java" url="../wizard/loader/templateDataObject.javx"/>
     1.6              <file name="templateDataObjectWithLookup.java" url="../wizard/loader/templateDataObjectWithLookup.javx"/>
     1.7 +            <file name="templateDataObjectMulti.java" url="../wizard/loader/templateDataObjectMulti.javx"/>
     1.8 +            <file name="templateDataObjectMultiForm.java" url="../wizard/loader/templateDataObjectMultiVisual.javx"/>
     1.9 +            <file name="templateDataObjectMultiForm.form" url="../wizard/loader/templateDataObjectMultiVisual.forx"/>
    1.10              <file name="templateDataObjectInLayer.java" url="../wizard/loader/templateDataObjectInLayer.javx"/>
    1.11              <file name="templateNew1" url="../wizard/loader/templateNew1"/>
    1.12              <file name="templateNew2" url="../wizard/loader/templateNew2"/>
     2.1 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/Bundle.properties	Wed May 25 16:24:45 2011 +0200
     2.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/Bundle.properties	Wed May 25 16:50:33 2011 +0200
     2.3 @@ -67,7 +67,7 @@
     2.4  LBL_CreatedFiles=&Created Files\:
     2.5  LBL_ModifiedFiles=&Modified Files\:
     2.6  LBL_Icon_Browse=Bro&wse...
     2.7 -LBL_Icon=&Icon\:
     2.8 +LBL_Icon=&Icon:
     2.9  LBL_Prefix=Class &Name Prefix\:
    2.10  LBL_Select=Select
    2.11  ERR_Name_Prefix_Empty=Please specify Class Name Prefix.
     3.1 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NameAndLocationPanel.form	Wed May 25 16:24:45 2011 +0200
     3.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NameAndLocationPanel.form	Wed May 25 16:50:33 2011 +0200
     3.3 @@ -1,9 +1,10 @@
     3.4 -<?xml version="1.0" encoding="UTF-8" ?>
     3.5 +<?xml version="1.1" encoding="UTF-8" ?>
     3.6  
     3.7  <Form version="1.2" maxVersion="1.2" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
     3.8    <AuxValues>
     3.9      <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
    3.10      <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
    3.11 +    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
    3.12      <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
    3.13      <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
    3.14      <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
    3.15 @@ -36,21 +37,6 @@
    3.16          </Constraint>
    3.17        </Constraints>
    3.18      </Component>
    3.19 -    <Component class="javax.swing.JLabel" name="lblIcon">
    3.20 -      <Properties>
    3.21 -        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
    3.22 -          <ComponentRef name="txtIcon"/>
    3.23 -        </Property>
    3.24 -        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
    3.25 -          <ResourceString bundle="org/netbeans/modules/apisupport/project/ui/wizard/loader/Bundle.properties" key="LBL_Icon" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
    3.26 -        </Property>
    3.27 -      </Properties>
    3.28 -      <Constraints>
    3.29 -        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.30 -          <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
    3.31 -        </Constraint>
    3.32 -      </Constraints>
    3.33 -    </Component>
    3.34      <Component class="javax.swing.JTextField" name="txtIcon">
    3.35        <Constraints>
    3.36          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.37 @@ -84,7 +70,7 @@
    3.38        </Properties>
    3.39        <Constraints>
    3.40          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.41 -          <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="18" insetsLeft="0" insetsBottom="6" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
    3.42 +          <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="18" insetsLeft="0" insetsBottom="6" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
    3.43          </Constraint>
    3.44        </Constraints>
    3.45      </Component>
    3.46 @@ -97,7 +83,7 @@
    3.47        </AuxValues>
    3.48        <Constraints>
    3.49          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.50 -          <GridBagConstraints gridX="1" gridY="2" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="18" insetsLeft="0" insetsBottom="6" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
    3.51 +          <GridBagConstraints gridX="1" gridY="3" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="18" insetsLeft="0" insetsBottom="6" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
    3.52          </Constraint>
    3.53        </Constraints>
    3.54      </Component>
    3.55 @@ -112,7 +98,7 @@
    3.56        </Properties>
    3.57        <Constraints>
    3.58          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.59 -          <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
    3.60 +          <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
    3.61          </Constraint>
    3.62        </Constraints>
    3.63      </Component>
    3.64 @@ -128,7 +114,7 @@
    3.65        </AuxValues>
    3.66        <Constraints>
    3.67          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.68 -          <GridBagConstraints gridX="1" gridY="3" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
    3.69 +          <GridBagConstraints gridX="1" gridY="4" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
    3.70          </Constraint>
    3.71        </Constraints>
    3.72      </Component>
    3.73 @@ -143,7 +129,7 @@
    3.74        </Properties>
    3.75        <Constraints>
    3.76          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.77 -          <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="36" insetsLeft="0" insetsBottom="6" insetsRight="12" anchor="18" weightX="0.0" weightY="0.0"/>
    3.78 +          <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="36" insetsLeft="0" insetsBottom="6" insetsRight="12" anchor="18" weightX="0.0" weightY="0.0"/>
    3.79          </Constraint>
    3.80        </Constraints>
    3.81      </Component>
    3.82 @@ -158,14 +144,14 @@
    3.83        </Properties>
    3.84        <Constraints>
    3.85          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.86 -          <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="18" weightX="0.0" weightY="0.0"/>
    3.87 +          <GridBagConstraints gridX="0" gridY="6" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="18" weightX="0.0" weightY="0.0"/>
    3.88          </Constraint>
    3.89        </Constraints>
    3.90      </Component>
    3.91      <Component class="javax.swing.JLabel" name="filler">
    3.92        <Constraints>
    3.93          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
    3.94 -          <GridBagConstraints gridX="0" gridY="6" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
    3.95 +          <GridBagConstraints gridX="0" gridY="7" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
    3.96          </Constraint>
    3.97        </Constraints>
    3.98      </Component>
    3.99 @@ -183,7 +169,7 @@
   3.100        </Properties>
   3.101        <Constraints>
   3.102          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.103 -          <GridBagConstraints gridX="1" gridY="4" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="36" insetsLeft="0" insetsBottom="6" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
   3.104 +          <GridBagConstraints gridX="1" gridY="5" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="36" insetsLeft="0" insetsBottom="6" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
   3.105          </Constraint>
   3.106        </Constraints>
   3.107      </Component>
   3.108 @@ -202,7 +188,32 @@
   3.109        </Properties>
   3.110        <Constraints>
   3.111          <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.112 -          <GridBagConstraints gridX="1" gridY="5" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
   3.113 +          <GridBagConstraints gridX="1" gridY="6" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
   3.114 +        </Constraint>
   3.115 +      </Constraints>
   3.116 +    </Component>
   3.117 +    <Component class="javax.swing.JLabel" name="lblIcon2">
   3.118 +      <Properties>
   3.119 +        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
   3.120 +          <ComponentRef name="txtIcon"/>
   3.121 +        </Property>
   3.122 +        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
   3.123 +          <ResourceString bundle="org/netbeans/modules/apisupport/project/ui/wizard/loader/Bundle.properties" key="LBL_Icon" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
   3.124 +        </Property>
   3.125 +      </Properties>
   3.126 +      <Constraints>
   3.127 +        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.128 +          <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="10" weightX="0.0" weightY="0.0"/>
   3.129 +        </Constraint>
   3.130 +      </Constraints>
   3.131 +    </Component>
   3.132 +    <Component class="javax.swing.JCheckBox" name="useMultiView">
   3.133 +      <Properties>
   3.134 +        <Property name="text" type="java.lang.String" value="&amp;Use MultiView"/>
   3.135 +      </Properties>
   3.136 +      <Constraints>
   3.137 +        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
   3.138 +          <GridBagConstraints gridX="1" gridY="2" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
   3.139          </Constraint>
   3.140        </Constraints>
   3.141      </Component>
     4.1 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NameAndLocationPanel.java	Wed May 25 16:24:45 2011 +0200
     4.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NameAndLocationPanel.java	Wed May 25 16:50:33 2011 +0200
     4.3 @@ -88,6 +88,14 @@
     4.4              JTextField txt = (JTextField)comPackageName.getEditor().getEditorComponent();
     4.5              txt.getDocument().addDocumentListener(dListener);
     4.6          }
     4.7 +        
     4.8 +        if (data.canUseMultiview()) {
     4.9 +            useMultiView.setEnabled(true);
    4.10 +            useMultiView.setSelected(true);
    4.11 +        } else {
    4.12 +            useMultiView.setEnabled(false);
    4.13 +            useMultiView.setSelected(false);
    4.14 +        }
    4.15      }
    4.16      
    4.17      protected void storeToDataModel() {
    4.18 @@ -99,6 +107,7 @@
    4.19          String icon = txtIcon.getText().trim();
    4.20          data.setIconPath(icon.length() == 0 ? (String)null : icon);
    4.21          data.setPrefix(txtPrefix.getText().trim());
    4.22 +        data.setUseMultiview(useMultiView.isSelected());
    4.23          NewLoaderIterator.generateFileChanges(data);
    4.24          createdFilesValue.setText(UIUtil.generateTextAreaContent(
    4.25                  data.getCreatedModifiedFiles().getCreatedPaths()));
    4.26 @@ -172,13 +181,12 @@
    4.27       * WARNING: Do NOT modify this code. The content of this method is
    4.28       * always regenerated by the Form Editor.
    4.29       */
    4.30 -    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    4.31 +    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    4.32      private void initComponents() {
    4.33          java.awt.GridBagConstraints gridBagConstraints;
    4.34  
    4.35          lblPrefix = new javax.swing.JLabel();
    4.36          txtPrefix = new javax.swing.JTextField();
    4.37 -        lblIcon = new javax.swing.JLabel();
    4.38          txtIcon = new javax.swing.JTextField();
    4.39          btnIcon = new javax.swing.JButton();
    4.40          lblProjectName = new javax.swing.JLabel();
    4.41 @@ -190,18 +198,19 @@
    4.42          filler = new javax.swing.JLabel();
    4.43          createdFilesValue = new javax.swing.JTextArea();
    4.44          modifiedFilesValue = new javax.swing.JTextArea();
    4.45 +        lblIcon2 = new javax.swing.JLabel();
    4.46 +        useMultiView = new javax.swing.JCheckBox();
    4.47  
    4.48          setLayout(new java.awt.GridBagLayout());
    4.49  
    4.50          lblPrefix.setLabelFor(txtPrefix);
    4.51 -        org.openide.awt.Mnemonics.setLocalizedText(lblPrefix, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Prefix"));
    4.52 +        org.openide.awt.Mnemonics.setLocalizedText(lblPrefix, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Prefix")); // NOI18N
    4.53          gridBagConstraints = new java.awt.GridBagConstraints();
    4.54          gridBagConstraints.gridx = 0;
    4.55          gridBagConstraints.gridy = 0;
    4.56          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    4.57          gridBagConstraints.insets = new java.awt.Insets(1, 0, 6, 12);
    4.58          add(lblPrefix, gridBagConstraints);
    4.59 -
    4.60          gridBagConstraints = new java.awt.GridBagConstraints();
    4.61          gridBagConstraints.gridx = 1;
    4.62          gridBagConstraints.gridy = 0;
    4.63 @@ -210,16 +219,6 @@
    4.64          gridBagConstraints.weightx = 1.0;
    4.65          gridBagConstraints.insets = new java.awt.Insets(1, 0, 6, 0);
    4.66          add(txtPrefix, gridBagConstraints);
    4.67 -
    4.68 -        lblIcon.setLabelFor(txtIcon);
    4.69 -        org.openide.awt.Mnemonics.setLocalizedText(lblIcon, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Icon"));
    4.70 -        gridBagConstraints = new java.awt.GridBagConstraints();
    4.71 -        gridBagConstraints.gridx = 0;
    4.72 -        gridBagConstraints.gridy = 1;
    4.73 -        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    4.74 -        gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
    4.75 -        add(lblIcon, gridBagConstraints);
    4.76 -
    4.77          gridBagConstraints = new java.awt.GridBagConstraints();
    4.78          gridBagConstraints.gridx = 1;
    4.79          gridBagConstraints.gridy = 1;
    4.80 @@ -227,13 +226,12 @@
    4.81          gridBagConstraints.weightx = 1.0;
    4.82          add(txtIcon, gridBagConstraints);
    4.83  
    4.84 -        org.openide.awt.Mnemonics.setLocalizedText(btnIcon, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Icon_Browse"));
    4.85 +        org.openide.awt.Mnemonics.setLocalizedText(btnIcon, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Icon_Browse")); // NOI18N
    4.86          btnIcon.addActionListener(new java.awt.event.ActionListener() {
    4.87              public void actionPerformed(java.awt.event.ActionEvent evt) {
    4.88                  btnIconActionPerformed(evt);
    4.89              }
    4.90          });
    4.91 -
    4.92          gridBagConstraints = new java.awt.GridBagConstraints();
    4.93          gridBagConstraints.gridx = 2;
    4.94          gridBagConstraints.gridy = 1;
    4.95 @@ -241,10 +239,11 @@
    4.96          add(btnIcon, gridBagConstraints);
    4.97  
    4.98          lblProjectName.setLabelFor(txtProjectName);
    4.99 -        org.openide.awt.Mnemonics.setLocalizedText(lblProjectName, java.util.ResourceBundle.getBundle("org/netbeans/modules/apisupport/project/ui/wizard/librarydescriptor/Bundle").getString("LBL_ProjectName"));
   4.100 +        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/netbeans/modules/apisupport/project/ui/wizard/librarydescriptor/Bundle"); // NOI18N
   4.101 +        org.openide.awt.Mnemonics.setLocalizedText(lblProjectName, bundle.getString("LBL_ProjectName")); // NOI18N
   4.102          gridBagConstraints = new java.awt.GridBagConstraints();
   4.103          gridBagConstraints.gridx = 0;
   4.104 -        gridBagConstraints.gridy = 2;
   4.105 +        gridBagConstraints.gridy = 3;
   4.106          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.107          gridBagConstraints.insets = new java.awt.Insets(18, 0, 6, 12);
   4.108          add(lblProjectName, gridBagConstraints);
   4.109 @@ -252,7 +251,7 @@
   4.110          txtProjectName.setEditable(false);
   4.111          gridBagConstraints = new java.awt.GridBagConstraints();
   4.112          gridBagConstraints.gridx = 1;
   4.113 -        gridBagConstraints.gridy = 2;
   4.114 +        gridBagConstraints.gridy = 3;
   4.115          gridBagConstraints.gridwidth = 2;
   4.116          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.117          gridBagConstraints.weightx = 1.0;
   4.118 @@ -260,10 +259,10 @@
   4.119          add(txtProjectName, gridBagConstraints);
   4.120  
   4.121          lblPackageName.setLabelFor(comPackageName);
   4.122 -        org.openide.awt.Mnemonics.setLocalizedText(lblPackageName, java.util.ResourceBundle.getBundle("org/netbeans/modules/apisupport/project/ui/wizard/librarydescriptor/Bundle").getString("LBL_PackageName"));
   4.123 +        org.openide.awt.Mnemonics.setLocalizedText(lblPackageName, bundle.getString("LBL_PackageName")); // NOI18N
   4.124          gridBagConstraints = new java.awt.GridBagConstraints();
   4.125          gridBagConstraints.gridx = 0;
   4.126 -        gridBagConstraints.gridy = 3;
   4.127 +        gridBagConstraints.gridy = 4;
   4.128          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.129          gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
   4.130          add(lblPackageName, gridBagConstraints);
   4.131 @@ -271,35 +270,34 @@
   4.132          comPackageName.setEditable(true);
   4.133          gridBagConstraints = new java.awt.GridBagConstraints();
   4.134          gridBagConstraints.gridx = 1;
   4.135 -        gridBagConstraints.gridy = 3;
   4.136 +        gridBagConstraints.gridy = 4;
   4.137          gridBagConstraints.gridwidth = 2;
   4.138          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.139          gridBagConstraints.weightx = 1.0;
   4.140          add(comPackageName, gridBagConstraints);
   4.141  
   4.142          createdFiles.setLabelFor(createdFilesValue);
   4.143 -        org.openide.awt.Mnemonics.setLocalizedText(createdFiles, java.util.ResourceBundle.getBundle("org/netbeans/modules/apisupport/project/ui/wizard/librarydescriptor/Bundle").getString("LBL_CreatedFiles"));
   4.144 +        org.openide.awt.Mnemonics.setLocalizedText(createdFiles, bundle.getString("LBL_CreatedFiles")); // NOI18N
   4.145          gridBagConstraints = new java.awt.GridBagConstraints();
   4.146          gridBagConstraints.gridx = 0;
   4.147 -        gridBagConstraints.gridy = 4;
   4.148 +        gridBagConstraints.gridy = 5;
   4.149          gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
   4.150          gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.151          gridBagConstraints.insets = new java.awt.Insets(36, 0, 6, 12);
   4.152          add(createdFiles, gridBagConstraints);
   4.153  
   4.154          modifiedFiles.setLabelFor(modifiedFilesValue);
   4.155 -        org.openide.awt.Mnemonics.setLocalizedText(modifiedFiles, java.util.ResourceBundle.getBundle("org/netbeans/modules/apisupport/project/ui/wizard/librarydescriptor/Bundle").getString("LBL_ModifiedFiles"));
   4.156 +        org.openide.awt.Mnemonics.setLocalizedText(modifiedFiles, bundle.getString("LBL_ModifiedFiles")); // NOI18N
   4.157          gridBagConstraints = new java.awt.GridBagConstraints();
   4.158          gridBagConstraints.gridx = 0;
   4.159 -        gridBagConstraints.gridy = 5;
   4.160 +        gridBagConstraints.gridy = 6;
   4.161          gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
   4.162          gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
   4.163          gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
   4.164          add(modifiedFiles, gridBagConstraints);
   4.165 -
   4.166          gridBagConstraints = new java.awt.GridBagConstraints();
   4.167          gridBagConstraints.gridx = 0;
   4.168 -        gridBagConstraints.gridy = 6;
   4.169 +        gridBagConstraints.gridy = 7;
   4.170          gridBagConstraints.gridwidth = 3;
   4.171          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.172          gridBagConstraints.weightx = 1.0;
   4.173 @@ -313,7 +311,7 @@
   4.174          createdFilesValue.setBorder(null);
   4.175          gridBagConstraints = new java.awt.GridBagConstraints();
   4.176          gridBagConstraints.gridx = 1;
   4.177 -        gridBagConstraints.gridy = 4;
   4.178 +        gridBagConstraints.gridy = 5;
   4.179          gridBagConstraints.gridwidth = 2;
   4.180          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.181          gridBagConstraints.weightx = 1.0;
   4.182 @@ -328,14 +326,29 @@
   4.183          modifiedFilesValue.setBorder(null);
   4.184          gridBagConstraints = new java.awt.GridBagConstraints();
   4.185          gridBagConstraints.gridx = 1;
   4.186 -        gridBagConstraints.gridy = 5;
   4.187 +        gridBagConstraints.gridy = 6;
   4.188          gridBagConstraints.gridwidth = 2;
   4.189          gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.190          gridBagConstraints.weightx = 1.0;
   4.191          add(modifiedFilesValue, gridBagConstraints);
   4.192  
   4.193 -    }
   4.194 -    // </editor-fold>//GEN-END:initComponents
   4.195 +        lblIcon2.setLabelFor(txtIcon);
   4.196 +        org.openide.awt.Mnemonics.setLocalizedText(lblIcon2, org.openide.util.NbBundle.getMessage(NameAndLocationPanel.class, "LBL_Icon")); // NOI18N
   4.197 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.198 +        gridBagConstraints.gridx = 0;
   4.199 +        gridBagConstraints.gridy = 1;
   4.200 +        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.201 +        gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
   4.202 +        add(lblIcon2, gridBagConstraints);
   4.203 +
   4.204 +        org.openide.awt.Mnemonics.setLocalizedText(useMultiView, "&Use MultiView");
   4.205 +        gridBagConstraints = new java.awt.GridBagConstraints();
   4.206 +        gridBagConstraints.gridx = 1;
   4.207 +        gridBagConstraints.gridy = 2;
   4.208 +        gridBagConstraints.gridwidth = 2;
   4.209 +        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
   4.210 +        add(useMultiView, gridBagConstraints);
   4.211 +    }// </editor-fold>//GEN-END:initComponents
   4.212      
   4.213      private void btnIconActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnIconActionPerformed
   4.214          JFileChooser chooser = UIUtil.getIconFileChooser(txtIcon.getText());
   4.215 @@ -352,7 +365,7 @@
   4.216      private javax.swing.JLabel createdFiles;
   4.217      private javax.swing.JTextArea createdFilesValue;
   4.218      private javax.swing.JLabel filler;
   4.219 -    private javax.swing.JLabel lblIcon;
   4.220 +    private javax.swing.JLabel lblIcon2;
   4.221      private javax.swing.JLabel lblPackageName;
   4.222      private javax.swing.JLabel lblPrefix;
   4.223      private javax.swing.JLabel lblProjectName;
   4.224 @@ -361,6 +374,7 @@
   4.225      private javax.swing.JTextField txtIcon;
   4.226      private javax.swing.JTextField txtPrefix;
   4.227      private javax.swing.JTextField txtProjectName;
   4.228 +    private javax.swing.JCheckBox useMultiView;
   4.229      // End of variables declaration//GEN-END:variables
   4.230      
   4.231      private void initAccessibility() {
     5.1 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NewLoaderIterator.java	Wed May 25 16:24:45 2011 +0200
     5.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/NewLoaderIterator.java	Wed May 25 16:50:33 2011 +0200
     5.3 @@ -115,6 +115,7 @@
     5.4          private boolean extensionBased = true;
     5.5          private String extension;
     5.6          private String namespace;
     5.7 +        private boolean useMultiview;
     5.8          
     5.9          private CreatedModifiedFiles files;
    5.10          
    5.11 @@ -161,6 +162,25 @@
    5.12          public void setExtensionBased(boolean extensionBased) {
    5.13              this.extensionBased = extensionBased;
    5.14          }
    5.15 +
    5.16 +        public boolean canUseMultiview() {
    5.17 +            try {
    5.18 +                SpecificationVersion v = getModuleInfo().getDependencyVersion("org.netbeans.core.multiview"); // NOI18N
    5.19 +                if (v == null) {
    5.20 +                    return false;
    5.21 +                }
    5.22 +                return v.compareTo(new SpecificationVersion("1.24")) >= 0; // NOI18N
    5.23 +            } catch (IOException ex) {
    5.24 +                return false;
    5.25 +            }
    5.26 +        }
    5.27 +        public boolean isUseMultiview() {
    5.28 +            return useMultiview;
    5.29 +        }
    5.30 +
    5.31 +        public void setUseMultiview(boolean useMultiview) {
    5.32 +            this.useMultiview = useMultiview;
    5.33 +        }
    5.34          
    5.35          public String getExtension() {
    5.36              return extension;
    5.37 @@ -186,7 +206,7 @@
    5.38          boolean loaderlessObject;
    5.39          boolean lookupReadyObject;
    5.40          try {
    5.41 -            SpecificationVersion current = model.getModuleInfo().getDependencyVersion("org.openide.loaders");
    5.42 +            SpecificationVersion current = model.getModuleInfo().getDependencyVersion("org.openide.loaders"); // NOI18N
    5.43              loaderlessObject = current == null || current.compareTo(new SpecificationVersion("7.1")) >= 0; // NOI18N
    5.44              lookupReadyObject = current == null || current.compareTo(new SpecificationVersion("6.0")) >= 0; // NOI18N
    5.45          } catch (IOException ex) {
    5.46 @@ -250,7 +270,11 @@
    5.47          String doName = model.getDefaultPackagePath(namePrefix + "DataObject.java", false); // NOI18N
    5.48          template = null;
    5.49          if (loaderlessObject) {
    5.50 -            template = CreatedModifiedFiles.getTemplate("templateDataObjectInLayer.java");//NOI18N
    5.51 +            if (model.isUseMultiview()) {
    5.52 +                template = CreatedModifiedFiles.getTemplate("templateDataObjectMulti.java");//NOI18N
    5.53 +            } else {
    5.54 +                template = CreatedModifiedFiles.getTemplate("templateDataObjectInLayer.java");//NOI18N
    5.55 +            }
    5.56          } else {
    5.57              if (lookupReadyObject) {
    5.58                  template = CreatedModifiedFiles.getTemplate("templateDataObjectWithLookup.java");//NOI18N
    5.59 @@ -260,6 +284,14 @@
    5.60              template = CreatedModifiedFiles.getTemplate("templateDataObject.java");//NOI18N
    5.61          }
    5.62          fileChanges.add(fileChanges.createFileWithSubstitutions(doName, template, replaceTokens));
    5.63 +        if (model.isUseMultiview()) {
    5.64 +            String formName = model.getDefaultPackagePath(namePrefix + "VisualElement.form", false); // NOI18N
    5.65 +            String javaName = model.getDefaultPackagePath(namePrefix + "VisualElement.java", false); // NOI18N
    5.66 +            FileObject java = CreatedModifiedFiles.getTemplate("templateDataObjectMultiForm.java");
    5.67 +            FileObject form = CreatedModifiedFiles.getTemplate("templateDataObjectMultiForm.form");
    5.68 +            fileChanges.add(fileChanges.createFile(formName, form));
    5.69 +            fileChanges.add(fileChanges.createFileWithSubstitutions(javaName, java, replaceTokens));
    5.70 +        }
    5.71          
    5.72          if (!loaderlessObject) {
    5.73              // 3. node file
    5.74 @@ -288,6 +320,12 @@
    5.75          if (isEditable) {
    5.76              fileChanges.add(fileChanges.addModuleDependency("org.openide.windows")); //NOI18N
    5.77          }
    5.78 +        if (model.isUseMultiview()) {
    5.79 +            fileChanges.add(fileChanges.addModuleDependency("org.netbeans.core.multiview")); //NOI18N
    5.80 +            String bundlePath = model.getDefaultPackagePath("Bundle.properties", true); // NOI18N
    5.81 +            fileChanges.add(fileChanges.bundleKey(bundlePath, "LBL_" + namePrefix + "_EDITOR", // NOI18N
    5.82 +                    "Source")); //NOI18N
    5.83 +        }
    5.84  
    5.85          if (!loaderlessObject) {
    5.86          // 6. update/create bundle file
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/templateDataObjectMulti.javx	Wed May 25 16:50:33 2011 +0200
     6.3 @@ -0,0 +1,62 @@
     6.4 +<#assign licenseFirst = "/*">
     6.5 +<#assign licensePrefix = " * ">
     6.6 +<#assign licenseLast = " */">
     6.7 +<#include "../Licenses/license-${project.license}.txt">
     6.8 +
     6.9 +package ${PACKAGENAME};
    6.10 +
    6.11 +import java.io.IOException;
    6.12 +import java.util.concurrent.Callable;
    6.13 +import org.netbeans.core.api.multiview.MultiViews;
    6.14 +import org.netbeans.core.spi.multiview.MultiViewElement;
    6.15 +import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
    6.16 +import org.openide.filesystems.FileObject;
    6.17 +import org.openide.loaders.DataNode;
    6.18 +import org.openide.loaders.DataObjectExistsException;
    6.19 +import org.openide.loaders.MultiDataObject;
    6.20 +import org.openide.loaders.MultiFileLoader;
    6.21 +import org.openide.text.DataEditorSupport;
    6.22 +import org.openide.nodes.Children;
    6.23 +import org.openide.nodes.CookieSet;
    6.24 +import org.openide.nodes.Node;
    6.25 +import org.openide.text.CloneableEditorSupport;
    6.26 +import org.openide.text.CloneableEditorSupport.Pane;
    6.27 +import org.openide.util.Lookup;
    6.28 +import org.openide.windows.TopComponent;
    6.29 +
    6.30 +public class ${PREFIX}DataObject extends MultiDataObject implements Callable<Pane> {
    6.31 +
    6.32 +    public ${PREFIX}DataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
    6.33 +        super(pf, loader);
    6.34 +        CookieSet cookies = getCookieSet();
    6.35 +        cookies.add((Node.Cookie) DataEditorSupport.create(this, getPrimaryEntry(), cookies, this));
    6.36 +    }
    6.37 +
    6.38 +    @Override
    6.39 +    protected Node createNodeDelegate() {
    6.40 +        return new DataNode(this, Children.LEAF, getLookup());
    6.41 +    }
    6.42 +
    6.43 +    @Override
    6.44 +    public Lookup getLookup() {
    6.45 +        return getCookieSet().getLookup();
    6.46 +    }
    6.47 +
    6.48 +    @Override
    6.49 +    public Pane call() {
    6.50 +        return (Pane)MultiViews.createCloneableMultiView("${MIMETYPE}", this);
    6.51 +    }
    6.52 +
    6.53 +    @MultiViewElement.Registration(
    6.54 +        displayName = "#LBL_${PREFIX}_EDITOR",
    6.55 +        iconBase = "${ICONPATH}",
    6.56 +        mimeType = "${MIMETYPE}",
    6.57 +        persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
    6.58 +        preferredID = "${PREFIX}",
    6.59 +        position = 1000
    6.60 +    )
    6.61 +    public static MultiViewEditorElement createEditor(Lookup lkp) {
    6.62 +        return new MultiViewEditorElement(lkp);
    6.63 +    }
    6.64 +
    6.65 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/templateDataObjectMultiVisual.forx	Wed May 25 16:50:33 2011 +0200
     7.3 @@ -0,0 +1,24 @@
     7.4 +<?xml version="1.0" encoding="UTF-8" ?>
     7.5 +
     7.6 +<Form version="1.3" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
     7.7 +  <AuxValues>
     7.8 +    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
     7.9 +    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
    7.10 +    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
    7.11 +    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
    7.12 +    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
    7.13 +  </AuxValues>
    7.14 +
    7.15 +  <Layout>
    7.16 +    <DimensionLayout dim="0">
    7.17 +      <Group type="103" groupAlignment="0" attributes="0">
    7.18 +          <EmptySpace min="0" pref="400" max="32767" attributes="0"/>
    7.19 +      </Group>
    7.20 +    </DimensionLayout>
    7.21 +    <DimensionLayout dim="1">
    7.22 +      <Group type="103" groupAlignment="0" attributes="0">
    7.23 +          <EmptySpace min="0" pref="300" max="32767" attributes="0"/>
    7.24 +      </Group>
    7.25 +    </DimensionLayout>
    7.26 +  </Layout>
    7.27 +</Form>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/loader/templateDataObjectMultiVisual.javx	Wed May 25 16:50:33 2011 +0200
     8.3 @@ -0,0 +1,132 @@
     8.4 +<#assign licenseFirst = "/*">
     8.5 +<#assign licensePrefix = " * ">
     8.6 +<#assign licenseLast = " */">
     8.7 +<#include "../Licenses/license-${project.license}.txt">
     8.8 +
     8.9 +package ${PACKAGENAME};
    8.10 +
    8.11 +import javax.swing.Action;
    8.12 +import javax.swing.JComponent;
    8.13 +import javax.swing.JPanel;
    8.14 +import javax.swing.JToolBar;
    8.15 +import org.netbeans.core.spi.multiview.CloseOperationState;
    8.16 +import org.netbeans.core.spi.multiview.MultiViewElement;
    8.17 +import org.netbeans.core.spi.multiview.MultiViewElementCallback;
    8.18 +import org.openide.awt.UndoRedo;
    8.19 +import org.openide.util.Lookup;
    8.20 +import org.openide.util.NbBundle.Messages;
    8.21 +import org.openide.windows.TopComponent;
    8.22 +
    8.23 +@MultiViewElement.Registration(
    8.24 +    displayName = "#LBL_${PREFIX}_VISUAL",
    8.25 +    iconBase = "${ICONPATH}",
    8.26 +    mimeType = "${MIMETYPE}",
    8.27 +    persistenceType = TopComponent.PERSISTENCE_NEVER,
    8.28 +    preferredID = "${PREFIX}Visual",
    8.29 +    position = 2000
    8.30 +)
    8.31 +@Messages({
    8.32 +    "LBL_${PREFIX}_VISUAL=Visual"
    8.33 +})
    8.34 +public final class ${PREFIX}VisualElement extends JPanel implements MultiViewElement {
    8.35 +    private ${PREFIX}DataObject obj;
    8.36 +    private JToolBar toolbar = new JToolBar();
    8.37 +    private transient MultiViewElementCallback callback;
    8.38 +
    8.39 +    public ${PREFIX}VisualElement(Lookup lkp) {
    8.40 +        obj = lkp.lookup(${PREFIX}DataObject.class);
    8.41 +        assert obj != null;
    8.42 +        initComponents();
    8.43 +    }
    8.44 +
    8.45 +    @Override
    8.46 +    public String getName() {
    8.47 +        return "${PREFIX}VisualElement";
    8.48 +    }
    8.49 +
    8.50 +    /** This method is called from within the constructor to
    8.51 +     * initialize the form.
    8.52 +     * WARNING: Do NOT modify this code. The content of this method is
    8.53 +     * always regenerated by the Form Editor.
    8.54 +     */
    8.55 +    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    8.56 +    private void initComponents() {
    8.57 +
    8.58 +        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    8.59 +        this.setLayout(layout);
    8.60 +        layout.setHorizontalGroup(
    8.61 +            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    8.62 +            .addGap(0, 400, Short.MAX_VALUE)
    8.63 +        );
    8.64 +        layout.setVerticalGroup(
    8.65 +            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    8.66 +            .addGap(0, 300, Short.MAX_VALUE)
    8.67 +        );
    8.68 +    }// </editor-fold>//GEN-END:initComponents
    8.69 +
    8.70 +
    8.71 +    // Variables declaration - do not modify//GEN-BEGIN:variables
    8.72 +    // End of variables declaration//GEN-END:variables
    8.73 +
    8.74 +
    8.75 +    @Override
    8.76 +    public JComponent getVisualRepresentation() {
    8.77 +        return this;
    8.78 +    }
    8.79 +
    8.80 +    @Override
    8.81 +    public JComponent getToolbarRepresentation() {
    8.82 +        return toolbar;
    8.83 +    }
    8.84 +
    8.85 +    @Override
    8.86 +    public Action[] getActions() {
    8.87 +        return new Action[0];
    8.88 +    }
    8.89 +
    8.90 +    @Override
    8.91 +    public Lookup getLookup() {
    8.92 +        return obj.getLookup();
    8.93 +    }
    8.94 +
    8.95 +    @Override
    8.96 +    public void componentOpened() {
    8.97 +    }
    8.98 +
    8.99 +    @Override
   8.100 +    public void componentClosed() {
   8.101 +    }
   8.102 +
   8.103 +    @Override
   8.104 +    public void componentShowing() {
   8.105 +    }
   8.106 +
   8.107 +    @Override
   8.108 +    public void componentHidden() {
   8.109 +    }
   8.110 +
   8.111 +    @Override
   8.112 +    public void componentActivated() {
   8.113 +    }
   8.114 +
   8.115 +    @Override
   8.116 +    public void componentDeactivated() {
   8.117 +    }
   8.118 +
   8.119 +    @Override
   8.120 +    public UndoRedo getUndoRedo() {
   8.121 +        return UndoRedo.NONE;
   8.122 +    }
   8.123 +
   8.124 +    @Override
   8.125 +    public void setMultiViewCallback(MultiViewElementCallback callback) {
   8.126 +        this.callback = callback;
   8.127 +    }
   8.128 +
   8.129 +    @Override
   8.130 +    public CloseOperationState canCloseElement() {
   8.131 +        return CloseOperationState.STATE_OK;
   8.132 +    }
   8.133 +
   8.134 +}
   8.135 +
     9.1 --- a/core.multiview/apichanges.xml	Wed May 25 16:24:45 2011 +0200
     9.2 +++ b/core.multiview/apichanges.xml	Wed May 25 16:50:33 2011 +0200
     9.3 @@ -103,12 +103,58 @@
     9.4      <apidefs>
     9.5          <apidef name="multiview_api">MultiView API</apidef>
     9.6          <apidef name="multiview_spi">MultiView SPI</apidef>
     9.7 +        <apidef name="multiview_text">MultiView Text SPI</apidef>
     9.8          <!-- etc. -->
     9.9      </apidefs>
    9.10  
    9.11      <!-- ACTUAL CHANGES BEGIN HERE: -->
    9.12  
    9.13    <changes>
    9.14 +    <change id="MultiViewEditorElement">
    9.15 +        <api name="multiview_text"/>
    9.16 +        <summary>MultiViewEditorElement</summary>
    9.17 +        <version major="1" minor="22"/>
    9.18 +        <date day="14" month="4" year="2011"/>
    9.19 +        <author login="jtulach"/>
    9.20 +        <compatibility addition="yes"/>
    9.21 +        <description>
    9.22 +            Common support class for integrating multi view and text 
    9.23 +            infrastructure.
    9.24 +        </description>
    9.25 +        <class package="org.netbeans.core.spi.multiview.text" name="MultiViewEditorElement"/>
    9.26 +        <issue number="196810"/>
    9.27 +    </change>
    9.28 +    <change id="MultiViews.create.mimetype">
    9.29 +        <api name="multiview_api"/>
    9.30 +        <summary>MultiViews.create for MIME type</summary>
    9.31 +        <version major="1" minor="22"/>
    9.32 +        <date day="14" month="4" year="2011"/>
    9.33 +        <author login="jtulach"/>
    9.34 +        <compatibility addition="yes"/>
    9.35 +        <description>
    9.36 +            New factory methods to create multiview components for a given
    9.37 +            mime type.
    9.38 +        </description>
    9.39 +        <class package="org.netbeans.core.api.multiview" name="MultiViews"/>
    9.40 +        <issue number="196810"/>
    9.41 +    </change>
    9.42 +    <change id="MultiViewElement.Registration">
    9.43 +        <api name="multiview_spi"/>
    9.44 +        <summary>@MultiViewElement.Registration</summary>
    9.45 +        <version major="1" minor="22"/>
    9.46 +        <date day="14" month="4" year="2011"/>
    9.47 +        <author login="jtulach"/>
    9.48 +        <compatibility addition="yes"/>
    9.49 +        <description>
    9.50 +            Declarative way to register 
    9.51 +            <a href="@TOP@org/netbeans/core/spi/multiview/MultiViewElement.html">
    9.52 +            MultiViewElement</a> via 
    9.53 +            <a href="@TOP@org/netbeans/core/spi/multiview/MultiViewElement.Registration.html">
    9.54 +            @Registration</a> annotation.
    9.55 +        </description>
    9.56 +        <class package="org.netbeans.core.spi.multiview" name="MultiViewElement"/>
    9.57 +        <issue number="196810"/>
    9.58 +    </change>
    9.59      <change>
    9.60          <api name="multiview_spi"/>
    9.61          <summary>Added marker interface SourceViewMarker to identify elements with sourcecode.</summary>
    10.1 --- a/core.multiview/arch.xml	Wed May 25 16:24:45 2011 +0200
    10.2 +++ b/core.multiview/arch.xml	Wed May 25 16:50:33 2011 +0200
    10.3 @@ -71,8 +71,16 @@
    10.4          </question>
    10.5  -->
    10.6  <answer id="arch-overall">
    10.7 -        <api name="MultiView" group="java" type="export" category="devel" 
    10.8 -             url="@TOP@/overview-summary.html"/>
    10.9 +        <api name="MultiView" group="java" type="export" category="stable" 
   10.10 +             url="@TOP@/overview-summary.html">
   10.11 +                 Provides support for creation of editors composed from
   10.12 +                 multiple (independent) elements. One can either specify
   10.13 +                 the <a href="@TOP@/org/netbeans/core/spi/multiview/MultiViewFactory.html">
   10.14 +                 elements directly</a> 
   10.15 +                 or read them from a 
   10.16 +                 <a href="@TOP@/org/netbeans/core/api/multiview/MultiViews.html">
   10.17 +                 declarative registration</a> for a particular mime type.
   10.18 +        </api>
   10.19  
   10.20  </answer>
   10.21  
    11.1 --- a/core.multiview/manifest.mf	Wed May 25 16:24:45 2011 +0200
    11.2 +++ b/core.multiview/manifest.mf	Wed May 25 16:50:33 2011 +0200
    11.3 @@ -1,6 +1,6 @@
    11.4  Manifest-Version: 1.0
    11.5  OpenIDE-Module: org.netbeans.core.multiview/1
    11.6 -OpenIDE-Module-Specification-Version: 1.23
    11.7 +OpenIDE-Module-Specification-Version: 1.24
    11.8  OpenIDE-Module-Localizing-Bundle: org/netbeans/core/multiview/resources/Bundle.properties
    11.9  OpenIDE-Module-Layer: org/netbeans/core/multiview/resources/mf-layer.xml
   11.10  AutoUpdate-Essential-Module: true
    12.1 --- a/core.multiview/nbproject/project.xml	Wed May 25 16:24:45 2011 +0200
    12.2 +++ b/core.multiview/nbproject/project.xml	Wed May 25 16:50:33 2011 +0200
    12.3 @@ -75,6 +75,11 @@
    12.4                      </run-dependency>
    12.5                  </dependency>
    12.6                  <dependency>
    12.7 +                    <code-name-base>org.openide.filesystems</code-name-base>
    12.8 +                    <build-prerequisite/>
    12.9 +                    <compile-dependency/>
   12.10 +                </dependency>
   12.11 +                <dependency>
   12.12                      <code-name-base>org.openide.nodes</code-name-base>
   12.13                      <build-prerequisite/>
   12.14                      <compile-dependency/>
   12.15 @@ -87,7 +92,7 @@
   12.16                      <build-prerequisite/>
   12.17                      <compile-dependency/>
   12.18                      <run-dependency>
   12.19 -                        <specification-version>6.16</specification-version>
   12.20 +                        <specification-version>6.39</specification-version>
   12.21                      </run-dependency>
   12.22                  </dependency>
   12.23                  <dependency>
   12.24 @@ -119,6 +124,11 @@
   12.25                  <test-type>
   12.26                      <name>unit</name>
   12.27                      <test-dependency>
   12.28 +                        <code-name-base>org.netbeans.modules.editor.mimelookup.impl</code-name-base>
   12.29 +                        <recursive/>
   12.30 +                        <compile-dependency/>
   12.31 +                    </test-dependency>
   12.32 +                    <test-dependency>
   12.33                          <code-name-base>org.netbeans.core.multiview</code-name-base>
   12.34                          <recursive/>
   12.35                          <compile-dependency/>
   12.36 @@ -141,11 +151,17 @@
   12.37                          <compile-dependency/>
   12.38                          <test/>
   12.39                      </test-dependency>
   12.40 +                    <test-dependency>
   12.41 +                        <code-name-base>org.openide.util.lookup</code-name-base>
   12.42 +                        <compile-dependency/>
   12.43 +                        <test/>
   12.44 +                    </test-dependency>
   12.45                  </test-type>
   12.46              </test-dependencies>
   12.47              <public-packages>
   12.48                  <package>org.netbeans.core.api.multiview</package>
   12.49                  <package>org.netbeans.core.spi.multiview</package>
   12.50 +                <package>org.netbeans.core.spi.multiview.text</package>
   12.51              </public-packages>
   12.52          </data>
   12.53      </configuration>
    13.1 --- a/core.multiview/src/org/netbeans/core/api/multiview/MultiViews.java	Wed May 25 16:24:45 2011 +0200
    13.2 +++ b/core.multiview/src/org/netbeans/core/api/multiview/MultiViews.java	Wed May 25 16:50:33 2011 +0200
    13.3 @@ -44,26 +44,32 @@
    13.4  
    13.5  package org.netbeans.core.api.multiview;
    13.6  
    13.7 -import javax.swing.Action;
    13.8 -import javax.swing.JPanel;
    13.9 -import javax.swing.JToolBar;
   13.10 +import java.io.Serializable;
   13.11 +import org.netbeans.api.editor.mimelookup.MimeLookup;
   13.12  import org.netbeans.core.multiview.MultiViewCloneableTopComponent;
   13.13  import org.netbeans.core.multiview.MultiViewTopComponent;
   13.14 +import org.netbeans.core.spi.multiview.MultiViewElement;
   13.15 +import org.netbeans.core.spi.multiview.MultiViewElement.Registration;
   13.16 +import org.openide.text.CloneableEditorSupport;
   13.17 +import org.openide.text.CloneableEditorSupport.Pane;
   13.18  import org.openide.util.Lookup;
   13.19 +import org.openide.windows.CloneableTopComponent;
   13.20 +import org.openide.windows.Mode;
   13.21  import org.openide.windows.TopComponent;
   13.22 +import org.openide.windows.WindowManager;
   13.23  
   13.24  /** Factory class for handling multi views.
   13.25   *
   13.26   * @author  Dafe Simonek, Milos Kleint
   13.27   */
   13.28 -public final class MultiViews {
   13.29 + public final class MultiViews {
   13.30  
   13.31      /** Factory class, no instances. */
   13.32      private MultiViews() {
   13.33      }
   13.34  
   13.35      /**
   13.36 -     * For advanced manupulation with Multiview component, the handler can be requested
   13.37 +     * For advanced manipulation with Multiview component, the handler can be requested
   13.38       * @return handle that one can use for manipulation with multiview component.
   13.39       */
   13.40      public static MultiViewHandler findMultiViewHandler(TopComponent tc) {
   13.41 @@ -77,5 +83,49 @@
   13.42          }
   13.43          return null;
   13.44      }
   13.45 -    
   13.46 + 
   13.47 +    /** Factory method to create multiview for a given mime type. The list
   13.48 +     * of {@link MultiViewElement}s to display is taken from {@link MimeLookup#getLookup}.
   13.49 +     * The <code>context</code> parameter has to be Serializable, so the top component
   13.50 +     * can be persisted and later, when deserialized, it can again recreate the 
   13.51 +     * {@link Lookup}. Suitable candidate for an object that implements both
   13.52 +     * {@link Serializable} as well as {@link org.openide.util.Lookup.Provider} is 
   13.53 +     * <a href="@org-openide-loaders@/org/openide/loaders/DataObject.html">DataObject</a>.
   13.54 +     * To register your elements into particular mime type see {@link Registration}.
   13.55 +     * 
   13.56 +     * @param context lookup provider representing the object to displayed in the multiview
   13.57 +     * @param mimeType the mime type to seek for elements in
   13.58 +     * @return multiview component
   13.59 +     * @since 1.22
   13.60 +     */
   13.61 +    public static <T extends Serializable & Lookup.Provider> TopComponent createMultiView(
   13.62 +        String mimeType, T context
   13.63 +    ) {
   13.64 +        MultiViewTopComponent tc = new MultiViewTopComponent();
   13.65 +        tc.setMimeLookup(mimeType, context);
   13.66 +        return tc;
   13.67 +    }
   13.68 +
   13.69 +    /** Factory method to create cloneable multiview for a given mime type. 
   13.70 +     * The way to obtain individual elements is the same as in 
   13.71 +     * {@link #createMultiView}. By default the returned component is put
   13.72 +     * into "editor" mode, if it exists.
   13.73 +     * 
   13.74 +     * @param context lookup representing the object to be displayed in the multiview
   13.75 +     * @param mimeType the mime type to seek for elements in
   13.76 +     * @return cloneable multiview component also implementing {@link Pane} interface
   13.77 +     * @since 1.22
   13.78 +     */
   13.79 +    public static <T extends Serializable & Lookup.Provider> CloneableTopComponent createCloneableMultiView(
   13.80 +            String mimeType, T context
   13.81 +    ) {
   13.82 +        MultiViewCloneableTopComponent tc = new MultiViewCloneableTopComponent();
   13.83 +        tc.setMimeLookup(mimeType, context);
   13.84 +        // dock into editor mode if possible.
   13.85 +        Mode editorMode = WindowManager.getDefault().findMode(CloneableEditorSupport.EDITOR_MODE);
   13.86 +        if (editorMode != null) {
   13.87 +            editorMode.dockInto(tc);
   13.88 +        }
   13.89 +        return tc;
   13.90 +    }
   13.91  }
    14.1 --- a/core.multiview/src/org/netbeans/core/api/multiview/package.html	Wed May 25 16:24:45 2011 +0200
    14.2 +++ b/core.multiview/src/org/netbeans/core/api/multiview/package.html	Wed May 25 16:50:33 2011 +0200
    14.3 @@ -43,7 +43,8 @@
    14.4    -->
    14.5  </head>
    14.6  <body>
    14.7 -MultiView API lets the developers manipulate existing multiview
    14.8 +MultiView API lets the developers create new multiview components 
    14.9 +(without specifying their content), manipulate existing multiview
   14.10  components, eg. examine what is inside the component, request focus for
   14.11  one of the views etc.<br>
   14.12  This API allows to access the multiview component's content.<p>
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/core.multiview/src/org/netbeans/core/multiview/ContextAwareDescription.java	Wed May 25 16:50:33 2011 +0200
    15.3 @@ -0,0 +1,53 @@
    15.4 +/*
    15.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 + *
    15.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    15.8 + *
    15.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   15.10 + * Other names may be trademarks of their respective owners.
   15.11 + *
   15.12 + * The contents of this file are subject to the terms of either the GNU
   15.13 + * General Public License Version 2 only ("GPL") or the Common
   15.14 + * Development and Distribution License("CDDL") (collectively, the
   15.15 + * "License"). You may not use this file except in compliance with the
   15.16 + * License. You can obtain a copy of the License at
   15.17 + * http://www.netbeans.org/cddl-gplv2.html
   15.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   15.19 + * specific language governing permissions and limitations under the
   15.20 + * License.  When distributing the software, include this License Header
   15.21 + * Notice in each file and include the License file at
   15.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   15.23 + * particular file as subject to the "Classpath" exception as provided
   15.24 + * by Oracle in the GPL Version 2 section of the License file that
   15.25 + * accompanied this code. If applicable, add the following below the
   15.26 + * License Header, with the fields enclosed by brackets [] replaced by
   15.27 + * your own identifying information:
   15.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   15.29 + *
   15.30 + * If you wish your version of this file to be governed by only the CDDL
   15.31 + * or only the GPL Version 2, indicate your decision by adding
   15.32 + * "[Contributor] elects to include this software in this distribution
   15.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   15.34 + * single choice of license, a recipient has the option to distribute
   15.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   15.36 + * to extend the choice of license to its licensees as provided above.
   15.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   15.38 + * Version 2 license, then the option applies only if the new code is
   15.39 + * made subject to such option by the copyright holder.
   15.40 + *
   15.41 + * Contributor(s):
   15.42 + *
   15.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   15.44 + */
   15.45 +package org.netbeans.core.multiview;
   15.46 +
   15.47 +import org.netbeans.core.spi.multiview.MultiViewDescription;
   15.48 +import org.openide.util.Lookup;
   15.49 +
   15.50 +/** Possibly part of an API in future.
   15.51 + *
   15.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   15.53 + */
   15.54 +public interface ContextAwareDescription extends MultiViewDescription {
   15.55 +    public ContextAwareDescription createContextAwareDescription(Lookup context);
   15.56 +}
    16.1 --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java	Wed May 25 16:24:45 2011 +0200
    16.2 +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewCloneableTopComponent.java	Wed May 25 16:50:33 2011 +0200
    16.3 @@ -48,7 +48,6 @@
    16.4  import java.util.Collection;
    16.5  import java.util.Iterator;
    16.6  import java.util.Map;
    16.7 -import java.util.logging.Level;
    16.8  import java.util.logging.Logger;
    16.9  import javax.swing.Action;
   16.10  import javax.swing.SwingUtilities;
   16.11 @@ -61,13 +60,14 @@
   16.12  import org.openide.awt.UndoRedo;
   16.13  import org.openide.text.CloneableEditorSupport;
   16.14  import org.openide.util.HelpCtx;
   16.15 +import org.openide.util.Lookup;
   16.16  import org.openide.windows.CloneableTopComponent;
   16.17  import org.openide.windows.TopComponent;
   16.18  
   16.19  
   16.20  /** Special subclass of TopComponent which shows and handles set of
   16.21   * MultiViewElements, shows them in switchable toggle buttons style, along
   16.22 - * with toolbsrs af actions asociated with individual view elements.
   16.23 + * with toolbars and actions associated with individual view elements.
   16.24   *
   16.25   *
   16.26   * @author Dafe Simonek, Milos Kleint
   16.27 @@ -92,6 +92,9 @@
   16.28  //        setFocusable(false);
   16.29      }
   16.30      
   16.31 +    public <T extends Serializable & Lookup.Provider> void setMimeLookup(String mimeType, T context) {
   16.32 +        peer.setMimeLookup(mimeType, context);
   16.33 +    }
   16.34      
   16.35      public void setMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) {
   16.36          peer.setMultiViewDescriptions(descriptions, defaultDesc);
   16.37 @@ -183,8 +186,15 @@
   16.38      protected String preferredID() {
   16.39          return peer.preferredID();
   16.40      }
   16.41 -    
   16.42 -    
   16.43 +
   16.44 +    @Override
   16.45 +    protected CloneableTopComponent createClonedObject() {
   16.46 +        MultiViewCloneableTopComponent tc = new MultiViewCloneableTopComponent();
   16.47 +        tc.setMultiViewDescriptions(peer.model.getDescriptions(), peer.model.getActiveDescription());;
   16.48 +        tc.setCloseOperationHandler(peer.closeHandler);
   16.49 +        tc.peer.copyMimeContext(peer);
   16.50 +        return tc;
   16.51 +    }
   16.52      
   16.53      /** Serialize this top component.
   16.54      * Subclasses wishing to store state must call the super method, then write to the stream.
   16.55 @@ -251,7 +261,7 @@
   16.56          
   16.57          MultiViewDescription[] descs = peer.model.getDescriptions();
   16.58          for (MultiViewDescription desc : descs) {
   16.59 -            if (desc instanceof SourceViewMarker) {
   16.60 +            if (isSourceView(desc)) {
   16.61                  el = peer.model.getElementForDescription(desc);
   16.62                  if (el.getVisualRepresentation() instanceof CloneableEditorSupport.Pane) {
   16.63                      return el;
   16.64 @@ -324,7 +334,17 @@
   16.65              MultiViewElementCallback call = peer.getModel().getCallbackForElement(paneEl);
   16.66              call.requestVisible();
   16.67          }
   16.68 -    }    
   16.69 +    }
   16.70 +
   16.71 +    static boolean isSourceView(MultiViewDescription desc) {
   16.72 +        if (desc instanceof SourceViewMarker) {
   16.73 +            return true;
   16.74 +        }
   16.75 +        if (desc instanceof SourceCheckDescription) {
   16.76 +            return ((SourceCheckDescription)desc).isSourceView();
   16.77 +        }
   16.78 +        return false;
   16.79 +    }
   16.80      
   16.81      
   16.82      /**
    17.1 --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java	Wed May 25 16:24:45 2011 +0200
    17.2 +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewPeer.java	Wed May 25 16:50:33 2011 +0200
    17.3 @@ -52,6 +52,7 @@
    17.4  import java.io.ObjectOutput;
    17.5  import java.io.Serializable;
    17.6  import java.util.ArrayList;
    17.7 +import java.util.Arrays;
    17.8  import java.util.Collection;
    17.9  import java.util.HashMap;
   17.10  import java.util.Iterator;
   17.11 @@ -89,18 +90,19 @@
   17.12  
   17.13  /** Special subclass of TopComponent which shows and handles set of
   17.14   * MultiViewElements, shows them in switchable toggle buttons style, along
   17.15 - * with toolbsrs af actions asociated with individual view elements.
   17.16 + * with toolbars of actions associated with individual view elements.
   17.17   *
   17.18   *
   17.19   * @author Dafe Simonek, Milos Kleint
   17.20   */
   17.21 -
   17.22 -
   17.23  public final class MultiViewPeer  {
   17.24  
   17.25      static final String MULTIVIEW_ID = "MultiView-"; //NOI18N
   17.26  
   17.27      private static final String TOOLBAR_VISIBLE_PROP = /* org.netbeans.api.editor.settings.SimpleValueNames.TOOLBAR_VISIBLE_PROP */ "toolbarVisible"; // NOI18N
   17.28 +
   17.29 +    private Lookup.Provider context;
   17.30 +    private String mimeType;
   17.31      
   17.32      MultiViewModel model;
   17.33      TabsComponent tabs;
   17.34 @@ -132,10 +134,38 @@
   17.35          delegateUndoRedo = new DelegateUndoRedo();
   17.36      }
   17.37      
   17.38 - 
   17.39 +    void copyMimeContext(MultiViewPeer other) {
   17.40 +        this.context = other.context;
   17.41 +        this.mimeType = other.mimeType;
   17.42 +    }
   17.43 +    
   17.44 +    /** @param context context needs to be also serializable */
   17.45 +    public void setMimeLookup(String mimeType, Lookup.Provider context) {
   17.46 +        this.context = context;
   17.47 +        this.mimeType = mimeType;
   17.48 +        
   17.49 +        List<MultiViewDescription> arr = new ArrayList<MultiViewDescription>();
   17.50 +        final Lookup lkp = MimeLookup.getLookup(mimeType);
   17.51 +        for (ContextAwareDescription d : lkp.lookupAll(ContextAwareDescription.class)) {
   17.52 +            d = d.createContextAwareDescription(context.getLookup());
   17.53 +            arr.add(d);
   17.54 +        }
   17.55 +        if (model != null) {
   17.56 +            model.removeElementSelectionListener(selListener);
   17.57 +        }
   17.58 +        model = new MultiViewModel(arr.toArray(new MultiViewDescription[0]), arr.get(0), factory);
   17.59 +        model.addElementSelectionListener(selListener);
   17.60 +        tabs.setModel(model);
   17.61 +        CloseOperationHandler h = lkp.lookup(CloseOperationHandler.class);
   17.62 +        if (h == null) {
   17.63 +            h = SpiAccessor.DEFAULT.createDefaultCloseHandler();
   17.64 +        }
   17.65 +        closeHandler = h;
   17.66 +    }
   17.67      
   17.68      
   17.69      public void setMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) {
   17.70 +        assert context == null;
   17.71          if (model != null) {
   17.72              model.removeElementSelectionListener(selListener);
   17.73          }
   17.74 @@ -145,6 +175,7 @@
   17.75      }
   17.76      
   17.77      public void setCloseOperationHandler(CloseOperationHandler handler) {
   17.78 +        assert context == null;
   17.79          closeHandler = handler;
   17.80      }
   17.81      
   17.82 @@ -229,12 +260,16 @@
   17.83          jc.setOpaque(false);
   17.84          tabs.setInnerToolBar(jc);
   17.85          tabs.setToolbarBarVisible(isToolbarVisible());
   17.86 -        editorSettingsPreferences.addPreferenceChangeListener(editorSettingsListener);
   17.87 +        if (editorSettingsPreferences != null) {
   17.88 +            editorSettingsPreferences.addPreferenceChangeListener(editorSettingsListener);
   17.89 +        }
   17.90      }
   17.91      
   17.92      void peerComponentHidden() {
   17.93          model.getActiveElement().componentHidden();
   17.94 -        editorSettingsPreferences.removePreferenceChangeListener(editorSettingsListener);
   17.95 +        if (editorSettingsPreferences != null) {
   17.96 +            editorSettingsPreferences.removePreferenceChangeListener(editorSettingsListener);
   17.97 +        }
   17.98      }
   17.99      
  17.100      void peerComponentDeactivated() {
  17.101 @@ -382,7 +417,7 @@
  17.102          MultiViewDescription[] descs = model.getDescriptions();
  17.103          int type = TopComponent.PERSISTENCE_NEVER;
  17.104          for (int i = 0; i < descs.length; i++) {
  17.105 -            if (!(descs[i] instanceof Serializable)) {
  17.106 +            if (context == null && !(descs[i] instanceof Serializable)) {
  17.107                  Logger.getLogger(MultiViewTopComponent.class.getName()).warning(
  17.108                          "The MultiviewDescription instance " + descs[i].getClass() + " is not serializable. Cannot persist TopComponent.");
  17.109                  type = TopComponent.PERSISTENCE_NEVER;
  17.110 @@ -421,20 +456,32 @@
  17.111      * @param out the stream to serialize to
  17.112      */
  17.113      void peerWriteExternal (ObjectOutput out) throws IOException {
  17.114 -        if (closeHandler != null) {
  17.115 -            if (closeHandler instanceof Serializable) {
  17.116 -                out.writeObject(closeHandler);
  17.117 -            } else {
  17.118 -                //TODO some warning to the SPI programmer
  17.119 -                Logger.getAnonymousLogger().info(
  17.120 -                       "The CloseOperationHandler isn not serializable. MultiView component id=" + preferredID());
  17.121 +        boolean fromMime;
  17.122 +        if (context != null) {
  17.123 +            out.writeObject(mimeType);
  17.124 +            out.writeObject(context);
  17.125 +            fromMime = true;
  17.126 +        } else {
  17.127 +            if (closeHandler != null) {
  17.128 +                if (closeHandler instanceof Serializable) {
  17.129 +                    out.writeObject(closeHandler);
  17.130 +                } else {
  17.131 +                    //TODO some warning to the SPI programmer
  17.132 +                    Logger.getAnonymousLogger().info(
  17.133 +                           "The CloseOperationHandler isn not serializable. MultiView component id=" + preferredID());
  17.134 +                }
  17.135              }
  17.136 +            fromMime = false;
  17.137          }
  17.138          MultiViewDescription[] descs = model.getDescriptions();
  17.139          MultiViewDescription curr = model.getActiveDescription();
  17.140          int currIndex = 0;
  17.141          for (int i = 0; i < descs.length; i++) {
  17.142 -            out.writeObject(descs[i]);
  17.143 +            if (!fromMime) {
  17.144 +                out.writeObject(descs[i]);
  17.145 +            } else {
  17.146 +                out.writeObject(descs[i].preferredID());
  17.147 +            }
  17.148              if (descs[i].getPersistenceType() != TopComponent.PERSISTENCE_NEVER) {
  17.149                  // only those requeTopsted and previously created elements are serialized.
  17.150                  MultiViewElement elem = model.getElementForDescription(descs[i], false);
  17.151 @@ -460,13 +507,32 @@
  17.152          int current = 0;
  17.153          CloseOperationHandler close = null;
  17.154          try {
  17.155 +            int counting = 0;
  17.156 +            MultiViewDescription lastDescription = null;
  17.157              while (true) {
  17.158                  Object obj = in.readObject();
  17.159 +                if ((obj instanceof String) && counting++ == 0) {
  17.160 +                    Lookup.Provider lp = (Lookup.Provider)in.readObject();
  17.161 +                    setMimeLookup((String)obj, lp);
  17.162 +                    descList.addAll(Arrays.asList(model.getDescriptions()));
  17.163 +                    continue;
  17.164 +                }
  17.165                  if (obj instanceof MultiViewDescription) {
  17.166 -                    descList.add((MultiViewDescription)obj);
  17.167 +                    lastDescription = (MultiViewDescription)obj;
  17.168 +                    descList.add(lastDescription);
  17.169 +                }
  17.170 +                else if (obj instanceof String) {
  17.171 +                    for (MultiViewDescription md : descList) {
  17.172 +                        if (md.preferredID().equals(obj)) {
  17.173 +                            lastDescription = md;
  17.174 +                            break;
  17.175 +                        }
  17.176 +                    }
  17.177                  }
  17.178                  else if (obj instanceof MultiViewElement) {
  17.179 -                    map.put(descList.get(descList.size() - 1), (MultiViewElement)obj);
  17.180 +                    assert lastDescription != null;
  17.181 +                    map.put(lastDescription, (MultiViewElement)obj);
  17.182 +                    lastDescription = null;
  17.183                  }
  17.184                  else if (obj instanceof Integer)  {
  17.185                      Integer integ = (Integer)obj;
  17.186 @@ -478,12 +544,14 @@
  17.187                  }
  17.188              }
  17.189          } catch (IOException exc) {
  17.190 -            //#121119 try preventing model corruption when deserialization of client code fails.
  17.191 -            if (close == null) {
  17.192 +                //#121119 try preventing model corruption when deserialization of client code fails.
  17.193 +            if (context == null) {
  17.194 +                if (close == null) {
  17.195                      //TODO some warning to the SPI programmer
  17.196 -                close = SpiAccessor.DEFAULT.createDefaultCloseHandler();
  17.197 +                    close = SpiAccessor.DEFAULT.createDefaultCloseHandler();
  17.198 +                }
  17.199 +                setCloseOperationHandler(close);
  17.200              }
  17.201 -            setCloseOperationHandler(close);
  17.202              if (descList.size() > 0) {
  17.203                  MultiViewDescription[] descs = new MultiViewDescription[descList.size()];
  17.204                  descs = descList.toArray(descs);
  17.205 @@ -497,19 +565,20 @@
  17.206              
  17.207              throw exc;
  17.208          }
  17.209 -        if (close == null) {
  17.210 -                //TODO some warning to the SPI programmer
  17.211 -            close = SpiAccessor.DEFAULT.createDefaultCloseHandler();
  17.212 +        if (context == null) {
  17.213 +            if (close == null) {
  17.214 +                    //TODO some warning to the SPI programmer
  17.215 +                close = SpiAccessor.DEFAULT.createDefaultCloseHandler();
  17.216 +            }
  17.217 +            setCloseOperationHandler(close);
  17.218          }
  17.219 -        setCloseOperationHandler(close);
  17.220          // now that we've read everything, we should set it correctly.
  17.221          MultiViewDescription[] descs = new MultiViewDescription[descList.size()];
  17.222          descs = descList.toArray(descs);
  17.223          MultiViewDescription currDesc = descs[current];
  17.224          setDeserializedMultiViewDescriptions(descs, currDesc, map);
  17.225      }    
  17.226 -    
  17.227 -    
  17.228 +
  17.229      private Action[] getDefaultTCActions() {
  17.230          //TODO for each suppoerted peer have one entry..
  17.231          if (peer instanceof MultiViewTopComponent) {
  17.232 @@ -577,14 +646,20 @@
  17.233      public void updateName() {
  17.234          // is called before setMultiViewDescriptions() need to check for null.
  17.235          if (model != null) {
  17.236 -            MultiViewElement el = model.getActiveElement();
  17.237 -            if (el.getVisualRepresentation() instanceof Pane) {
  17.238 -                Pane pane = (Pane)el.getVisualRepresentation();
  17.239 -                pane.updateName();
  17.240 -                peer.setDisplayName(pane.getComponent().getDisplayName());
  17.241 +            for (MultiViewDescription mvd : model.getDescriptions()) {
  17.242 +                MultiViewElement el = model.getElementForDescription(
  17.243 +                    mvd, MultiViewCloneableTopComponent.isSourceView(mvd)
  17.244 +                );
  17.245 +                if (el == null) {
  17.246 +                    continue;
  17.247 +                }
  17.248 +                if (el.getVisualRepresentation() instanceof Pane) {
  17.249 +                    Pane pane = (Pane)el.getVisualRepresentation();
  17.250 +                    pane.updateName();
  17.251 +                    peer.setDisplayName(pane.getComponent().getDisplayName());
  17.252 +                }
  17.253              }
  17.254          }
  17.255 -        //TODO
  17.256      }
  17.257      
  17.258      public Lookup getLookup() {
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewProcessor.java	Wed May 25 16:50:33 2011 +0200
    18.3 @@ -0,0 +1,187 @@
    18.4 +/*
    18.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    18.6 + *
    18.7 + * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
    18.8 + *
    18.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   18.10 + * Other names may be trademarks of their respective owners.
   18.11 + *
   18.12 + * The contents of this file are subject to the terms of either the GNU
   18.13 + * General Public License Version 2 only ("GPL") or the Common
   18.14 + * Development and Distribution License("CDDL") (collectively, the
   18.15 + * "License"). You may not use this file except in compliance with the
   18.16 + * License. You can obtain a copy of the License at
   18.17 + * http://www.netbeans.org/cddl-gplv2.html
   18.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   18.19 + * specific language governing permissions and limitations under the
   18.20 + * License.  When distributing the software, include this License Header
   18.21 + * Notice in each file and include the License file at
   18.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   18.23 + * particular file as subject to the "Classpath" exception as provided
   18.24 + * by Oracle in the GPL Version 2 section of the License file that
   18.25 + * accompanied this code. If applicable, add the following below the
   18.26 + * License Header, with the fields enclosed by brackets [] replaced by
   18.27 + * your own identifying information:
   18.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   18.29 + *
   18.30 + * If you wish your version of this file to be governed by only the CDDL
   18.31 + * or only the GPL Version 2, indicate your decision by adding
   18.32 + * "[Contributor] elects to include this software in this distribution
   18.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   18.34 + * single choice of license, a recipient has the option to distribute
   18.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   18.36 + * to extend the choice of license to its licensees as provided above.
   18.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   18.38 + * Version 2 license, then the option applies only if the new code is
   18.39 + * made subject to such option by the copyright holder.
   18.40 + *
   18.41 + * Contributor(s):
   18.42 + *
   18.43 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
   18.44 + */
   18.45 +
   18.46 +package org.netbeans.core.multiview;
   18.47 +
   18.48 +import java.util.Arrays;
   18.49 +import java.util.HashSet;
   18.50 +import java.util.List;
   18.51 +import java.util.Set;
   18.52 +import javax.annotation.processing.Processor;
   18.53 +import javax.annotation.processing.RoundEnvironment;
   18.54 +import javax.annotation.processing.SupportedSourceVersion;
   18.55 +import javax.lang.model.SourceVersion;
   18.56 +import javax.lang.model.element.Element;
   18.57 +import javax.lang.model.element.ElementKind;
   18.58 +import javax.lang.model.element.ExecutableElement;
   18.59 +import javax.lang.model.element.Modifier;
   18.60 +import javax.lang.model.element.TypeElement;
   18.61 +import javax.lang.model.element.VariableElement;
   18.62 +import javax.lang.model.type.TypeMirror;
   18.63 +import javax.lang.model.util.ElementFilter;
   18.64 +import org.netbeans.core.spi.multiview.MultiViewElement;
   18.65 +import org.netbeans.core.spi.multiview.MultiViewFactory;
   18.66 +import org.openide.filesystems.annotations.LayerBuilder;
   18.67 +import org.openide.filesystems.annotations.LayerGeneratingProcessor;
   18.68 +import org.openide.filesystems.annotations.LayerGenerationException;
   18.69 +import org.openide.text.CloneableEditorSupport;
   18.70 +import org.openide.util.Lookup;
   18.71 +import org.openide.util.lookup.ServiceProvider;
   18.72 +import org.openide.windows.TopComponent;
   18.73 +
   18.74 +/**
   18.75 + * Register {@link MultiViewElement}s for given mime types.
   18.76 + * 
   18.77 + * @author Jaroslav Tulach
   18.78 + */
   18.79 +@ServiceProvider(service=Processor.class)
   18.80 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
   18.81 +public class MultiViewProcessor extends LayerGeneratingProcessor {
   18.82 +    public @Override Set<String> getSupportedAnnotationTypes() {
   18.83 +        return new HashSet<String>(Arrays.asList(
   18.84 +            MultiViewElement.Registration.class.getCanonicalName()
   18.85 +        ));
   18.86 +    }
   18.87 +
   18.88 +    @Override
   18.89 +    protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws LayerGenerationException {
   18.90 +        if (roundEnv.processingOver()) {
   18.91 +            return false;
   18.92 +        }
   18.93 +        TypeMirror pane = null;
   18.94 +        TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(CloneableEditorSupport.Pane.class.getCanonicalName());
   18.95 +        if(typeElement != null) {
   18.96 +            pane = typeElement.asType();
   18.97 +        }
   18.98 +        
   18.99 +        for (Element e : roundEnv.getElementsAnnotatedWith(MultiViewElement.Registration.class)) {
  18.100 +            MultiViewElement.Registration mvr = e.getAnnotation(MultiViewElement.Registration.class);
  18.101 +            if (mvr.mimeType().length == 0) {
  18.102 +                throw new LayerGenerationException("You must specify mimeType", e);
  18.103 +            }
  18.104 +            TypeMirror[] exprType = new TypeMirror[1];
  18.105 +            String[] binAndMethodNames = findDefinition(e, exprType);
  18.106 +            String fileBaseName = binAndMethodNames[0].replace('.', '-');
  18.107 +            if (binAndMethodNames[1] != null) {
  18.108 +                fileBaseName += "-" + binAndMethodNames[1];
  18.109 +            }
  18.110 +            for (String type : mvr.mimeType()) {
  18.111 +                LayerBuilder.File f = layer(e).file("Editors/" + (type.equals("") ? "" : type + '/') + fileBaseName + ".instance");
  18.112 +                f.methodvalue("instanceCreate", MultiViewFactory.class.getName(), "createMultiViewDescription");
  18.113 +                f.stringvalue("instanceClass", ContextAwareDescription.class.getName());
  18.114 +                f.stringvalue("class", binAndMethodNames[0]);
  18.115 +                f.bundlevalue("displayName", mvr.displayName());
  18.116 +                f.stringvalue("iconBase", mvr.iconBase());
  18.117 +                f.stringvalue("preferredID", mvr.preferredID());
  18.118 +                f.intvalue("persistenceType", mvr.persistenceType());
  18.119 +                f.position(mvr.position());
  18.120 +                if (binAndMethodNames[1] != null) {
  18.121 +                    f.stringvalue("method", binAndMethodNames[1]);
  18.122 +                }
  18.123 +                if (pane != null && processingEnv.getTypeUtils().isAssignable(exprType[0], pane)) {
  18.124 +                    f.boolvalue("sourceview", true);
  18.125 +                }
  18.126 +                f.write();
  18.127 +            }
  18.128 +        }
  18.129 +        return true;
  18.130 +    }
  18.131 +
  18.132 +    private String[] findDefinition(Element e, TypeMirror[] type) throws LayerGenerationException {
  18.133 +        final TypeMirror lkp = processingEnv.getElementUtils().getTypeElement(Lookup.class.getCanonicalName()).asType();
  18.134 +        final TypeMirror mve = processingEnv.getElementUtils().getTypeElement(MultiViewElement.class.getName()).asType();
  18.135 +        if (e.getKind() == ElementKind.CLASS) {
  18.136 +            TypeElement clazz = (TypeElement) e;
  18.137 +            if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), mve)) {
  18.138 +                throw new LayerGenerationException("Not assignable to " + mve, e);
  18.139 +            }
  18.140 +            int constructorCount = 0;
  18.141 +            CONSTRUCTOR: for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
  18.142 +                if (!constructor.getModifiers().contains(Modifier.PUBLIC)) {
  18.143 +                    continue;
  18.144 +                }
  18.145 +                List<? extends VariableElement> params = constructor.getParameters();
  18.146 +                if (params.size() > 1) {
  18.147 +                    continue;
  18.148 +                }
  18.149 +                for (VariableElement param : params) {
  18.150 +                    if (!param.asType().equals(lkp)) {
  18.151 +                        continue CONSTRUCTOR;
  18.152 +                    }
  18.153 +                }
  18.154 +            }
  18.155 +            if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
  18.156 +                throw new LayerGenerationException("Class must be public", e);
  18.157 +            }
  18.158 +            type[0] = e.asType();
  18.159 +            return new String[] {processingEnv.getElementUtils().getBinaryName(clazz).toString(), null};
  18.160 +        } else {
  18.161 +            ExecutableElement meth = (ExecutableElement) e;
  18.162 +            if (!processingEnv.getTypeUtils().isAssignable(meth.getReturnType(), mve)) {
  18.163 +                throw new LayerGenerationException("Not assignable to " + mve, e);
  18.164 +            }
  18.165 +            if (!meth.getModifiers().contains(Modifier.PUBLIC)) {
  18.166 +                throw new LayerGenerationException("Method must be public", e);
  18.167 +            }
  18.168 +            if (!meth.getModifiers().contains(Modifier.STATIC)) {
  18.169 +                throw new LayerGenerationException("Method must be static", e);
  18.170 +            }
  18.171 +            List<? extends VariableElement> params = meth.getParameters();
  18.172 +            if (params.size() > 1) {
  18.173 +                throw new LayerGenerationException("Method must take at most one parameter", e);
  18.174 +            }
  18.175 +            for (VariableElement param : params) {
  18.176 +                if (!param.asType().equals(lkp)) {
  18.177 +                    throw new LayerGenerationException("Method parameters may be either Lookup or Project", e);
  18.178 +                }
  18.179 +            }
  18.180 +            if (!meth.getEnclosingElement().getModifiers().contains(Modifier.PUBLIC)) {
  18.181 +                throw new LayerGenerationException("Class must be public", e);
  18.182 +            }
  18.183 +            type[0] = meth.getReturnType();
  18.184 +            return new String[] {
  18.185 +                processingEnv.getElementUtils().getBinaryName((TypeElement) meth.getEnclosingElement()).toString(),
  18.186 +                meth.getSimpleName().toString()};
  18.187 +        }
  18.188 +    }
  18.189 +
  18.190 +}
    19.1 --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java	Wed May 25 16:24:45 2011 +0200
    19.2 +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewTopComponent.java	Wed May 25 16:50:33 2011 +0200
    19.3 @@ -53,12 +53,13 @@
    19.4  import org.netbeans.core.spi.multiview.MultiViewElementCallback;
    19.5  import org.openide.awt.UndoRedo;
    19.6  import org.openide.util.HelpCtx;
    19.7 +import org.openide.util.Lookup;
    19.8  import org.openide.windows.TopComponent;
    19.9  
   19.10  
   19.11  /** Special subclass of TopComponent which shows and handles set of
   19.12   * MultiViewElements, shows them in switchable toggle buttons style, along
   19.13 - * with toolbsrs af actions asociated with individual view elements.
   19.14 + * with toolbars and actions associated with individual view elements.
   19.15   *
   19.16   *
   19.17   * @author Dafe Simonek, Milos Kleint
   19.18 @@ -82,6 +83,9 @@
   19.19          setFocusCycleRoot(false);
   19.20      }
   19.21      
   19.22 +    public <T extends Serializable & Lookup.Provider> void setMimeLookup(String mimeType, T context) {
   19.23 +        peer.setMimeLookup(mimeType, context);
   19.24 +    }
   19.25      
   19.26      public void setMultiViewDescriptions(MultiViewDescription[] descriptions, MultiViewDescription defaultDesc) {
   19.27          peer.setMultiViewDescriptions(descriptions, defaultDesc);
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/core.multiview/src/org/netbeans/core/multiview/SourceCheckDescription.java	Wed May 25 16:50:33 2011 +0200
    20.3 @@ -0,0 +1,55 @@
    20.4 +/*
    20.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    20.6 + *
    20.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    20.8 + *
    20.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   20.10 + * Other names may be trademarks of their respective owners.
   20.11 + *
   20.12 + * The contents of this file are subject to the terms of either the GNU
   20.13 + * General Public License Version 2 only ("GPL") or the Common
   20.14 + * Development and Distribution License("CDDL") (collectively, the
   20.15 + * "License"). You may not use this file except in compliance with the
   20.16 + * License. You can obtain a copy of the License at
   20.17 + * http://www.netbeans.org/cddl-gplv2.html
   20.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   20.19 + * specific language governing permissions and limitations under the
   20.20 + * License.  When distributing the software, include this License Header
   20.21 + * Notice in each file and include the License file at
   20.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   20.23 + * particular file as subject to the "Classpath" exception as provided
   20.24 + * by Oracle in the GPL Version 2 section of the License file that
   20.25 + * accompanied this code. If applicable, add the following below the
   20.26 + * License Header, with the fields enclosed by brackets [] replaced by
   20.27 + * your own identifying information:
   20.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   20.29 + *
   20.30 + * If you wish your version of this file to be governed by only the CDDL
   20.31 + * or only the GPL Version 2, indicate your decision by adding
   20.32 + * "[Contributor] elects to include this software in this distribution
   20.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   20.34 + * single choice of license, a recipient has the option to distribute
   20.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   20.36 + * to extend the choice of license to its licensees as provided above.
   20.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   20.38 + * Version 2 license, then the option applies only if the new code is
   20.39 + * made subject to such option by the copyright holder.
   20.40 + *
   20.41 + * Contributor(s):
   20.42 + *
   20.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   20.44 + */
   20.45 +package org.netbeans.core.multiview;
   20.46 +
   20.47 +import org.netbeans.core.spi.multiview.MultiViewDescription;
   20.48 +import org.netbeans.core.spi.multiview.SourceViewMarker;
   20.49 +
   20.50 +/** More dynamic version of {@link SourceViewMarker}. Possibly candidate for
   20.51 + * some future API.
   20.52 + *
   20.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   20.54 + */
   20.55 +public interface SourceCheckDescription extends MultiViewDescription {
   20.56 +    /** @return true if this description likely represents source view */
   20.57 +    public boolean isSourceView();
   20.58 +}
    21.1 --- a/core.multiview/src/org/netbeans/core/spi/multiview/CloseOperationHandler.java	Wed May 25 16:24:45 2011 +0200
    21.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/CloseOperationHandler.java	Wed May 25 16:50:33 2011 +0200
    21.3 @@ -59,7 +59,7 @@
    21.4       * the decision.
    21.5       * @param elements {@link org.netbeans.core.spi.multiview.CloseOperationState} instances of {@link org.netbeans.core.spi.multiview.MultiViewElement}s that cannot be
    21.6       * closed and require resolution.
    21.7 -     * @returns true if component can be close, false if it shall remain opened.
    21.8 +     * @return true if component can be close, false if it shall remain opened.
    21.9       */
   21.10      boolean resolveCloseOperation(CloseOperationState[] elements);
   21.11      
    22.1 --- a/core.multiview/src/org/netbeans/core/spi/multiview/MultiViewCloneableEditor.java	Wed May 25 16:24:45 2011 +0200
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,174 +0,0 @@
    22.4 -/*
    22.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    22.6 - *
    22.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    22.8 - *
    22.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   22.10 - * Other names may be trademarks of their respective owners.
   22.11 - *
   22.12 - * The contents of this file are subject to the terms of either the GNU
   22.13 - * General Public License Version 2 only ("GPL") or the Common
   22.14 - * Development and Distribution License("CDDL") (collectively, the
   22.15 - * "License"). You may not use this file except in compliance with the
   22.16 - * License. You can obtain a copy of the License at
   22.17 - * http://www.netbeans.org/cddl-gplv2.html
   22.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   22.19 - * specific language governing permissions and limitations under the
   22.20 - * License.  When distributing the software, include this License Header
   22.21 - * Notice in each file and include the License file at
   22.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   22.23 - * particular file as subject to the "Classpath" exception as provided
   22.24 - * by Oracle in the GPL Version 2 section of the License file that
   22.25 - * accompanied this code. If applicable, add the following below the
   22.26 - * License Header, with the fields enclosed by brackets [] replaced by
   22.27 - * your own identifying information:
   22.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   22.29 - *
   22.30 - * Contributor(s):
   22.31 - *
   22.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   22.33 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   22.34 - * Microsystems, Inc. All Rights Reserved.
   22.35 - *
   22.36 - * If you wish your version of this file to be governed by only the CDDL
   22.37 - * or only the GPL Version 2, indicate your decision by adding
   22.38 - * "[Contributor] elects to include this software in this distribution
   22.39 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   22.40 - * single choice of license, a recipient has the option to distribute
   22.41 - * your version of this file under either the CDDL, the GPL Version 2 or
   22.42 - * to extend the choice of license to its licensees as provided above.
   22.43 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   22.44 - * Version 2 license, then the option applies only if the new code is
   22.45 - * made subject to such option by the copyright holder.
   22.46 - */
   22.47 -
   22.48 -package org.netbeans.core.spi.multiview;
   22.49 -
   22.50 -import javax.swing.JComponent;
   22.51 -import javax.swing.JToolBar;
   22.52 -import javax.swing.text.Document;
   22.53 -import org.openide.text.CloneableEditor;
   22.54 -import org.openide.text.CloneableEditorSupport;
   22.55 -import org.openide.text.NbDocument;
   22.56 -
   22.57 -/**
   22.58 - * @author  mkleint
   22.59 - */
   22.60 -abstract class MultiViewCloneableEditor extends CloneableEditor  implements MultiViewElement {
   22.61 -
   22.62 -    private static final long serialVersionUID =-3126744316644172415L;
   22.63 -
   22.64 -    private transient MultiViewElementCallback multiViewObserver;
   22.65 -    private transient JToolBar bar;
   22.66 -    
   22.67 -    /** Creates a new instance of MultiViewClonableEditor */
   22.68 -    public MultiViewCloneableEditor() {
   22.69 -        this(null);
   22.70 -    }
   22.71 -    
   22.72 -    public MultiViewCloneableEditor(CloneableEditorSupport support) {
   22.73 -        super(support);
   22.74 -    }
   22.75 -    
   22.76 -    public JComponent getToolbarRepresentation() {
   22.77 -        Document doc = getEditorPane().getDocument();
   22.78 -        if (doc instanceof NbDocument.CustomToolbar) {
   22.79 -            if (bar == null) {
   22.80 -                bar = ((NbDocument.CustomToolbar)doc).createToolbar(getEditorPane());
   22.81 -            }
   22.82 -            return bar;
   22.83 -        }
   22.84 -        return null;
   22.85 -    }
   22.86 -    
   22.87 -    public javax.swing.JComponent getVisualRepresentation() {
   22.88 -        return this;
   22.89 -    }
   22.90 -    
   22.91 -    public final void setMultiViewCallback(MultiViewElementCallback callback) {
   22.92 -        multiViewObserver = callback;
   22.93 -    }
   22.94 -    
   22.95 -    protected final MultiViewElementCallback getElementObserver() {
   22.96 -        return multiViewObserver;
   22.97 -    }
   22.98 -    
   22.99 -    public void componentActivated() {
  22.100 -        super.componentActivated();
  22.101 -    }
  22.102 -    
  22.103 -    public void componentClosed() {
  22.104 -        super.componentClosed();
  22.105 -    }
  22.106 -    
  22.107 -    public void componentDeactivated() {
  22.108 -        super.componentDeactivated();
  22.109 -    }
  22.110 -    
  22.111 -    public void componentHidden() {
  22.112 -        super.componentHidden();
  22.113 -    }
  22.114 -    
  22.115 -    public void componentOpened() {
  22.116 -        super.componentOpened();
  22.117 -    }
  22.118 -    
  22.119 -    public void componentShowing() {
  22.120 -        if (multiViewObserver != null) {
  22.121 -            updateName();
  22.122 -        }
  22.123 -        super.componentShowing();
  22.124 -    }
  22.125 -    
  22.126 -    public javax.swing.Action[] getActions() {
  22.127 -        return super.getActions();
  22.128 -    }
  22.129 -    
  22.130 -    public org.openide.util.Lookup getLookup() {
  22.131 -        return super.getLookup();
  22.132 -    }
  22.133 -    
  22.134 -    public String preferredID() {
  22.135 -        return super.preferredID();
  22.136 -    }
  22.137 -    
  22.138 -    
  22.139 -    public void requestVisible() {
  22.140 -        if (multiViewObserver != null) {
  22.141 -            multiViewObserver.requestVisible();
  22.142 -        } else {
  22.143 -            super.requestVisible();
  22.144 -        }
  22.145 -    }
  22.146 -    
  22.147 -    public void requestActive() {
  22.148 -        if (multiViewObserver != null) {
  22.149 -            multiViewObserver.requestActive();
  22.150 -        } else {
  22.151 -            super.requestActive();
  22.152 -        }
  22.153 -    }
  22.154 -    
  22.155 -    
  22.156 -    public void updateName() {
  22.157 -        super.updateName();
  22.158 -        if (multiViewObserver != null) {
  22.159 -            multiViewObserver.updateTitle(getDisplayName());
  22.160 -        }
  22.161 -    }
  22.162 -    
  22.163 -    public void open() {
  22.164 -        if (multiViewObserver != null) {
  22.165 -            multiViewObserver.requestVisible();
  22.166 -        } else {
  22.167 -            super.open();
  22.168 -        }
  22.169 -        
  22.170 -    }
  22.171 -    
  22.172 -    public CloseOperationState canCloseElement() {
  22.173 -        throw new IllegalStateException("Not implemented yet.");
  22.174 -//        return CloseOperationState.STATE_OK;
  22.175 -    }
  22.176 -    
  22.177 -}
    23.1 --- a/core.multiview/src/org/netbeans/core/spi/multiview/MultiViewElement.java	Wed May 25 16:24:45 2011 +0200
    23.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/MultiViewElement.java	Wed May 25 16:50:33 2011 +0200
    23.3 @@ -44,8 +44,14 @@
    23.4  
    23.5  package org.netbeans.core.spi.multiview;
    23.6  
    23.7 +import java.lang.annotation.ElementType;
    23.8 +import java.lang.annotation.Retention;
    23.9 +import java.lang.annotation.RetentionPolicy;
   23.10 +import java.lang.annotation.Target;
   23.11  import javax.swing.Action;
   23.12  import javax.swing.JComponent;
   23.13 +import org.netbeans.api.editor.mimelookup.MimeLookup;
   23.14 +import org.netbeans.core.api.multiview.MultiViews;
   23.15  import org.openide.awt.UndoRedo;
   23.16  import org.openide.util.Lookup;
   23.17  
   23.18 @@ -165,4 +171,59 @@
   23.19      CloseOperationState canCloseElement();
   23.20      
   23.21     
   23.22 +    /** Registers a {@link MultiViewElement}, so it is available in 
   23.23 +     * {@link MimeLookup} and can be found and located by 
   23.24 +     * {@link MultiViews#createCloneableMultiView}
   23.25 +     * and
   23.26 +     * {@link MultiViews#createMultiView}
   23.27 +     * factory methods. 
   23.28 +     * <p>
   23.29 +     * The element class may have default constructor or a constructor that 
   23.30 +     * takes {@link Lookup} as an argument.
   23.31 +     */
   23.32 +    @Target({ ElementType.TYPE, ElementType.METHOD })
   23.33 +    @Retention(RetentionPolicy.SOURCE)
   23.34 +    public @interface Registration {
   23.35 +        /** Mime type this registration is associated with.
   23.36 +         * 
   23.37 +         * @return array of mime types like "text/java", "text", etc.
   23.38 +         */
   23.39 +        public String[] mimeType();
   23.40 +        
   23.41 +        /** Gets persistence type of multi view element, the TopComponent will decide
   23.42 +         * on it's own persistenceType based on the sum of all it's elements.
   23.43 +         * {@link org.openide.windows.TopComponent#PERSISTENCE_ALWAYS} has higher priority than {@link org.openide.windows.TopComponent#PERSISTENCE_ONLY_OPENED}
   23.44 +         * and {@link org.openide.windows.TopComponent#PERSISTENCE_NEVER} has lowest priority.
   23.45 +         * The {@link org.openide.windows.TopComponent} will be stored only if at least one element requesting persistence
   23.46 +         * was made visible.
   23.47 +         */
   23.48 +        public int persistenceType();
   23.49 +
   23.50 +        /** 
   23.51 +         * Gets localized display name of multi view element. Will be placed on the Element's toggle button.
   23.52 +         *@return localized display name
   23.53 +         */
   23.54 +        public String displayName();
   23.55 +
   23.56 +        /** 
   23.57 +         * Icon for the MultiViewDescription's multiview component. Will be shown as TopComponent's icon
   23.58 +         * when this element is selected.
   23.59 +         * @return the icon of multi view element 
   23.60 +         */
   23.61 +        public String iconBase();
   23.62 +
   23.63 +        /**
   23.64 +         * A Description's contribution 
   23.65 +         * to unique {@link org.openide.windows.TopComponent}'s Id returned by <code>getID</code>. Returned value is used as starting
   23.66 +         * value for creating unique {@link org.openide.windows.TopComponent} ID for whole enclosing multi view
   23.67 +         * component.
   23.68 +         * Value should be preferably unique, but need not be.
   23.69 +         */
   23.70 +        public String preferredID();
   23.71 +
   23.72 +        /** Position of this element amoung the list of other elements.
   23.73 +         * @return integer value
   23.74 +         */
   23.75 +        public int position() default Integer.MAX_VALUE;
   23.76 +    }
   23.77  }
    24.1 --- a/core.multiview/src/org/netbeans/core/spi/multiview/MultiViewFactory.java	Wed May 25 16:24:45 2011 +0200
    24.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/MultiViewFactory.java	Wed May 25 16:50:33 2011 +0200
    24.3 @@ -44,16 +44,29 @@
    24.4  
    24.5  package org.netbeans.core.spi.multiview;
    24.6  
    24.7 +import java.awt.Image;
    24.8 +import java.awt.event.ActionEvent;
    24.9  import java.io.Serializable;
   24.10 -import java.util.ArrayList;
   24.11 -import java.util.Collection;
   24.12 +import java.lang.reflect.Constructor;
   24.13 +import java.lang.reflect.Method;
   24.14 +import java.util.Iterator;
   24.15 +import java.util.LinkedHashMap;
   24.16 +import java.util.Map;
   24.17  import javax.swing.AbstractAction;
   24.18  import javax.swing.Action;
   24.19  import javax.swing.JComponent;
   24.20  import javax.swing.JPanel;
   24.21 +import org.netbeans.core.api.multiview.MultiViews;
   24.22 +import org.netbeans.core.multiview.ContextAwareDescription;
   24.23  import org.netbeans.core.multiview.MultiViewCloneableTopComponent;
   24.24  import org.netbeans.core.multiview.MultiViewTopComponent;
   24.25 +import org.netbeans.core.multiview.SourceCheckDescription;
   24.26 +import org.openide.DialogDisplayer;
   24.27 +import org.openide.NotifyDescriptor;
   24.28 +import org.openide.util.HelpCtx;
   24.29 +import org.openide.util.ImageUtilities;
   24.30  import org.openide.util.Lookup;
   24.31 +import org.openide.util.NbBundle.Messages;
   24.32  import org.openide.windows.CloneableTopComponent;
   24.33  import org.openide.windows.TopComponent;
   24.34  
   24.35 @@ -84,6 +97,10 @@
   24.36       * multi views.
   24.37       * PLEASE NOTE: a non-cloneable TopComponent is not able to embed editors aka subclasses of CloneableEditor correctly.
   24.38       * Use createCloneableMultiView() method in such a case.
   24.39 +     * <p>
   24.40 +     * Please see {@link MultiViews#createMultiView} for loosely coupled variant
   24.41 +     * of this method which may be more suitable for modular environment.
   24.42 +     * 
   24.43       * @param descriptions array of descriptions of tabs in the multiview.
   24.44       * @param defaultDesc the initial selection, one of the descriptions array values.
   24.45       */
   24.46 @@ -95,6 +112,10 @@
   24.47       * multi views.
   24.48       * PLEASE NOTE: a non-cloneable TopComponent is not able to embed editors aka subclasses of CloneableEditor correctly.
   24.49       * Use createCloneableMultiView() method in such a case.
   24.50 +     * <p>
   24.51 +     * Please see {@link MultiViews#createMultiView} for loosely coupled variant
   24.52 +     * of this method which may be more suitable for modular environment.
   24.53 +     * 
   24.54       * @param descriptions  array of descriptions of tabs in the multiview.
   24.55       * @param defaultDesc  the initial selection, one of the descriptions array values.
   24.56       * @param closeHandler handles closing of the multiview component, useful when any of the embedded elements can be in modified state and closing would cause a dataloss..
   24.57 @@ -110,7 +131,12 @@
   24.58      }
   24.59      
   24.60     /** Creates and returns new instance of cloneable top component with
   24.61 -     * multi views 
   24.62 +     * multi views.
   24.63 +     * <p>
   24.64 +     * Please see {@link MultiViews#createCloneableMultiView} for loosely coupled variant
   24.65 +     * of this method which may be more suitable for modular environment.
   24.66 +     * 
   24.67 +     * 
   24.68       * @param descriptions  array of descriptions of tabs in the multiview.
   24.69       * @param defaultDesc  the initial selection, one of the descriptions array values.
   24.70      */
   24.71 @@ -120,6 +146,10 @@
   24.72  
   24.73      /** Creates and returns new instance of cloneable top component with
   24.74       * multi views.
   24.75 +     * <p>
   24.76 +     * Please see {@link MultiViews#createCloneableMultiView} for loosely coupled variant
   24.77 +     * of this method which may be more suitable for modular environment.
   24.78 +     * 
   24.79       * @param descriptions  array of descriptions of tabs in the multiview.
   24.80       * @param defaultDesc  the initial selection, one of the descriptions array values.
   24.81       * @param closeHandler handles closing of the multiview component, useful when any of the embedded elements can be in modified state and closing would cause a dataloss..
   24.82 @@ -146,7 +176,15 @@
   24.83      /**
   24.84       * Utility method for MultiViewElements to create a CloseOperationState instance 
   24.85       * that warns about possible data loss. Corrective actions can be defined.
   24.86 -     * @param warningId an id that idenfifies the problem, 
   24.87 +     * <p>
   24.88 +     * There is a default implementation of {@link CloseOperationHandler}. It 
   24.89 +     * uses <code>warningId</code> of all elements with unsafe close state to
   24.90 +     * select the unique ones. These unique elements are then presented in a 
   24.91 +     * question box and user can decide to save or discard them. The user
   24.92 +     * friendly message in such dialog is taken from 
   24.93 +     * <code>proceedAction.getValue(Action.LONG_DESCRIPTION)</code>, if present.
   24.94 +     * 
   24.95 +     * @param warningId an id that identifies the problem, 
   24.96       *     the CloseOperationHandler used in the component should know about the warning's meaning and handle appropriately
   24.97       * @param proceedAction will be performed when the CloseOperationHandler decides that closing the component is ok and changes are to be saved.
   24.98       * @param discardAction will be performed when the CloseOperationHandler decides that the nonsaved data shall be discarded
   24.99 @@ -163,6 +201,9 @@
  24.100          return new DefaultCloseHandler();
  24.101      }
  24.102      
  24.103 +    static MultiViewDescription createMultiViewDescription(Map map) {
  24.104 +        return new MapMVD(map, null);
  24.105 +    }
  24.106      
  24.107      private static final class Blank implements MultiViewElement, Serializable {
  24.108          
  24.109 @@ -228,74 +269,87 @@
  24.110      private static final class DefaultCloseHandler implements CloseOperationHandler, Serializable {
  24.111           private static final long serialVersionUID =-3126744916624172427L;        
  24.112         
  24.113 +        @Override
  24.114 +        @Messages({
  24.115 +            "CTL_Save=Save",
  24.116 +            "CTL_Discard=&Discard"
  24.117 +        })
  24.118          public boolean resolveCloseOperation(CloseOperationState[] elements) {
  24.119 +            Iterator<CloseOperationState> it;
  24.120              if (elements != null) {
  24.121                  boolean canBeClosed = true;
  24.122 -                Collection badOnes = new ArrayList();
  24.123 +                Map<String,CloseOperationState> badOnes = new LinkedHashMap<String, CloseOperationState>();
  24.124                  for (int i = 0; i < elements.length; i++) {
  24.125                      if (!elements[i].canClose()) {
  24.126 -                        badOnes.add(elements[i]);
  24.127 +                        badOnes.put(elements[i].getCloseWarningID(), elements[i]);
  24.128                          canBeClosed = false;
  24.129                      }
  24.130                  }
  24.131                  if (!canBeClosed) {
  24.132 -                    //TODO SHOW dialog here.
  24.133 -                    throw new IllegalStateException("Cannot close component. Some of the elements require close operation handling. See MultiViewFactory.createMultiView()");
  24.134 -//                    Object[] options = new Object[] {
  24.135 -//                        new JButton("Proceed"),
  24.136 -//                        new JButton("Discard"),
  24.137 -//                        new JButton("Cancel")
  24.138 -//                    };
  24.139 -//                    NotifyDescriptor desc = new NotifyDescriptor(createPanel(badOnes), "Cannot close component.", 
  24.140 -//                                NotifyDescriptor.DEFAULT_OPTION, NotifyDescriptor.WARNING_MESSAGE, 
  24.141 -//                                options, options[0]);
  24.142 -//                    Object retVal = DialogDisplayer.getDefault().notify(desc);
  24.143 -//                    if (retVal == options[0]) {
  24.144 -//                        // do proceed.
  24.145 -//                        Iterator it = badOnes.iterator();
  24.146 -//                        while (it.hasNext()) {
  24.147 -//                            Action act = ((CloseOperationState)it.next()).getProceedAction();
  24.148 -//                            if (act != null) {
  24.149 -//                                act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "proceed"));
  24.150 -//                            }
  24.151 -//                        }
  24.152 -//                    } else if (retVal == options[1]) {
  24.153 -//                        // do discard
  24.154 -//                        Iterator it = badOnes.iterator();
  24.155 -//                        while (it.hasNext()) {
  24.156 -//                            Action act = ((CloseOperationState)it.next()).getDiscardAction();
  24.157 -//                            if (act != null) {
  24.158 -//                                act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "discard"));
  24.159 -//                            }
  24.160 -//                        }
  24.161 -//                    } else {
  24.162 -//                        // was cancel..
  24.163 -//                        return false;
  24.164 -//                    }
  24.165 +                    NotifyDescriptor desc = new NotifyDescriptor.Confirmation(
  24.166 +                        createPanel(badOnes), NotifyDescriptor.YES_NO_CANCEL_OPTION
  24.167 +                    );
  24.168 +                    Object[] choose = { Bundle.CTL_Save(), Bundle.CTL_Discard(), NotifyDescriptor.CANCEL_OPTION };
  24.169 +                    desc.setOptions(choose);
  24.170 +                    Object retVal = DialogDisplayer.getDefault().notify(desc);
  24.171 +                    if (retVal == choose[0]) {
  24.172 +                        // do proceed.
  24.173 +                        it = badOnes.values().iterator();
  24.174 +                        while (it.hasNext()) {
  24.175 +                            Action act = ((CloseOperationState)it.next()).getProceedAction();
  24.176 +                            if (act != null) {
  24.177 +                                act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "proceed"));
  24.178 +                            }
  24.179 +                        }
  24.180 +                    } else if (retVal == choose[1]) {
  24.181 +                        // do discard
  24.182 +                        it = badOnes.values().iterator();
  24.183 +                        while (it.hasNext()) {
  24.184 +                            Action act = ((CloseOperationState)it.next()).getDiscardAction();
  24.185 +                            if (act != null) {
  24.186 +                                act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "discard"));
  24.187 +                            }
  24.188 +                        }
  24.189 +                    } else {
  24.190 +                        // was cancel..
  24.191 +                        return false;
  24.192 +                    }
  24.193                  }
  24.194              }
  24.195              return true;
  24.196          }
  24.197          
  24.198 -//        private JPanel createPanel(Collection elems) {
  24.199 -//            JPanel panel = new JPanel();
  24.200 -//            panel.setLayout(new BorderLayout());
  24.201 -//            JLabel lbl = new JLabel("Cannot safely close component for following reasons:");
  24.202 -//            panel.add(lbl, BorderLayout.NORTH);
  24.203 -//            JScrollPane pane = new JScrollPane();
  24.204 -//            String[] warnings = new String[elems.size()];
  24.205 -//            int index = 0;
  24.206 -//            Iterator it = elems.iterator();
  24.207 -//            while (it.hasNext()) {
  24.208 -//                CloseOperationState state = (CloseOperationState)it.next();
  24.209 -//                warnings[index] = state.getCloseWarningMessage();
  24.210 -//                index = index + 1;
  24.211 -//            }
  24.212 -//            JList list = new JList(warnings);
  24.213 -//            pane.setViewportView(list);
  24.214 -//            panel.add(pane);
  24.215 -//            return panel;
  24.216 -//        }
  24.217 +        private Object createPanel(Map<String,CloseOperationState> elems) {
  24.218 +            if (elems.size() == 1) {
  24.219 +                return findDescription(elems.values().iterator().next());
  24.220 +            }
  24.221 +            
  24.222 +            StringBuilder sb = new StringBuilder();
  24.223 +            Iterator it = elems.values().iterator();
  24.224 +            while (it.hasNext()) {
  24.225 +                CloseOperationState state = (CloseOperationState)it.next();
  24.226 +                if (sb.length() > 0) {
  24.227 +                    sb.append(" ");
  24.228 +                }
  24.229 +                sb.append(findDescription(state));
  24.230 +            }
  24.231 +            return sb;
  24.232 +        }
  24.233 +
  24.234 +        private Object findDescription(final CloseOperationState e) {
  24.235 +            final Action a = e.getProceedAction();
  24.236 +            Object msg = a.getValue(Action.LONG_DESCRIPTION);
  24.237 +            if (msg == null) {
  24.238 +                msg = a.getValue(Action.SHORT_DESCRIPTION);
  24.239 +            }
  24.240 +            if (msg == null) {
  24.241 +                msg = a.getValue(Action.NAME);
  24.242 +            }
  24.243 +            if (msg == null) {
  24.244 +                msg = e.getCloseWarningID();
  24.245 +            }
  24.246 +            return msg;
  24.247 +        }
  24.248      }
  24.249      
  24.250      /**
  24.251 @@ -308,5 +362,98 @@
  24.252          }
  24.253          
  24.254      }
  24.255 -    
  24.256 +
  24.257 +    /** default MultiViewDescription */
  24.258 +    private static final class MapMVD implements
  24.259 +    MultiViewDescription, ContextAwareDescription , SourceCheckDescription {
  24.260 +        private final Map map;
  24.261 +        private final Lookup context;
  24.262 +        public MapMVD(Map map, Lookup context) {
  24.263 +            this.map = map;
  24.264 +            this.context = context;
  24.265 +        }
  24.266 +        
  24.267 +        private <T> T get(String attr, Class<T> type) {
  24.268 +            Object obj = map.get(attr); // NOI18N
  24.269 +            if (obj == null) {
  24.270 +                throw new NullPointerException(attr + " attribute not specified");
  24.271 +            }
  24.272 +            if (type.isInstance(obj)) {
  24.273 +                return type.cast(obj);
  24.274 +            }
  24.275 +            throw new IllegalArgumentException(attr + " not of type " + type + " but " + obj);
  24.276 +        }
  24.277 +        
  24.278 +
  24.279 +        @Override
  24.280 +        public int getPersistenceType() {
  24.281 +            return get("persistenceType", Integer.class);
  24.282 +        }
  24.283 +
  24.284 +        @Override
  24.285 +        public String getDisplayName() {
  24.286 +            return get("displayName", String.class);
  24.287 +        }
  24.288 +
  24.289 +        @Override
  24.290 +        public Image getIcon() {
  24.291 +            String base = get("iconBase", String.class); // NOI18N
  24.292 +            return ImageUtilities.loadImage(base, true);
  24.293 +        }
  24.294 +
  24.295 +        @Override
  24.296 +        public HelpCtx getHelpCtx() {
  24.297 +            return HelpCtx.DEFAULT_HELP;
  24.298 +        }
  24.299 +
  24.300 +        @Override
  24.301 +        public String preferredID() {
  24.302 +            return get("preferredID", String.class); // NOI18N
  24.303 +        }
  24.304 +
  24.305 +        @Override
  24.306 +        public MultiViewElement createElement() {
  24.307 +            String name = get("class", String.class); // NOI18N
  24.308 +            String method = (String)map.get("method"); // NOI18N
  24.309 +            try {
  24.310 +                ClassLoader cl = Lookup.getDefault().lookup(ClassLoader.class);
  24.311 +                if (cl == null) {
  24.312 +                    cl = Thread.currentThread().getContextClassLoader();
  24.313 +                }
  24.314 +                if (cl == null) {
  24.315 +                    cl = MultiViewFactory.class.getClassLoader();
  24.316 +                }
  24.317 +                Class<?> clazz = Class.forName(name, true, cl);
  24.318 +                if (method == null) {
  24.319 +                    try {
  24.320 +                        Constructor<?> lookupC = clazz.getConstructor(Lookup.class);
  24.321 +                        return (MultiViewElement)lookupC.newInstance(context);
  24.322 +                    } catch (Exception ex) {
  24.323 +                        Constructor<?> defC = clazz.getConstructor();
  24.324 +                        return (MultiViewElement)defC.newInstance();
  24.325 +                    }
  24.326 +                } else {
  24.327 +                    try {
  24.328 +                        Method m = clazz.getMethod(method, Lookup.class);
  24.329 +                        return (MultiViewElement) m.invoke(null, context);
  24.330 +                    } catch (Exception ex) {
  24.331 +                        Method m = clazz.getMethod(method);
  24.332 +                        return (MultiViewElement) m.invoke(null);
  24.333 +                    }
  24.334 +                }
  24.335 +            } catch (Exception ex) {
  24.336 +                throw new IllegalStateException("Cannot instantiate " + name, ex);
  24.337 +            }
  24.338 +        }
  24.339 +
  24.340 +        @Override
  24.341 +        public ContextAwareDescription createContextAwareDescription(Lookup context) {
  24.342 +            return new MapMVD(map, context);
  24.343 +        }
  24.344 +
  24.345 +        @Override
  24.346 +        public boolean isSourceView() {
  24.347 +            return Boolean.TRUE.equals(map.get("sourceview")); // NOI18N
  24.348 +        }
  24.349 +    }
  24.350  }
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/text/MultiViewCloneableEditor.java	Wed May 25 16:50:33 2011 +0200
    25.3 @@ -0,0 +1,241 @@
    25.4 +/*
    25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    25.6 + *
    25.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    25.8 + *
    25.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   25.10 + * Other names may be trademarks of their respective owners.
   25.11 + *
   25.12 + * The contents of this file are subject to the terms of either the GNU
   25.13 + * General Public License Version 2 only ("GPL") or the Common
   25.14 + * Development and Distribution License("CDDL") (collectively, the
   25.15 + * "License"). You may not use this file except in compliance with the
   25.16 + * License. You can obtain a copy of the License at
   25.17 + * http://www.netbeans.org/cddl-gplv2.html
   25.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   25.19 + * specific language governing permissions and limitations under the
   25.20 + * License.  When distributing the software, include this License Header
   25.21 + * Notice in each file and include the License file at
   25.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   25.23 + * particular file as subject to the "Classpath" exception as provided
   25.24 + * by Oracle in the GPL Version 2 section of the License file that
   25.25 + * accompanied this code. If applicable, add the following below the
   25.26 + * License Header, with the fields enclosed by brackets [] replaced by
   25.27 + * your own identifying information:
   25.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   25.29 + *
   25.30 + * Contributor(s):
   25.31 + *
   25.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   25.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   25.34 + * Microsystems, Inc. All Rights Reserved.
   25.35 + *
   25.36 + * If you wish your version of this file to be governed by only the CDDL
   25.37 + * or only the GPL Version 2, indicate your decision by adding
   25.38 + * "[Contributor] elects to include this software in this distribution
   25.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   25.40 + * single choice of license, a recipient has the option to distribute
   25.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   25.42 + * to extend the choice of license to its licensees as provided above.
   25.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   25.44 + * Version 2 license, then the option applies only if the new code is
   25.45 + * made subject to such option by the copyright holder.
   25.46 + */
   25.47 +
   25.48 +package org.netbeans.core.spi.multiview.text;
   25.49 +
   25.50 +import java.awt.event.ActionEvent;
   25.51 +import java.io.IOException;
   25.52 +import java.util.Enumeration;
   25.53 +import javax.swing.AbstractAction;
   25.54 +import javax.swing.Action;
   25.55 +import javax.swing.JComponent;
   25.56 +import javax.swing.JToolBar;
   25.57 +import javax.swing.text.Document;
   25.58 +import org.netbeans.api.actions.Savable;
   25.59 +import org.netbeans.core.spi.multiview.CloseOperationState;
   25.60 +import org.netbeans.core.spi.multiview.MultiViewElement;
   25.61 +import org.netbeans.core.spi.multiview.MultiViewElementCallback;
   25.62 +import org.netbeans.core.spi.multiview.MultiViewFactory;
   25.63 +import org.openide.text.CloneableEditor;
   25.64 +import org.openide.text.CloneableEditorSupport;
   25.65 +import org.openide.text.NbDocument;
   25.66 +import org.openide.util.Exceptions;
   25.67 +import org.openide.util.NbBundle.Messages;
   25.68 +import org.openide.windows.TopComponent;
   25.69 +
   25.70 +/**
   25.71 + * @author  mkleint
   25.72 + */
   25.73 +class MultiViewCloneableEditor extends CloneableEditor  implements MultiViewElement {
   25.74 +    private static final long serialVersionUID =-3126744316644172415L;
   25.75 +
   25.76 +    private transient MultiViewElementCallback multiViewObserver;
   25.77 +    private transient JToolBar bar;
   25.78 +    
   25.79 +    public MultiViewCloneableEditor() {
   25.80 +        super();
   25.81 +    }
   25.82 +    
   25.83 +    public MultiViewCloneableEditor(CloneableEditorSupport support) {
   25.84 +        super(support, true);
   25.85 +        initializeBySupport();
   25.86 +    }
   25.87 +    
   25.88 +    @Override
   25.89 +    public JComponent getToolbarRepresentation() {
   25.90 +        Document doc = getEditorPane().getDocument();
   25.91 +        if (doc instanceof NbDocument.CustomToolbar) {
   25.92 +            if (bar == null) {
   25.93 +                bar = ((NbDocument.CustomToolbar)doc).createToolbar(getEditorPane());
   25.94 +            }
   25.95 +        }
   25.96 +        if (bar == null) {
   25.97 +            bar = new JToolBar();
   25.98 +        }
   25.99 +        return bar;
  25.100 +    }
  25.101 +    
  25.102 +    @Override
  25.103 +    public javax.swing.JComponent getVisualRepresentation() {
  25.104 +        return this;
  25.105 +    }
  25.106 +    
  25.107 +    @Override
  25.108 +    public final void setMultiViewCallback(MultiViewElementCallback callback) {
  25.109 +        multiViewObserver = callback;
  25.110 +    }
  25.111 +    
  25.112 +    protected final MultiViewElementCallback getElementObserver() {
  25.113 +        return multiViewObserver;
  25.114 +    }
  25.115 +    
  25.116 +    @Override
  25.117 +    public void componentActivated() {
  25.118 +        super.componentActivated();
  25.119 +    }
  25.120 +    
  25.121 +    @Override
  25.122 +    public void componentClosed() {
  25.123 +        super.componentClosed();
  25.124 +    }
  25.125 +    
  25.126 +    @Override
  25.127 +    public void componentDeactivated() {
  25.128 +        super.componentDeactivated();
  25.129 +    }
  25.130 +    
  25.131 +    @Override
  25.132 +    public void componentHidden() {
  25.133 +        super.componentHidden();
  25.134 +    }
  25.135 +    
  25.136 +    @Override
  25.137 +    public void componentOpened() {
  25.138 +        super.componentOpened();
  25.139 +    }
  25.140 +    
  25.141 +    @Override
  25.142 +    public void componentShowing() {
  25.143 +        if (multiViewObserver != null) {
  25.144 +            updateName();
  25.145 +        }
  25.146 +        super.componentShowing();
  25.147 +    }
  25.148 +    
  25.149 +    @Override
  25.150 +    public javax.swing.Action[] getActions() {
  25.151 +        return super.getActions();
  25.152 +    }
  25.153 +    
  25.154 +    @Override
  25.155 +    public org.openide.util.Lookup getLookup() {
  25.156 +        return super.getLookup();
  25.157 +    }
  25.158 +    
  25.159 +    @Override
  25.160 +    public String preferredID() {
  25.161 +        return super.preferredID();
  25.162 +    }
  25.163 +    
  25.164 +    
  25.165 +    @Override
  25.166 +    public void requestVisible() {
  25.167 +        if (multiViewObserver != null) {
  25.168 +            multiViewObserver.requestVisible();
  25.169 +        } else {
  25.170 +            super.requestVisible();
  25.171 +        }
  25.172 +    }
  25.173 +    
  25.174 +    @Override
  25.175 +    public void requestActive() {
  25.176 +        if (multiViewObserver != null) {
  25.177 +            multiViewObserver.requestActive();
  25.178 +        } else {
  25.179 +            super.requestActive();
  25.180 +        }
  25.181 +    }
  25.182 +    
  25.183 +    
  25.184 +    @Override
  25.185 +    public void updateName() {
  25.186 +        super.updateName();
  25.187 +        if (multiViewObserver != null) {
  25.188 +            TopComponent tc = multiViewObserver.getTopComponent();
  25.189 +            tc.setHtmlDisplayName(getHtmlDisplayName());
  25.190 +            tc.setDisplayName(getDisplayName());
  25.191 +            tc.setName(getName());
  25.192 +            tc.setToolTipText(getToolTipText());
  25.193 +        }
  25.194 +    }
  25.195 +    
  25.196 +    @Override
  25.197 +    public void open() {
  25.198 +        if (multiViewObserver != null) {
  25.199 +            multiViewObserver.requestVisible();
  25.200 +        } else {
  25.201 +            super.open();
  25.202 +        }
  25.203 +        
  25.204 +    }
  25.205 +
  25.206 +    @Override
  25.207 +    protected boolean closeLast() {
  25.208 +        return super.closeLast(false);
  25.209 +    }
  25.210 +
  25.211 +    @Messages({
  25.212 +        "MSG_SaveModified=File {0} is modified. Save?"
  25.213 +    })
  25.214 +    @Override
  25.215 +    public CloseOperationState canCloseElement() {
  25.216 +        final CloneableEditorSupport sup = getLookup().lookup(CloneableEditorSupport.class);
  25.217 +        Enumeration en = getReference().getComponents();
  25.218 +        if (en.hasMoreElements()) {
  25.219 +            en.nextElement();
  25.220 +            if (en.hasMoreElements()) {
  25.221 +                // at least two is OK
  25.222 +                return CloseOperationState.STATE_OK;
  25.223 +            }
  25.224 +        }
  25.225 +        
  25.226 +        Savable sav = getLookup().lookup(Savable.class);
  25.227 +        if (sav != null) {
  25.228 +            AbstractAction save = new AbstractAction() {
  25.229 +                @Override
  25.230 +                public void actionPerformed(ActionEvent e) {
  25.231 +                    try {
  25.232 +                        sup.saveDocument();
  25.233 +                    } catch (IOException ex) {
  25.234 +                        Exceptions.printStackTrace(ex);
  25.235 +                    }
  25.236 +                }
  25.237 +            };
  25.238 +            save.putValue(Action.LONG_DESCRIPTION, Bundle.MSG_SaveModified(sav));
  25.239 +            return MultiViewFactory.createUnsafeCloseState("editor", save, null);
  25.240 +        } 
  25.241 +        return CloseOperationState.STATE_OK;
  25.242 +    }
  25.243 +    
  25.244 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/text/MultiViewEditorElement.java	Wed May 25 16:50:33 2011 +0200
    26.3 @@ -0,0 +1,186 @@
    26.4 +/*
    26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    26.6 + *
    26.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    26.8 + *
    26.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   26.10 + * Other names may be trademarks of their respective owners.
   26.11 + *
   26.12 + * The contents of this file are subject to the terms of either the GNU
   26.13 + * General Public License Version 2 only ("GPL") or the Common
   26.14 + * Development and Distribution License("CDDL") (collectively, the
   26.15 + * "License"). You may not use this file except in compliance with the
   26.16 + * License. You can obtain a copy of the License at
   26.17 + * http://www.netbeans.org/cddl-gplv2.html
   26.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   26.19 + * specific language governing permissions and limitations under the
   26.20 + * License.  When distributing the software, include this License Header
   26.21 + * Notice in each file and include the License file at
   26.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   26.23 + * particular file as subject to the "Classpath" exception as provided
   26.24 + * by Oracle in the GPL Version 2 section of the License file that
   26.25 + * accompanied this code. If applicable, add the following below the
   26.26 + * License Header, with the fields enclosed by brackets [] replaced by
   26.27 + * your own identifying information:
   26.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   26.29 + *
   26.30 + * If you wish your version of this file to be governed by only the CDDL
   26.31 + * or only the GPL Version 2, indicate your decision by adding
   26.32 + * "[Contributor] elects to include this software in this distribution
   26.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   26.34 + * single choice of license, a recipient has the option to distribute
   26.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   26.36 + * to extend the choice of license to its licensees as provided above.
   26.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   26.38 + * Version 2 license, then the option applies only if the new code is
   26.39 + * made subject to such option by the copyright holder.
   26.40 + *
   26.41 + * Contributor(s):
   26.42 + *
   26.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   26.44 + */
   26.45 +package org.netbeans.core.spi.multiview.text;
   26.46 +
   26.47 +import java.io.Serializable;
   26.48 +import javax.swing.Action;
   26.49 +import javax.swing.JComponent;
   26.50 +import javax.swing.JEditorPane;
   26.51 +import org.netbeans.core.api.multiview.MultiViews;
   26.52 +import org.netbeans.core.spi.multiview.CloseOperationState;
   26.53 +import org.netbeans.core.spi.multiview.MultiViewElement;
   26.54 +import org.netbeans.core.spi.multiview.MultiViewElement.Registration;
   26.55 +import org.netbeans.core.spi.multiview.MultiViewElementCallback;
   26.56 +import org.openide.awt.UndoRedo;
   26.57 +import org.openide.text.CloneableEditorSupport;
   26.58 +import org.openide.util.Lookup;
   26.59 +import org.openide.windows.CloneableTopComponent;
   26.60 +
   26.61 +/** Standard {@link MultiViewElement} to integrate editor with 
   26.62 + * {@link MultiViews}. It can be used directly via a factory method:
   26.63 + * <pre>
   26.64 + <code>@</code>MultiViewElement.Registration(
   26.65 +   displayName = "#BUNDLE_KEY",
   26.66 +   iconBase = "path/to/some-icon.png",
   26.67 +   mimeType = "text/yourmime",
   26.68 +   persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
   26.69 +   preferredID = "yourId",
   26.70 +   position = 1000
   26.71 + )
   26.72 + public static MultiViewEditorElement createEditor(Lookup lkp) {
   26.73 +   return new MultiViewEditorElement(lkp);
   26.74 + }</pre>
   26.75 + * Or one can subclass the class, override some methods (it is recommended
   26.76 + * to continue to call super implementation) and register the
   26.77 + * subclass.
   26.78 + *
   26.79 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   26.80 + * @since 1.24
   26.81 + */
   26.82 +public class MultiViewEditorElement implements 
   26.83 +MultiViewElement, CloneableEditorSupport.Pane, Serializable {
   26.84 +    static final long serialVersionUID = 430840231840923L;
   26.85 +    
   26.86 +    private MultiViewCloneableEditor editor;
   26.87 +
   26.88 +    /** Constructor suitable for use with {@link Registration} annotation. 
   26.89 +     * The {@link Lookup} parameter is expected to contain 
   26.90 +     * {@link CloneableEditorSupport}, otherwise it yields an exception
   26.91 +     * 
   26.92 +     * @param lookup context for the editor. Should contain instance of {@link CloneableEditorSupport}
   26.93 +     *   class
   26.94 +     * @throws IllegalArgumentException if {@link CloneableEditorSupport} is not present
   26.95 +     *   in provided {@link Lookup}
   26.96 +     */
   26.97 +    public MultiViewEditorElement(Lookup lookup) {
   26.98 +        CloneableEditorSupport sup = lookup.lookup(CloneableEditorSupport.class);
   26.99 +        if (sup == null) {
  26.100 +            throw new IllegalArgumentException("We expect CloneableEditorSupport in " + lookup);
  26.101 +        }
  26.102 +        editor = new MultiViewCloneableEditor(sup);
  26.103 +    }
  26.104 +    
  26.105 +    @Override
  26.106 +    public JComponent getVisualRepresentation() {
  26.107 +        return editor.getVisualRepresentation();
  26.108 +    }
  26.109 +
  26.110 +    @Override
  26.111 +    public JComponent getToolbarRepresentation() {
  26.112 +        return editor.getToolbarRepresentation();
  26.113 +    }
  26.114 +
  26.115 +    @Override
  26.116 +    public Action[] getActions() {
  26.117 +        return editor.getActions();
  26.118 +    }
  26.119 +
  26.120 +    @Override
  26.121 +    public Lookup getLookup() {
  26.122 +        return editor.getLookup();
  26.123 +    }
  26.124 +
  26.125 +    @Override
  26.126 +    public void componentOpened() {
  26.127 +        editor.componentOpened();
  26.128 +    }
  26.129 +
  26.130 +    @Override
  26.131 +    public void componentClosed() {
  26.132 +        editor.componentClosed();
  26.133 +    }
  26.134 +
  26.135 +    @Override
  26.136 +    public void componentShowing() {
  26.137 +        editor.componentShowing();
  26.138 +    }
  26.139 +
  26.140 +    @Override
  26.141 +    public void componentHidden() {
  26.142 +        editor.componentHidden();
  26.143 +    }
  26.144 +
  26.145 +    @Override
  26.146 +    public void componentActivated() {
  26.147 +        editor.componentActivated();
  26.148 +    }
  26.149 +
  26.150 +    @Override
  26.151 +    public void componentDeactivated() {
  26.152 +        editor.componentDeactivated();
  26.153 +    }
  26.154 +
  26.155 +    @Override
  26.156 +    public UndoRedo getUndoRedo() {
  26.157 +        return editor.getUndoRedo();
  26.158 +    }
  26.159 +
  26.160 +    @Override
  26.161 +    public void setMultiViewCallback(MultiViewElementCallback callback) {
  26.162 +        editor.setMultiViewCallback(callback);
  26.163 +    }
  26.164 +
  26.165 +    @Override
  26.166 +    public CloseOperationState canCloseElement() {
  26.167 +        return editor.canCloseElement();
  26.168 +    }
  26.169 +
  26.170 +    @Override
  26.171 +    public JEditorPane getEditorPane() {
  26.172 +        return editor.getEditorPane();
  26.173 +    }
  26.174 +
  26.175 +    @Override
  26.176 +    public CloneableTopComponent getComponent() {
  26.177 +        return editor.getComponent();
  26.178 +    }
  26.179 +
  26.180 +    @Override
  26.181 +    public void updateName() {
  26.182 +        editor.updateName();
  26.183 +    }
  26.184 +
  26.185 +    @Override
  26.186 +    public void ensureVisible() {
  26.187 +        editor.ensureVisible();
  26.188 +    }
  26.189 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/core.multiview/src/org/netbeans/core/spi/multiview/text/package.html	Wed May 25 16:50:33 2011 +0200
    27.3 @@ -0,0 +1,51 @@
    27.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    27.5 +<html>
    27.6 +<head>
    27.7 +<!--
    27.8 +   - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    27.9 +   -
   27.10 +   - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
   27.11 +   -
   27.12 +   - The contents of this file are subject to the terms of either the GNU
   27.13 +   - General Public License Version 2 only ("GPL") or the Common
   27.14 +   - Development and Distribution License("CDDL") (collectively, the
   27.15 +   - "License"). You may not use this file except in compliance with the
   27.16 +   - License. You can obtain a copy of the License at
   27.17 +   - http://www.netbeans.org/cddl-gplv2.html
   27.18 +   - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   27.19 +   - specific language governing permissions and limitations under the
   27.20 +   - License.  When distributing the software, include this License Header
   27.21 +   - Notice in each file and include the License file at
   27.22 +   - nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   27.23 +   - particular file as subject to the "Classpath" exception as provided
   27.24 +   - by Sun in the GPL Version 2 section of the License file that
   27.25 +   - accompanied this code. If applicable, add the following below the
   27.26 +   - License Header, with the fields enclosed by brackets [] replaced by
   27.27 +   - your own identifying information:
   27.28 +   - "Portions Copyrighted [year] [name of copyright owner]"
   27.29 +   -
   27.30 +   - Contributor(s):
   27.31 +   -
   27.32 +   - The Original Software is NetBeans. The Initial Developer of the Original
   27.33 +   - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   27.34 +   - Microsystems, Inc. All Rights Reserved.
   27.35 +   -
   27.36 +   - If you wish your version of this file to be governed by only the CDDL
   27.37 +   - or only the GPL Version 2, indicate your decision by adding
   27.38 +   - "[Contributor] elects to include this software in this distribution
   27.39 +   - under the [CDDL or GPL Version 2] license." If you do not indicate a
   27.40 +   - single choice of license, a recipient has the option to distribute
   27.41 +   - your version of this file under either the CDDL, the GPL Version 2 or
   27.42 +   - to extend the choice of license to its licensees as provided above.
   27.43 +   - However, if you add GPL Version 2 code and therefore, elected the GPL
   27.44 +   - Version 2 license, then the option applies only if the new code is
   27.45 +   - made subject to such option by the copyright holder.
   27.46 +  -->
   27.47 +</head>
   27.48 +<body>
   27.49 +    <p>
   27.50 +    MultiView Text provides integration between multi view
   27.51 +    infrastructure and common textual framework.
   27.52 +    </p>
   27.53 +</body>
   27.54 +</html>
    28.1 --- a/core.multiview/test/unit/src/org/netbeans/core/multiview/MultiViewCloneableTopComponentTest.java	Wed May 25 16:24:45 2011 +0200
    28.2 +++ b/core.multiview/test/unit/src/org/netbeans/core/multiview/MultiViewCloneableTopComponentTest.java	Wed May 25 16:50:33 2011 +0200
    28.3 @@ -55,10 +55,12 @@
    28.4  import java.util.Collection;
    28.5  import javax.swing.Action;
    28.6  import javax.swing.JEditorPane;
    28.7 +import javax.swing.JPanel;
    28.8  import org.netbeans.core.api.multiview.MultiViewPerspective;
    28.9  import org.netbeans.core.spi.multiview.CloseOperationHandler;
   28.10  import org.netbeans.core.spi.multiview.MultiViewElement;
   28.11  import org.netbeans.core.spi.multiview.SourceViewMarker;
   28.12 +import org.openide.text.CloneableEditor;
   28.13  import org.openide.text.CloneableEditorSupport;
   28.14  import org.openide.util.io.NbMarshalledObject;
   28.15  
   28.16 @@ -161,6 +163,86 @@
   28.17          assertFalse(desc3.equals(Accessor.DEFAULT.extractDescription(hand.getSelectedPerspective())));
   28.18          
   28.19      }
   28.20 +    public void testUpdateNameTellsAll() throws Exception {
   28.21 +        class P extends CloneableEditor {
   28.22 +            int cnt;
   28.23 +            boolean used;
   28.24 +            
   28.25 +            @Override
   28.26 +            public void updateName() {
   28.27 +                cnt++;
   28.28 +            }
   28.29 +        }
   28.30 +        final P edit1 = new P();
   28.31 +        final P edit2 = new P();
   28.32 +        final P edit3 = new P();
   28.33 +        
   28.34 +        
   28.35 +        MVElem elem1 = new MVElem() {
   28.36 +            @Override
   28.37 +            public JComponent getVisualRepresentation() {
   28.38 +                edit1.used = true;
   28.39 +                return edit1;
   28.40 +            }
   28.41 +        };
   28.42 +        MVElem elem2 = new MVElem() {
   28.43 +            @Override
   28.44 +            public JComponent getVisualRepresentation() {
   28.45 +                edit2.used = true;
   28.46 +                return edit2;
   28.47 +            }
   28.48 +        };
   28.49 +        MVElem elem3 = new SourceMVElem() {
   28.50 +            @Override
   28.51 +            public JComponent getVisualRepresentation() {
   28.52 +                edit3.used = true;
   28.53 +                return edit3;
   28.54 +            }
   28.55 +        };
   28.56 +        MultiViewDescription desc1 = new MVDesc("desc1", null, 0, elem1);
   28.57 +        MultiViewDescription desc2 = new MVDesc("desc2", null, 0, elem2);
   28.58 +        MultiViewDescription desc3 = new SourceMVDesc("desc3", null, 0, elem3);
   28.59 +        MultiViewDescription[] descs = new MultiViewDescription[] { desc1, desc2, desc3 };
   28.60 +        CloneableTopComponent tc = MultiViewFactory.createCloneableMultiView(descs, desc1);
   28.61 +        
   28.62 +        tc.open();
   28.63 +        tc.requestActive();
   28.64 +        CloneableEditorSupport.Pane pane = (CloneableEditorSupport.Pane)tc;
   28.65 +        
   28.66 +        assertTrue("First one is used", edit1.used);
   28.67 +        assertFalse("Second one is not used", edit2.used);
   28.68 +        assertFalse("Third one is not used", edit3.used);
   28.69 +        
   28.70 +        edit1.cnt = 0;
   28.71 +        edit2.cnt = 0;
   28.72 +        edit3.cnt = 0;
   28.73 +        pane.updateName();
   28.74 +        
   28.75 +        assertTrue("First one is used (obviously)", edit1.used);
   28.76 +        assertFalse("Second one is still not used", edit2.used);
   28.77 +        assertTrue("Third one is now used", edit3.used);
   28.78 +        
   28.79 +        assertEquals("Update name called on first as it is used", 1, edit1.cnt);
   28.80 +        assertEquals("Update name called on third as it marked", 1, edit3.cnt);
   28.81 +        assertEquals("No call to 2nd one", 0, edit2.cnt);
   28.82 +        
   28.83 +        MultiViewHandler h = MultiViews.findMultiViewHandler(tc);
   28.84 +        h.requestActive(h.getPerspectives()[1]);
   28.85 +        h.requestVisible(h.getPerspectives()[1]);
   28.86 +        
   28.87 +        edit1.cnt = 0;
   28.88 +        edit2.cnt = 0;
   28.89 +        edit3.cnt = 0;
   28.90 +        pane.updateName();
   28.91 +        
   28.92 +        assertTrue("1st is used", edit1.used);
   28.93 +        assertTrue("2nd is used", edit2.used);
   28.94 +        assertTrue("3rd is now used", edit3.used);
   28.95 +        
   28.96 +        assertEquals("All updateName called: 1st", 1, edit1.cnt);
   28.97 +        assertEquals("All updateName called: 2nd", 1, edit2.cnt);
   28.98 +        assertEquals("All updateName called: 3rd", 1, edit3.cnt);
   28.99 +    }
  28.100      
  28.101      private class SourceMVDesc extends MVDesc implements SourceViewMarker {
  28.102          public SourceMVDesc(String name, Image img, int persType, MultiViewElement element) {
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/core.multiview/test/unit/src/org/netbeans/core/multiview/MultiViewProcessorTest.java	Wed May 25 16:50:33 2011 +0200
    29.3 @@ -0,0 +1,464 @@
    29.4 +/*
    29.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    29.6 + *
    29.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    29.8 + *
    29.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   29.10 + * Other names may be trademarks of their respective owners.
   29.11 + *
   29.12 + * The contents of this file are subject to the terms of either the GNU
   29.13 + * General Public License Version 2 only ("GPL") or the Common
   29.14 + * Development and Distribution License("CDDL") (collectively, the
   29.15 + * "License"). You may not use this file except in compliance with the
   29.16 + * License. You can obtain a copy of the License at
   29.17 + * http://www.netbeans.org/cddl-gplv2.html
   29.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   29.19 + * specific language governing permissions and limitations under the
   29.20 + * License.  When distributing the software, include this License Header
   29.21 + * Notice in each file and include the License file at
   29.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   29.23 + * particular file as subject to the "Classpath" exception as provided
   29.24 + * by Oracle in the GPL Version 2 section of the License file that
   29.25 + * accompanied this code. If applicable, add the following below the
   29.26 + * License Header, with the fields enclosed by brackets [] replaced by
   29.27 + * your own identifying information:
   29.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   29.29 + *
   29.30 + * If you wish your version of this file to be governed by only the CDDL
   29.31 + * or only the GPL Version 2, indicate your decision by adding
   29.32 + * "[Contributor] elects to include this software in this distribution
   29.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   29.34 + * single choice of license, a recipient has the option to distribute
   29.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   29.36 + * to extend the choice of license to its licensees as provided above.
   29.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   29.38 + * Version 2 license, then the option applies only if the new code is
   29.39 + * made subject to such option by the copyright holder.
   29.40 + *
   29.41 + * Contributor(s):
   29.42 + *
   29.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   29.44 + */
   29.45 +package org.netbeans.core.multiview;
   29.46 +
   29.47 +import java.awt.Dialog;
   29.48 +import java.awt.event.ActionEvent;
   29.49 +import java.io.ByteArrayOutputStream;
   29.50 +import java.io.Serializable;
   29.51 +import java.util.Arrays;
   29.52 +import java.util.HashMap;
   29.53 +import java.util.Map;
   29.54 +import java.util.logging.Level;
   29.55 +import javax.swing.AbstractAction;
   29.56 +import javax.swing.Action;
   29.57 +import javax.swing.JComponent;
   29.58 +import javax.swing.JEditorPane;
   29.59 +import javax.swing.JPanel;
   29.60 +import org.netbeans.api.editor.mimelookup.MimeLookup;
   29.61 +import org.netbeans.api.editor.mimelookup.MimeRegistration;
   29.62 +import org.netbeans.core.api.multiview.MultiViewHandler;
   29.63 +import org.netbeans.core.api.multiview.MultiViewPerspective;
   29.64 +import org.netbeans.core.api.multiview.MultiViews;
   29.65 +import org.netbeans.core.spi.multiview.CloseOperationHandler;
   29.66 +import org.netbeans.core.spi.multiview.CloseOperationState;
   29.67 +import org.netbeans.core.spi.multiview.MultiViewDescription;
   29.68 +import org.netbeans.core.spi.multiview.MultiViewElement;
   29.69 +import org.netbeans.core.spi.multiview.MultiViewElementCallback;
   29.70 +import org.netbeans.core.spi.multiview.MultiViewFactory;
   29.71 +import org.netbeans.junit.Log;
   29.72 +import org.netbeans.junit.MockServices;
   29.73 +import org.netbeans.junit.NbTestCase;
   29.74 +import org.openide.DialogDescriptor;
   29.75 +import org.openide.DialogDisplayer;
   29.76 +import org.openide.NotifyDescriptor;
   29.77 +import org.openide.awt.UndoRedo;
   29.78 +import org.openide.text.CloneableEditorSupport;
   29.79 +import org.openide.util.Lookup;
   29.80 +import org.openide.util.io.NbMarshalledObject;
   29.81 +import org.openide.util.lookup.AbstractLookup;
   29.82 +import org.openide.util.lookup.InstanceContent;
   29.83 +import org.openide.util.test.AnnotationProcessorTestUtils;
   29.84 +import org.openide.windows.CloneableTopComponent;
   29.85 +import org.openide.windows.TopComponent;
   29.86 +
   29.87 +/**
   29.88 + *
   29.89 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   29.90 + */
   29.91 +public class MultiViewProcessorTest extends NbTestCase {
   29.92 +    
   29.93 +    public MultiViewProcessorTest(String n) {
   29.94 +        super(n);
   29.95 +    }
   29.96 +
   29.97 +    @Override
   29.98 +    protected void setUp() throws Exception {
   29.99 +        MVE.closeState = null;
  29.100 +        CloseH.globalElements = null;
  29.101 +        CloseH.retValue = null;
  29.102 +        DD.d = null;
  29.103 +        DD.ret = -1;
  29.104 +        MockServices.setServices(DD.class);
  29.105 +    }
  29.106 +
  29.107 +    public void testMultiViewsCreate() {
  29.108 +        TopComponent mvc = MultiViews.createMultiView("text/figaro", new LP(Lookup.EMPTY));
  29.109 +        assertNotNull("MultiViewComponent created", mvc);
  29.110 +        mvc.open();
  29.111 +        mvc.requestActive();
  29.112 +        
  29.113 +        MultiViewHandler handler = MultiViews.findMultiViewHandler(mvc);
  29.114 +        assertNotNull("Handler found", handler);
  29.115 +        MultiViewPerspective[] arr = handler.getPerspectives();
  29.116 +        assertEquals("One perspetive found", 1, arr.length);
  29.117 +        assertEquals("Figaro", arr[0].getDisplayName());
  29.118 +
  29.119 +        CloseH.retValue = true;
  29.120 +        MVE.closeState = MultiViewFactory.createUnsafeCloseState("warn", null, null);
  29.121 +        assertTrue("Closed OK", mvc.close());
  29.122 +        assertNotNull(CloseH.globalElements);
  29.123 +        assertEquals("One handle", 1, CloseH.globalElements.length);
  29.124 +        assertEquals("states are the same", MVE.closeState, CloseH.globalElements[0]);
  29.125 +    }
  29.126 +
  29.127 +    public void testCloneableMultiViewsCreate() {
  29.128 +        InstanceContent ic = new InstanceContent();
  29.129 +        Lookup lookup = new AbstractLookup(ic);
  29.130 +        
  29.131 +        CloneableTopComponent cmv = MultiViews.createCloneableMultiView("text/context", new LP(lookup));
  29.132 +        assertNotNull("MultiViewComponent created", cmv);
  29.133 +        TopComponent mvc = cmv.cloneTopComponent();
  29.134 +        doCheck(mvc, ic);
  29.135 +        
  29.136 +        CntAction accept = new CntAction();
  29.137 +        CntAction discard = new CntAction();
  29.138 +        CloseH.retValue = false;
  29.139 +        MVE.closeState = MultiViewFactory.createUnsafeCloseState("warn", accept, discard);
  29.140 +        DD.ret = 2;
  29.141 +        mvc.open();
  29.142 +        assertFalse("Closed cancelled", mvc.close());
  29.143 +        assertEquals("No accept", 0, accept.cnt);
  29.144 +        assertEquals("No discard", 0, discard.cnt);
  29.145 +        MVE.closeState = MultiViewFactory.createUnsafeCloseState("warn", accept, discard);
  29.146 +        DD.ret = 1;
  29.147 +        DD.d = null;
  29.148 +        mvc.open();
  29.149 +        assertTrue("Changes discarded, close accepted", mvc.close());
  29.150 +        assertEquals("Still no accept", 0, accept.cnt);
  29.151 +        assertEquals("One discard", 1, discard.cnt);
  29.152 +        MVE.closeState = MultiViewFactory.createUnsafeCloseState("warn", accept, discard);
  29.153 +        DD.ret = 0;
  29.154 +        DD.d = null;
  29.155 +        mvc.open();
  29.156 +        assertTrue("Closed accepted OK", mvc.close());
  29.157 +        assertEquals("Three buttons", 3, DD.d.getOptions().length);
  29.158 +        assertNull("Not called, we use default handler", CloseH.globalElements);
  29.159 +    }
  29.160 +
  29.161 +    public void testCloneableMultiViewsSerialize() throws Exception {
  29.162 +        InstanceContent ic = new InstanceContent();
  29.163 +        Lookup lookup = new AbstractLookup(ic);
  29.164 +        
  29.165 +        CloneableTopComponent cmv = MultiViews.createCloneableMultiView("text/context", new LP(lookup));
  29.166 +        assertPersistence("Always", TopComponent.PERSISTENCE_ALWAYS, cmv);
  29.167 +        assertNotNull("MultiViewComponent created", cmv);
  29.168 +        NbMarshalledObject mar = new NbMarshalledObject(cmv);
  29.169 +        TopComponent mvc = (TopComponent) mar.get();
  29.170 +        doCheck(mvc, ic);
  29.171 +    }
  29.172 +
  29.173 +    private void assertPersistence(String msg, int pt, TopComponent cmv) {
  29.174 +        CharSequence log = Log.enable("org.netbeans.core.multiview", Level.WARNING);
  29.175 +        int res = cmv.getPersistenceType();
  29.176 +        if (log.length() > 0) {
  29.177 +            fail("There should be no warnings to compute getPersistenceType():\n" + log);
  29.178 +        }
  29.179 +        assertEquals(msg, pt, res);
  29.180 +    }
  29.181 +    
  29.182 +    private void doCheck(TopComponent mvc, InstanceContent ic) {
  29.183 +        assertNotNull("MultiViewComponent cloned", mvc);
  29.184 +        MultiViewHandler handler = MultiViews.findMultiViewHandler(mvc);
  29.185 +        assertNotNull("Handler found", handler);
  29.186 +        MultiViewPerspective[] arr = handler.getPerspectives();
  29.187 +        assertEquals("One perspetive found", 1, arr.length);
  29.188 +        assertEquals("Contextual", arr[0].getDisplayName());
  29.189 +
  29.190 +        assertPersistence("Always", TopComponent.PERSISTENCE_ALWAYS, mvc);
  29.191 +        
  29.192 +        mvc.open();
  29.193 +        mvc.requestActive();
  29.194 +        mvc.requestVisible();
  29.195 +        
  29.196 +        handler.requestActive(arr[0]);
  29.197 +        assertNull("No integer now", mvc.getLookup().lookup(Integer.class));
  29.198 +        ic.add(1);
  29.199 +        assertEquals("1 now", Integer.valueOf(1), mvc.getLookup().lookup(Integer.class));
  29.200 +    }
  29.201 +    
  29.202 +    public void testNotSourceView() {
  29.203 +        int cnt = 0;
  29.204 +        for (MultiViewDescription d : MimeLookup.getLookup("text/context").lookupAll(MultiViewDescription.class)) {
  29.205 +            cnt++;
  29.206 +            assertFalse(
  29.207 +                "No view in text/context has source element",
  29.208 +                MultiViewCloneableTopComponent.isSourceView(d)
  29.209 +            );
  29.210 +        }
  29.211 +        if (cnt == 0) {
  29.212 +            fail("There shall be at least one description");
  29.213 +        }
  29.214 +    }
  29.215 +    
  29.216 +    public void testCompileInApt() throws Exception {
  29.217 +        clearWorkDir();
  29.218 +        String src = "\n"
  29.219 +                + "import org.netbeans.core.spi.multiview.MultiViewElement;\n"
  29.220 +                + "public class Test extends org.netbeans.core.multiview.MultiViewProcessorTest.MVE {\n"
  29.221 +        + "@MultiViewElement.Registration(displayName = \"Testing\","
  29.222 +        + "iconBase = \"none\","
  29.223 +        + "mimeType = \"text/ble\","
  29.224 +        + "persistenceType = 0,"
  29.225 +        + "preferredID = \"bleple\")"
  29.226 +                + "  public static MultiViewElement create() {\n"
  29.227 +                + "    return new Test();\n"
  29.228 +                + "  }\n"
  29.229 +                + "}\n";
  29.230 +        AnnotationProcessorTestUtils.makeSource(getWorkDir(), "pkg.Test", src);
  29.231 +        ByteArrayOutputStream os = new ByteArrayOutputStream();
  29.232 +        boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, os);
  29.233 +        assertTrue("Compilation should succeed:\n" + os.toString(), res);
  29.234 +    }
  29.235 +    
  29.236 +    public void testIsSourceView() {
  29.237 +        int cnt = 0;
  29.238 +        for (MultiViewDescription d : MimeLookup.getLookup("text/plain").lookupAll(MultiViewDescription.class)) {
  29.239 +            cnt++;
  29.240 +            assertTrue(
  29.241 +                "All views in text/plain have source element: " + d,
  29.242 +                MultiViewCloneableTopComponent.isSourceView(d)
  29.243 +            );
  29.244 +        }
  29.245 +        if (cnt == 0) {
  29.246 +            fail("There shall be at least one description");
  29.247 +        }
  29.248 +    }
  29.249 +
  29.250 +    public void testMultiViewsContextCreate() {
  29.251 +        InstanceContent ic = new InstanceContent();
  29.252 +        Lookup lookup = new AbstractLookup(ic);
  29.253 +        
  29.254 +        TopComponent mvc = MultiViews.createMultiView("text/context", new LP(lookup));
  29.255 +        assertNotNull("MultiViewComponent created", mvc);
  29.256 +        MultiViewHandler handler = MultiViews.findMultiViewHandler(mvc);
  29.257 +        assertNotNull("Handler found", handler);
  29.258 +        MultiViewPerspective[] arr = handler.getPerspectives();
  29.259 +        assertEquals("One perspetive found", 1, arr.length);
  29.260 +        assertEquals("Contextual", arr[0].getDisplayName());
  29.261 +        
  29.262 +        mvc.open();
  29.263 +        mvc.requestActive();
  29.264 +        mvc.requestVisible();
  29.265 +        
  29.266 +        handler.requestActive(arr[0]);
  29.267 +        assertNull("No integer now", mvc.getLookup().lookup(Integer.class));
  29.268 +        ic.add(1);
  29.269 +        assertEquals("1 now", Integer.valueOf(1), mvc.getLookup().lookup(Integer.class));
  29.270 +    }
  29.271 +
  29.272 +    @MimeRegistration(mimeType="text/figaro", service=CloseOperationHandler.class)
  29.273 +    public static class CloseH implements CloseOperationHandler {
  29.274 +        static CloseOperationState[] globalElements;
  29.275 +        static Boolean retValue;
  29.276 +        @Override
  29.277 +        public boolean resolveCloseOperation(CloseOperationState[] elements) {
  29.278 +            assertNull("globalElement not specified yet", globalElements);
  29.279 +            assertNotNull("We know what to return", retValue);
  29.280 +            boolean r = retValue;
  29.281 +            retValue = null;
  29.282 +            globalElements = elements;
  29.283 +            return r;
  29.284 +        }
  29.285 +    }
  29.286 +
  29.287 +    @MultiViewElement.Registration(
  29.288 +        displayName="org.netbeans.core.multiview.TestBundle#FIGARO",
  29.289 +        iconBase="none",
  29.290 +        mimeType="text/figaro",
  29.291 +        persistenceType=TopComponent.PERSISTENCE_NEVER,
  29.292 +        preferredID="figaro"
  29.293 +    )
  29.294 +    public static class MVE extends JPanel implements MultiViewElement {
  29.295 +        static CloseOperationState closeState;
  29.296 +        
  29.297 +        private JPanel toolbar = new JPanel();
  29.298 +        
  29.299 +        public MVE() {
  29.300 +        }
  29.301 +        
  29.302 +        @Override
  29.303 +        public JComponent getVisualRepresentation() {
  29.304 +            return this;
  29.305 +        }
  29.306 +
  29.307 +        @Override
  29.308 +        public JComponent getToolbarRepresentation() {
  29.309 +            return toolbar;
  29.310 +        }
  29.311 +
  29.312 +        @Override
  29.313 +        public Action[] getActions() {
  29.314 +            return new Action[0];
  29.315 +        }
  29.316 +
  29.317 +        @Override
  29.318 +        public Lookup getLookup() {
  29.319 +            return Lookup.EMPTY;
  29.320 +        }
  29.321 +
  29.322 +        @Override
  29.323 +        public void componentOpened() {
  29.324 +        }
  29.325 +
  29.326 +        @Override
  29.327 +        public void componentClosed() {
  29.328 +        }
  29.329 +
  29.330 +        @Override
  29.331 +        public void componentShowing() {
  29.332 +        }
  29.333 +
  29.334 +        @Override
  29.335 +        public void componentHidden() {
  29.336 +        }
  29.337 +
  29.338 +        @Override
  29.339 +        public void componentActivated() {
  29.340 +        }
  29.341 +
  29.342 +        @Override
  29.343 +        public void componentDeactivated() {
  29.344 +        }
  29.345 +
  29.346 +        @Override
  29.347 +        public UndoRedo getUndoRedo() {
  29.348 +            return UndoRedo.NONE;
  29.349 +        }
  29.350 +
  29.351 +        @Override
  29.352 +        public void setMultiViewCallback(MultiViewElementCallback callback) {
  29.353 +        }
  29.354 +
  29.355 +        @Override
  29.356 +        public CloseOperationState canCloseElement() {
  29.357 +            if (closeState != null) {
  29.358 +                return closeState;
  29.359 +            }
  29.360 +            return CloseOperationState.STATE_OK;
  29.361 +        }
  29.362 +    } // end of MVE
  29.363 +    
  29.364 +    @MultiViewElement.Registration(
  29.365 +        displayName="Contextual",
  29.366 +        iconBase="none",
  29.367 +        mimeType="text/context",
  29.368 +        persistenceType=TopComponent.PERSISTENCE_ALWAYS,
  29.369 +        preferredID="context"
  29.370 +    )
  29.371 +    public static CntxMVE create(Lookup lkp) {
  29.372 +        return new CntxMVE(lkp);
  29.373 +    }
  29.374 +    static class CntxMVE extends MVE {
  29.375 +        private Lookup context;
  29.376 +        public CntxMVE(Lookup context) {
  29.377 +            this.context = context;
  29.378 +        }
  29.379 +        public CntxMVE() {
  29.380 +        }
  29.381 +
  29.382 +        @Override
  29.383 +        public Lookup getLookup() {
  29.384 +            return context;
  29.385 +        }
  29.386 +    } // end of CntxMVE
  29.387 +
  29.388 +    @MultiViewElement.Registration(
  29.389 +        displayName="Source",
  29.390 +        iconBase="none",
  29.391 +        mimeType="text/plain",
  29.392 +        persistenceType=TopComponent.PERSISTENCE_NEVER,
  29.393 +        preferredID="source"
  29.394 +    )
  29.395 +    public static class SourceMVC extends MVE implements CloneableEditorSupport.Pane {
  29.396 +        @Override
  29.397 +        public JEditorPane getEditorPane() {
  29.398 +            throw new UnsupportedOperationException("Not supported yet.");
  29.399 +        }
  29.400 +
  29.401 +        @Override
  29.402 +        public CloneableTopComponent getComponent() {
  29.403 +            throw new UnsupportedOperationException("Not supported yet.");
  29.404 +        }
  29.405 +
  29.406 +        @Override
  29.407 +        public void updateName() {
  29.408 +            throw new UnsupportedOperationException("Not supported yet.");
  29.409 +        }
  29.410 +
  29.411 +        @Override
  29.412 +        public void ensureVisible() {
  29.413 +            throw new UnsupportedOperationException("Not supported yet.");
  29.414 +        }
  29.415 +    }
  29.416 +    
  29.417 +    private static class LP implements Lookup.Provider, Serializable {
  29.418 +        private static final Map<Integer,Lookup> map = new HashMap<Integer, Lookup>();
  29.419 +        
  29.420 +        private final int cnt;
  29.421 +        public LP(Lookup lkp) {
  29.422 +            synchronized (map) {
  29.423 +                cnt = map.size() + 1;
  29.424 +                map.put(cnt, lkp);
  29.425 +            }
  29.426 +        }
  29.427 +        
  29.428 +        @Override
  29.429 +        public Lookup getLookup() {
  29.430 +            return map.get(cnt);
  29.431 +        }
  29.432 +    }
  29.433 +    
  29.434 +    public static final class DD extends DialogDisplayer {
  29.435 +        static int ret;
  29.436 +        static NotifyDescriptor d;
  29.437 +        
  29.438 +        @Override
  29.439 +        public Object notify(NotifyDescriptor descriptor) {
  29.440 +            assertNull("No descriptor yet", d);
  29.441 +            if (ret == -1) {
  29.442 +                fail("We should know what to return");
  29.443 +            }
  29.444 +            d = descriptor;
  29.445 +            if (d.getOptions().length <= ret) {
  29.446 +                fail("not enough options. Need index " + ret + " but is just " + Arrays.toString(d.getOptions()));
  29.447 +            }
  29.448 +            Object obj = d.getOptions()[ret];
  29.449 +            ret = -1;
  29.450 +            return obj;
  29.451 +        }
  29.452 +
  29.453 +        @Override
  29.454 +        public Dialog createDialog(DialogDescriptor descriptor) {
  29.455 +            throw new UnsupportedOperationException("Not supported yet.");
  29.456 +        }
  29.457 +    }
  29.458 +    
  29.459 +    private static final class CntAction extends AbstractAction {
  29.460 +        int cnt;
  29.461 +        
  29.462 +        @Override
  29.463 +        public void actionPerformed(ActionEvent e) {
  29.464 +            cnt++;
  29.465 +        }
  29.466 +    }
  29.467 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/core.multiview/test/unit/src/org/netbeans/core/multiview/TestBundle.properties	Wed May 25 16:50:33 2011 +0200
    30.3 @@ -0,0 +1,41 @@
    30.4 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    30.5 +#
    30.6 +# Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    30.7 +#
    30.8 +# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    30.9 +# Other names may be trademarks of their respective owners.
   30.10 +#
   30.11 +# The contents of this file are subject to the terms of either the GNU
   30.12 +# General Public License Version 2 only ("GPL") or the Common
   30.13 +# Development and Distribution License("CDDL") (collectively, the
   30.14 +# "License"). You may not use this file except in compliance with the
   30.15 +# License. You can obtain a copy of the License at
   30.16 +# http://www.netbeans.org/cddl-gplv2.html
   30.17 +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   30.18 +# specific language governing permissions and limitations under the
   30.19 +# License.  When distributing the software, include this License Header
   30.20 +# Notice in each file and include the License file at
   30.21 +# nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   30.22 +# particular file as subject to the "Classpath" exception as provided
   30.23 +# by Oracle in the GPL Version 2 section of the License file that
   30.24 +# accompanied this code. If applicable, add the following below the
   30.25 +# License Header, with the fields enclosed by brackets [] replaced by
   30.26 +# your own identifying information:
   30.27 +# "Portions Copyrighted [year] [name of copyright owner]"
   30.28 +#
   30.29 +# If you wish your version of this file to be governed by only the CDDL
   30.30 +# or only the GPL Version 2, indicate your decision by adding
   30.31 +# "[Contributor] elects to include this software in this distribution
   30.32 +# under the [CDDL or GPL Version 2] license." If you do not indicate a
   30.33 +# single choice of license, a recipient has the option to distribute
   30.34 +# your version of this file under either the CDDL, the GPL Version 2 or
   30.35 +# to extend the choice of license to its licensees as provided above.
   30.36 +# However, if you add GPL Version 2 code and therefore, elected the GPL
   30.37 +# Version 2 license, then the option applies only if the new code is
   30.38 +# made subject to such option by the copyright holder.
   30.39 +#
   30.40 +# Contributor(s):
   30.41 +#
   30.42 +# Portions Copyrighted 2011 Sun Microsystems, Inc.
   30.43 +
   30.44 +FIGARO=Figaro
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/core.multiview/test/unit/src/org/netbeans/core/spi/multiview/text/MultiViewEditorElementTest.java	Wed May 25 16:50:33 2011 +0200
    31.3 @@ -0,0 +1,273 @@
    31.4 +/*
    31.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    31.6 + *
    31.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
    31.8 + *
    31.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   31.10 + * Other names may be trademarks of their respective owners.
   31.11 + *
   31.12 + * The contents of this file are subject to the terms of either the GNU
   31.13 + * General Public License Version 2 only ("GPL") or the Common
   31.14 + * Development and Distribution License("CDDL") (collectively, the
   31.15 + * "License"). You may not use this file except in compliance with the
   31.16 + * License. You can obtain a copy of the License at
   31.17 + * http://www.netbeans.org/cddl-gplv2.html
   31.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   31.19 + * specific language governing permissions and limitations under the
   31.20 + * License.  When distributing the software, include this License Header
   31.21 + * Notice in each file and include the License file at
   31.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   31.23 + * particular file as subject to the "Classpath" exception as provided
   31.24 + * by Oracle in the GPL Version 2 section of the License file that
   31.25 + * accompanied this code. If applicable, add the following below the
   31.26 + * License Header, with the fields enclosed by brackets [] replaced by
   31.27 + * your own identifying information:
   31.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   31.29 + *
   31.30 + * If you wish your version of this file to be governed by only the CDDL
   31.31 + * or only the GPL Version 2, indicate your decision by adding
   31.32 + * "[Contributor] elects to include this software in this distribution
   31.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   31.34 + * single choice of license, a recipient has the option to distribute
   31.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   31.36 + * to extend the choice of license to its licensees as provided above.
   31.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   31.38 + * Version 2 license, then the option applies only if the new code is
   31.39 + * made subject to such option by the copyright holder.
   31.40 + *
   31.41 + * Contributor(s):
   31.42 + *
   31.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
   31.44 + */
   31.45 +package org.netbeans.core.spi.multiview.text;
   31.46 +
   31.47 +import java.beans.PropertyChangeListener;
   31.48 +import java.beans.VetoableChangeListener;
   31.49 +import java.io.ByteArrayInputStream;
   31.50 +import java.io.ByteArrayOutputStream;
   31.51 +import java.io.IOException;
   31.52 +import java.io.InputStream;
   31.53 +import java.io.OutputStream;
   31.54 +import java.io.Serializable;
   31.55 +import java.util.Date;
   31.56 +import org.netbeans.junit.NbTestCase;
   31.57 +import org.openide.text.CloneableEditorSupport;
   31.58 +import org.openide.util.Lookup;
   31.59 +import org.openide.util.io.NbMarshalledObject;
   31.60 +import org.openide.util.lookup.AbstractLookup;
   31.61 +import org.openide.util.lookup.InstanceContent;
   31.62 +import org.openide.windows.CloneableOpenSupport;
   31.63 +
   31.64 +
   31.65 +/**
   31.66 + *
   31.67 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   31.68 + */
   31.69 +public class MultiViewEditorElementTest extends NbTestCase {
   31.70 +    
   31.71 +    public MultiViewEditorElementTest(String n) {
   31.72 +        super(n);
   31.73 +    }
   31.74 +
   31.75 +    public void testLookupMustContainCES() throws Exception {
   31.76 +        try {
   31.77 +            MultiViewEditorElement mvee = new MultiViewEditorElement(Lookup.EMPTY);
   31.78 +        } catch (IllegalArgumentException ex) {
   31.79 +            // OK
   31.80 +            return;
   31.81 +        }
   31.82 +        fail("Should throw an exception");
   31.83 +    }
   31.84 +    
   31.85 +    public void testSerializeAndDeserialize() throws Exception {
   31.86 +        InstanceContent ic = new InstanceContent();
   31.87 +        Lookup context = new AbstractLookup(ic);
   31.88 +        
   31.89 +        Env env = new Env();
   31.90 +        CES ces = new CES(env, context);
   31.91 +        env.setSupport(ces);
   31.92 +        ic.add(ces);
   31.93 +        ic.add(10);
   31.94 +        
   31.95 +        MultiViewEditorElement mvee = new MultiViewEditorElement(context);
   31.96 +        
   31.97 +        assertEquals("ces", ces, mvee.getLookup().lookup(CloneableEditorSupport.class));
   31.98 +        assertEquals("ten", Integer.valueOf(10), mvee.getLookup().lookup(Integer.class));
   31.99 +        
  31.100 +        NbMarshalledObject mar = new NbMarshalledObject(mvee);
  31.101 +        MultiViewEditorElement deser = (MultiViewEditorElement)mar.get();
  31.102 +        
  31.103 +        assertEquals("ten", Integer.valueOf(10), deser.getLookup().lookup(Integer.class));
  31.104 +        assertEquals("ces", ces, deser.getLookup().lookup(CloneableEditorSupport.class));
  31.105 +    }
  31.106 +    
  31.107 +    
  31.108 +    static class CES extends CloneableEditorSupport {
  31.109 +        public CES(Env env, Lookup l) {
  31.110 +            super(env, l);
  31.111 +        }
  31.112 +
  31.113 +        @Override
  31.114 +        protected String messageSave() {
  31.115 +            return "do save";
  31.116 +        }
  31.117 +
  31.118 +        @Override
  31.119 +        protected String messageName() {
  31.120 +            return "MY NAME";
  31.121 +        }
  31.122 +
  31.123 +        @Override
  31.124 +        protected String messageToolTip() {
  31.125 +            return "tool tip";
  31.126 +        }
  31.127 +
  31.128 +        @Override
  31.129 +        protected String messageOpening() {
  31.130 +            return "about to open";
  31.131 +        }
  31.132 +
  31.133 +        @Override
  31.134 +        protected String messageOpened() {
  31.135 +            return "done opening";
  31.136 +        }
  31.137 +    } // end of CES
  31.138 +    
  31.139 +    /** Helper Env implementation. */
  31.140 +    public static class Env extends Object
  31.141 +    implements CloneableEditorSupport.Env, Serializable {
  31.142 +        private static Env LAST_ONE;
  31.143 +        
  31.144 +        /** object to serialize and be connected to*/
  31.145 +        private transient String output;
  31.146 +        /** Reference to support instance. */
  31.147 +        private transient CloneableOpenSupport support;
  31.148 +
  31.149 +        /** Constructor. Attaches itself as listener to 
  31.150 +         * the data object so, all property changes of the data object
  31.151 +         * are also rethrown to own listeners.
  31.152 +         *
  31.153 +         * @param obj data object to be attached to
  31.154 +         */
  31.155 +        public Env() {
  31.156 +            LAST_ONE = this;
  31.157 +        }
  31.158 +
  31.159 +        public void setSupport(CloneableOpenSupport support) {
  31.160 +            this.support = support;
  31.161 +        }
  31.162 +
  31.163 +        /** Method that allows environment to find its 
  31.164 +         * cloneable open support.
  31.165 +         * @return the support or null if the environemnt is not in valid 
  31.166 +         * state and the CloneableOpenSupport cannot be found for associated
  31.167 +         * data object
  31.168 +         */
  31.169 +        @Override
  31.170 +        public CloneableOpenSupport findCloneableOpenSupport() {
  31.171 +            return support;
  31.172 +        }
  31.173 +
  31.174 +        /** Obtains the input stream.
  31.175 +         * @exception IOException if an I/O error occures
  31.176 +         */
  31.177 +        @Override
  31.178 +        public InputStream inputStream() throws IOException {
  31.179 +            return new ByteArrayInputStream(output.getBytes());
  31.180 +        }
  31.181 +
  31.182 +        /** Obtains the output stream.
  31.183 +         * @exception IOException if an I/O error occures
  31.184 +         */
  31.185 +        @Override
  31.186 +        public OutputStream outputStream() throws IOException {
  31.187 +            return new ByteArrayOutputStream() {
  31.188 +
  31.189 +                @Override
  31.190 +                public void close() throws IOException {
  31.191 +                    super.close();
  31.192 +                    output = new String(toByteArray());
  31.193 +                }
  31.194 +            };
  31.195 +        }
  31.196 +
  31.197 +        Date date = new Date();
  31.198 +        /** The time when the data has been modified */
  31.199 +        @Override
  31.200 +        public Date getTime() {
  31.201 +            return date;
  31.202 +        }
  31.203 +
  31.204 +        /** Mime type of the document.
  31.205 +         * @return the mime type to use for the document
  31.206 +         */
  31.207 +        @Override
  31.208 +        public String getMimeType() {
  31.209 +            return "text/test";
  31.210 +        }
  31.211 +
  31.212 +        /** Adds property listener.
  31.213 +         */
  31.214 +        @Override
  31.215 +        public void addPropertyChangeListener(PropertyChangeListener l) {
  31.216 +        }
  31.217 +
  31.218 +        /** Removes property listener.
  31.219 +         */
  31.220 +        @Override
  31.221 +        public void removePropertyChangeListener(PropertyChangeListener l) {
  31.222 +        }
  31.223 +
  31.224 +        /** Adds veto listener.
  31.225 +         */
  31.226 +        @Override
  31.227 +        public void addVetoableChangeListener(VetoableChangeListener l) {
  31.228 +        }
  31.229 +
  31.230 +        /** Removes veto listener.
  31.231 +         */
  31.232 +        @Override
  31.233 +        public void removeVetoableChangeListener(VetoableChangeListener l) {
  31.234 +        }
  31.235 +
  31.236 +        /** Test whether the support is in valid state or not.
  31.237 +         * It could be invalid after deserialization when the object it
  31.238 +         * referenced to does not exist anymore.
  31.239 +         *
  31.240 +         * @return true or false depending on its state
  31.241 +         */
  31.242 +        @Override
  31.243 +        public boolean isValid() {
  31.244 +            return true;
  31.245 +        }
  31.246 +
  31.247 +        /** Test whether the object is modified or not.
  31.248 +         * @return true if the object is modified
  31.249 +         */
  31.250 +        @Override
  31.251 +        public boolean isModified() {
  31.252 +            return false;
  31.253 +        }
  31.254 +
  31.255 +        /** Support for marking the environement modified.
  31.256 +         * @exception IOException if the environment cannot be marked modified
  31.257 +         *    (for example when the file is readonly), when such exception
  31.258 +         *    is the support should discard all previous changes
  31.259 +         */
  31.260 +        @Override
  31.261 +        public void markModified() throws java.io.IOException {
  31.262 +        }
  31.263 +
  31.264 +        /** Reverse method that can be called to make the environment 
  31.265 +         * unmodified.
  31.266 +         */
  31.267 +        @Override
  31.268 +        public void unmarkModified() {
  31.269 +        }
  31.270 +        
  31.271 +        private Object readResolve() {
  31.272 +            return LAST_ONE;
  31.273 +        }
  31.274 +    } // End of Env class.
  31.275 +    
  31.276 +}
    32.1 --- a/form/nbproject/project.xml	Wed May 25 16:24:45 2011 +0200
    32.2 +++ b/form/nbproject/project.xml	Wed May 25 16:50:33 2011 +0200
    32.3 @@ -98,7 +98,7 @@
    32.4                      <compile-dependency/>
    32.5                      <run-dependency>
    32.6                          <release-version>1</release-version>
    32.7 -                        <specification-version>1.10</specification-version>
    32.8 +                        <specification-version>1.24</specification-version>
    32.9                      </run-dependency>
   32.10                  </dependency>
   32.11                  <dependency>
   32.12 @@ -163,6 +163,15 @@
   32.13                      </run-dependency>
   32.14                  </dependency>
   32.15                  <dependency>
   32.16 +                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
   32.17 +                    <build-prerequisite/>
   32.18 +                    <compile-dependency/>
   32.19 +                    <run-dependency>
   32.20 +                        <release-version>1</release-version>
   32.21 +                        <specification-version>1.21</specification-version>
   32.22 +                    </run-dependency>
   32.23 +                </dependency>
   32.24 +                <dependency>
   32.25                      <code-name-base>org.netbeans.modules.java.project</code-name-base>
   32.26                      <build-prerequisite/>
   32.27                      <compile-dependency/>
    33.1 --- a/form/src/org/netbeans/modules/form/FormDesignerTC.java	Wed May 25 16:24:45 2011 +0200
    33.2 +++ b/form/src/org/netbeans/modules/form/FormDesignerTC.java	Wed May 25 16:50:33 2011 +0200
    33.3 @@ -64,16 +64,23 @@
    33.4  import org.netbeans.modules.form.assistant.AssistantView;
    33.5  import org.openide.actions.FileSystemAction;
    33.6  import org.openide.awt.StatusDisplayer;
    33.7 +import org.openide.filesystems.FileUtil;
    33.8 +import org.openide.util.ContextAwareAction;
    33.9  import org.openide.util.HelpCtx;
   33.10  import org.openide.util.ImageUtilities;
   33.11 +import org.openide.util.Lookup;
   33.12  import org.openide.util.actions.SystemAction;
   33.13  import org.openide.util.lookup.ProxyLookup;
   33.14  import org.openide.windows.TopComponent;
   33.15  
   33.16 -/**
   33.17 - *
   33.18 - * @author Tomas Pavek
   33.19 - */
   33.20 +@MultiViewElement.Registration(
   33.21 +    displayName="#CTL_DesignTabCaption",
   33.22 +    iconBase=FormEditorSupport.iconURL,
   33.23 +    persistenceType=TopComponent.PERSISTENCE_NEVER,
   33.24 +    preferredID=FormEditorSupport.MV_FORM_ID,
   33.25 +    mimeType="text/x-form",
   33.26 +    position=2000
   33.27 +)
   33.28  public class FormDesignerTC extends TopComponent implements MultiViewElement {
   33.29  
   33.30      private FormEditorSupport formEditorSupport;
   33.31 @@ -92,6 +99,10 @@
   33.32      private static String iconURL =
   33.33          "org/netbeans/modules/form/resources/formDesigner.gif"; // NOI18N
   33.34  
   33.35 +    public FormDesignerTC(Lookup lkp) {
   33.36 +        this(lkp.lookup(FormEditorSupport.class));
   33.37 +    }
   33.38 +    
   33.39      FormDesignerTC(FormEditorSupport formEditorSupport) {
   33.40          this.formEditorSupport = formEditorSupport;
   33.41          lookup = new FormDesignerLookup();
   33.42 @@ -345,16 +356,7 @@
   33.43  
   33.44      @Override
   33.45      public CloseOperationState canCloseElement() {
   33.46 -        // if this is not the last cloned designer, closing is OK
   33.47 -        if (!FormEditorSupport.isLastView(multiViewObserver.getTopComponent())) {
   33.48 -            return CloseOperationState.STATE_OK;
   33.49 -        }
   33.50 -
   33.51 -        // return a placeholder state - to be sure our CloseHandler is called
   33.52 -        return MultiViewFactory.createUnsafeCloseState(
   33.53 -            "ID_FORM_CLOSING", // dummy ID // NOI18N
   33.54 -            MultiViewFactory.NOOP_CLOSE_ACTION,
   33.55 -            MultiViewFactory.NOOP_CLOSE_ACTION);
   33.56 +        return formEditorSupport.canCloseElement(multiViewObserver.getTopComponent());
   33.57      }
   33.58  
   33.59      @Override
    34.1 --- a/form/src/org/netbeans/modules/form/FormEditorSupport.java	Wed May 25 16:24:45 2011 +0200
    34.2 +++ b/form/src/org/netbeans/modules/form/FormEditorSupport.java	Wed May 25 16:50:33 2011 +0200
    34.3 @@ -46,6 +46,7 @@
    34.4  
    34.5  import java.awt.Cursor;
    34.6  import java.awt.EventQueue;
    34.7 +import java.awt.event.ActionEvent;
    34.8  import java.beans.BeanInfo;
    34.9  import java.beans.PropertyChangeEvent;
   34.10  import java.beans.PropertyChangeListener;
   34.11 @@ -70,6 +71,8 @@
   34.12  import java.util.Set;
   34.13  import java.util.logging.Level;
   34.14  import java.util.logging.Logger;
   34.15 +import javax.swing.AbstractAction;
   34.16 +import javax.swing.Action;
   34.17  import javax.swing.JButton;
   34.18  import javax.swing.JComponent;
   34.19  import javax.swing.JEditorPane;
   34.20 @@ -111,6 +114,7 @@
   34.21  import org.openide.filesystems.FileStatusEvent;
   34.22  import org.openide.filesystems.FileStatusListener;
   34.23  import org.openide.filesystems.FileSystem;
   34.24 +import org.openide.filesystems.FileUtil;
   34.25  import org.openide.loaders.DataObject;
   34.26  import org.openide.loaders.MultiDataObject;
   34.27  import org.openide.nodes.CookieSet;
   34.28 @@ -122,8 +126,12 @@
   34.29  import org.openide.text.DataEditorSupport;
   34.30  import org.openide.text.NbDocument;
   34.31  import org.openide.text.PositionRef;
   34.32 +import org.openide.util.ContextAwareAction;
   34.33 +import org.openide.util.Exceptions;
   34.34  import org.openide.util.ImageUtilities;
   34.35 +import org.openide.util.Lookup;
   34.36  import org.openide.util.Mutex;
   34.37 +import org.openide.util.NbBundle.Messages;
   34.38  import org.openide.util.UserQuestionException;
   34.39  import org.openide.windows.CloneableOpenSupport;
   34.40  import org.openide.windows.CloneableTopComponent;
   34.41 @@ -141,7 +149,7 @@
   34.42  public class FormEditorSupport extends DataEditorSupport implements EditorCookie.Observable, CloseCookie, PrintCookie {
   34.43      
   34.44      /** ID of the form designer (in the multiview) */
   34.45 -    private static final String MV_FORM_ID = "form"; //NOI18N
   34.46 +    static final String MV_FORM_ID = "form"; //NOI18N
   34.47      /** ID of the java editor (in the multiview) */
   34.48      private static final String MV_JAVA_ID = "java"; // NOI18N
   34.49      
   34.50 @@ -153,7 +161,7 @@
   34.51      private static final String SECTION_VARIABLES = "variables"; // NOI18N
   34.52      
   34.53      /** Icon for the form editor multiview window */
   34.54 -    private static final String iconURL =
   34.55 +    static final String iconURL =
   34.56              "org/netbeans/modules/form/resources/form.gif"; // NOI18N
   34.57      
   34.58      /** The DataObject of the form */
   34.59 @@ -833,14 +841,8 @@
   34.60          if (!formDataObject.isValid()) {
   34.61              return super.createPane(); // Issue 110249
   34.62          } 
   34.63 -        MultiViewDescription[] descs = new MultiViewDescription[] {
   34.64 -            new JavaDesc(formDataObject), new FormDesc(formDataObject) };
   34.65          
   34.66 -        CloneableTopComponent mvtc =
   34.67 -                MultiViewFactory.createCloneableMultiView(
   34.68 -                descs,
   34.69 -                descs[elementToOpen],
   34.70 -                new CloseHandler(formDataObject));
   34.71 +        CloneableTopComponent mvtc = MultiViews.createCloneableMultiView("text/x-form", getDataObject());
   34.72          
   34.73          // #45665 - dock into editor mode if possible..
   34.74          Mode editorMode = WindowManager.getDefault().findMode(CloneableEditorSupport.EDITOR_MODE);
   34.75 @@ -976,6 +978,40 @@
   34.76              });
   34.77          }
   34.78      }
   34.79 +
   34.80 +    @Messages({
   34.81 +        "MSG_MODIFIED=File {0} is modified. Save?"
   34.82 +    })
   34.83 +    final CloseOperationState canCloseElement(TopComponent tc) {
   34.84 +        // if this is not the last cloned java editor component, closing is OK
   34.85 +        if (!FormEditorSupport.isLastView(tc)) {
   34.86 +            return CloseOperationState.STATE_OK;
   34.87 +        }
   34.88 +
   34.89 +        if (!isModified()) {
   34.90 +            return CloseOperationState.STATE_OK;
   34.91 +        }
   34.92 +        
   34.93 +        AbstractAction save = new AbstractAction() {
   34.94 +            @Override
   34.95 +            public void actionPerformed(ActionEvent e) {
   34.96 +                try {
   34.97 +                    saveDocument();
   34.98 +                } catch (IOException ex) {
   34.99 +                    Exceptions.printStackTrace(ex);
  34.100 +                }
  34.101 +            }
  34.102 +        };
  34.103 +        save.putValue(Action.LONG_DESCRIPTION, Bundle.MSG_MODIFIED(
  34.104 +            getDataObject().getPrimaryFile().getNameExt()
  34.105 +        ));
  34.106 +
  34.107 +        // return a placeholder state - to be sure our CloseHandler is called
  34.108 +        return MultiViewFactory.createUnsafeCloseState(
  34.109 +                "ID_FORM_CLOSING", // NOI18N
  34.110 +                save,
  34.111 +                MultiViewFactory.NOOP_CLOSE_ACTION);
  34.112 +    }
  34.113      
  34.114      static boolean isLastView(TopComponent tc) {
  34.115          if (!(tc instanceof CloneableTopComponent))
  34.116 @@ -1157,165 +1193,40 @@
  34.117          }
  34.118      }
  34.119      
  34.120 -    // --------
  34.121 -    
  34.122 -    /** A descriptor for the FormDesigner element of multiview. Allows lazy
  34.123 -     * creation of the FormDesigner (and thus form loading). */
  34.124 -    private static class FormDesc implements MultiViewDescription, Serializable {
  34.125 -        
  34.126 -        private static final long serialVersionUID =-3126744316624172415L;
  34.127 -        
  34.128 -        private DataObject dataObject;
  34.129 -        
  34.130 -        private FormDesc() {
  34.131 -        }
  34.132 -        
  34.133 -        public FormDesc(DataObject formDO) {
  34.134 -            dataObject = formDO;
  34.135 -        }
  34.136 -        
  34.137 -        private FormEditorSupport getFormEditor() {
  34.138 -            return dataObject != null && dataObject instanceof FormDataObject ?
  34.139 -                ((FormDataObject)dataObject).getFormEditorSupport() : null;
  34.140 -        }
  34.141 -        
  34.142 -        @Override
  34.143 -        public MultiViewElement createElement() {
  34.144 -            return new FormDesignerTC(getFormEditor());
  34.145 -        }
  34.146 -        
  34.147 -        @Override
  34.148 -        public String getDisplayName() {
  34.149 -            return FormUtils.getBundleString("CTL_DesignTabCaption"); // NOI18N
  34.150 -        }
  34.151 -        
  34.152 -        @Override
  34.153 -        public org.openide.util.HelpCtx getHelpCtx() {
  34.154 -            return org.openide.util.HelpCtx.DEFAULT_HELP;
  34.155 -        }
  34.156 -        
  34.157 -        @Override
  34.158 -        public java.awt.Image getIcon() {
  34.159 -            if (dataObject.isValid()) {
  34.160 -                return dataObject.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16);
  34.161 -            } else {
  34.162 -                return ImageUtilities.loadImage(iconURL);
  34.163 -            }
  34.164 -        }
  34.165 -        
  34.166 -        @Override
  34.167 -        public int getPersistenceType() {
  34.168 -            return TopComponent.PERSISTENCE_NEVER;
  34.169 -        }
  34.170 -        
  34.171 -        @Override
  34.172 -        public String preferredID() {
  34.173 -            return MV_FORM_ID;
  34.174 -        }
  34.175 -        
  34.176 -        public void writeExternal(ObjectOutput out) throws IOException {
  34.177 -            out.writeObject(dataObject);
  34.178 -        }
  34.179 -        
  34.180 -        public void readExternal(ObjectInput in)
  34.181 -                throws IOException, ClassNotFoundException
  34.182 -        {
  34.183 -            Object firstObject = in.readObject();
  34.184 -            if (firstObject instanceof FormDataObject)
  34.185 -                dataObject = (DataObject) firstObject;
  34.186 -        }
  34.187 -    }
  34.188 -    
  34.189 -    // -------
  34.190 -    
  34.191 -    /** A descriptor for the java editor as an element in multiview. */
  34.192 -    private static class JavaDesc implements MultiViewDescription, SourceViewMarker, Serializable {
  34.193 -        
  34.194 -        private static final long serialVersionUID =-3126744316624172415L;
  34.195 -        
  34.196 -        private DataObject dataObject;
  34.197 -        
  34.198 -        private JavaDesc() {
  34.199 -        }
  34.200 -        
  34.201 -        public JavaDesc(DataObject formDO) {
  34.202 -            dataObject = formDO;
  34.203 -        }
  34.204 -        
  34.205 -        private FormEditorSupport getJavaEditor() {
  34.206 -            return dataObject != null && dataObject instanceof FormDataObject ?
  34.207 -                ((FormDataObject)dataObject).getFormEditorSupport() : null;
  34.208 -        }
  34.209 -        
  34.210 -        @Override
  34.211 -        public MultiViewElement createElement() {
  34.212 -            FormEditorSupport javaEditor = getJavaEditor();
  34.213 -            if (javaEditor != null) {
  34.214 -                javaEditor.prepareDocument();
  34.215 -                JavaEditorTopComponent editor = new JavaEditorTopComponent(dataObject.getCookie(FormEditorSupport.class));
  34.216 -                Node[] nodes = editor.getActivatedNodes();
  34.217 -                if ((nodes == null) || (nodes.length == 0)) {
  34.218 -                    editor.setActivatedNodes(new Node[] {dataObject.getNodeDelegate()});
  34.219 -                }
  34.220 -                return (MultiViewElement) editor;
  34.221 -            }
  34.222 -            return MultiViewFactory.BLANK_ELEMENT;
  34.223 -        }
  34.224 -        
  34.225 -        @Override
  34.226 -        public String getDisplayName() {
  34.227 -            return FormUtils.getBundleString("CTL_SourceTabCaption"); // NOI18N
  34.228 -        }
  34.229 -        
  34.230 -        @Override
  34.231 -        public org.openide.util.HelpCtx getHelpCtx() {
  34.232 -            return org.openide.util.HelpCtx.DEFAULT_HELP;
  34.233 -        }
  34.234 -        
  34.235 -        @Override
  34.236 -        public java.awt.Image getIcon() {
  34.237 -            if (dataObject.isValid()) {
  34.238 -                return dataObject.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16);
  34.239 -            } else {
  34.240 -                return ImageUtilities.loadImage(iconURL);
  34.241 -            }
  34.242 -        }
  34.243 -        
  34.244 -        @Override
  34.245 -        public int getPersistenceType() {
  34.246 -            return TopComponent.PERSISTENCE_ONLY_OPENED;
  34.247 -        }
  34.248 -        
  34.249 -        @Override
  34.250 -        public String preferredID() {
  34.251 -            return MV_JAVA_ID;
  34.252 -        }
  34.253 -        
  34.254 -        public void writeExternal(ObjectOutput out) throws IOException {
  34.255 -            out.writeObject(dataObject);
  34.256 -        }
  34.257 -        
  34.258 -        public void readExternal(ObjectInput in)
  34.259 -                throws IOException, ClassNotFoundException
  34.260 -        {
  34.261 -            Object firstObject = in.readObject();
  34.262 -            if (firstObject instanceof FormDataObject)
  34.263 -                dataObject = (DataObject) firstObject;
  34.264 -        }
  34.265 -    }
  34.266 -    
  34.267 -    // --------
  34.268 -    
  34.269 -    private static class JavaEditorTopComponent
  34.270 +    @MultiViewElement.Registration(
  34.271 +        displayName="#CTL_SourceTabCaption",
  34.272 +        iconBase=iconURL,
  34.273 +        persistenceType=TopComponent.PERSISTENCE_ONLY_OPENED,
  34.274 +        preferredID=MV_JAVA_ID,
  34.275 +        mimeType="text/x-form",
  34.276 +        position=1000
  34.277 +    )
  34.278 +    public static class JavaEditorTopComponent
  34.279                       extends CloneableEditor
  34.280                       implements MultiViewElement
  34.281      {
  34.282          private static final long serialVersionUID =-3126744316624172415L;
  34.283          
  34.284          private transient JComponent toolbar;
  34.285 -        
  34.286 +        private FormEditorSupport javaEditor;
  34.287          private transient MultiViewElementCallback multiViewObserver;
  34.288          
  34.289 +        
  34.290 +        public JavaEditorTopComponent(Lookup context) {
  34.291 +            super(context.lookup(DataEditorSupport.class));
  34.292 +            javaEditor = context.lookup(FormEditorSupport.class);
  34.293 +            DataObject dataObject = context.lookup(DataObject.class);
  34.294 +            if (javaEditor != null) {
  34.295 +                javaEditor.prepareDocument();
  34.296 +            }
  34.297 +            if (dataObject != null) {
  34.298 +                Node[] nodes = getActivatedNodes();
  34.299 +                if ((nodes == null) || (nodes.length == 0)) {
  34.300 +                    setActivatedNodes(new Node[]{dataObject.getNodeDelegate()});
  34.301 +                }
  34.302 +            }
  34.303 +        }
  34.304 +       
  34.305          JavaEditorTopComponent() {
  34.306              super();
  34.307          }
  34.308 @@ -1448,15 +1359,10 @@
  34.309          
  34.310          @Override
  34.311          public CloseOperationState canCloseElement() {
  34.312 -            // if this is not the last cloned java editor component, closing is OK
  34.313 -            if (!FormEditorSupport.isLastView(multiViewObserver.getTopComponent()))
  34.314 +            if (javaEditor == null) {
  34.315                  return CloseOperationState.STATE_OK;
  34.316 -            
  34.317 -            // return a placeholder state - to be sure our CloseHandler is called
  34.318 -            return MultiViewFactory.createUnsafeCloseState(
  34.319 -                    "ID_JAVA_CLOSING", // dummy ID // NOI18N
  34.320 -                    MultiViewFactory.NOOP_CLOSE_ACTION,
  34.321 -                    MultiViewFactory.NOOP_CLOSE_ACTION);
  34.322 +            }
  34.323 +            return javaEditor.canCloseElement(multiViewObserver.getTopComponent());
  34.324          }
  34.325          
  34.326          protected boolean isActiveTC() {
  34.327 @@ -1477,41 +1383,6 @@
  34.328          }
  34.329      }
  34.330      
  34.331 -    // ------
  34.332 -    
  34.333 -    /** Implementation of CloseOperationHandler for multiview. Ensures both form
  34.334 -     * and java editor are correctly closed, data saved, etc. Holds a reference
  34.335 -     * to form DataObject only - to be serializable with the multiview
  34.336 -     * TopComponent without problems.
  34.337 -     */
  34.338 -    private static class CloseHandler implements CloseOperationHandler,
  34.339 -                                                 Serializable
  34.340 -    {
  34.341 -        private static final long serialVersionUID =-3126744315424172415L;
  34.342 -        
  34.343 -        private DataObject dataObject;
  34.344 -        
  34.345 -        private CloseHandler() {
  34.346 -        }
  34.347 -        
  34.348 -        public CloseHandler(DataObject formDO) {
  34.349 -            dataObject = formDO;
  34.350 -        }
  34.351 -        
  34.352 -        private FormEditorSupport getFormEditor() {
  34.353 -            return dataObject != null && dataObject instanceof FormDataObject ?
  34.354 -                ((FormDataObject)dataObject).getFormEditorSupport() : null;
  34.355 -        }
  34.356 -        
  34.357 -        @Override
  34.358 -        public boolean resolveCloseOperation(CloseOperationState[] elements) {
  34.359 -            FormEditorSupport formEditor = getFormEditor();
  34.360 -            return formEditor != null ? formEditor.canClose() : true;
  34.361 -        }
  34.362 -    }
  34.363 -    
  34.364 -    // ------
  34.365 -    
  34.366      private static final class Environment extends DataEditorSupport.Env {
  34.367          
  34.368          private static final long serialVersionUID = -1;
    35.1 --- a/nbbuild/build.properties	Wed May 25 16:24:45 2011 +0200
    35.2 +++ b/nbbuild/build.properties	Wed May 25 16:50:33 2011 +0200
    35.3 @@ -102,6 +102,7 @@
    35.4      autoupdate.services,\
    35.5      autoupdate.ui,\
    35.6      core.ide,\
    35.7 +    core.multiview,\
    35.8      openide.util,\
    35.9      openide.util.lookup,\
   35.10      openide.actions,\
   35.11 @@ -168,7 +169,6 @@
   35.12      jellytools.ide,\
   35.13      o.openidex.util,\
   35.14      core.netigso,\
   35.15 -    core.multiview,\
   35.16      o.n.swing.outline,\
   35.17      o.n.swing.tabcontrol,\
   35.18      editor.indent,\
    36.1 --- a/openide.loaders/apichanges.xml	Wed May 25 16:24:45 2011 +0200
    36.2 +++ b/openide.loaders/apichanges.xml	Wed May 25 16:50:33 2011 +0200
    36.3 @@ -109,6 +109,22 @@
    36.4  <!-- ACTUAL CHANGES BEGIN HERE: -->
    36.5  
    36.6    <changes>
    36.7 +      <change id="DataEditorSupport.create-callable">
    36.8 +          <api name="editor"/>
    36.9 +          <summary>DataEditorSupport.create(...., Callable&lt;Pane&gt;)</summary>
   36.10 +          <version major="7" minor="21"/>
   36.11 +          <date day="7" month="4" year="2011"/>
   36.12 +          <author login="jtulach"/>
   36.13 +          <compatibility semantic="compatible" addition="yes"/>
   36.14 +          <description>
   36.15 +              <p>
   36.16 +                  New <code>create</code> factory method to allow creation
   36.17 +                  of different <code>CloneableEditorSupport.Pane</code> implementations
   36.18 +                  than the default <code>CloneableEditor</code>.
   36.19 +              </p>
   36.20 +          </description>
   36.21 +          <class package="org.openide.text" name="DataEditorSupport"/>
   36.22 +      </change>
   36.23        <change id="removing.org.openide.loaders.DataFolder.lazy">
   36.24            <api name="loaders"/>
   36.25            <summary>Removed <code>org.openide.loaders.DataFolder.lazy</code></summary>
    37.1 --- a/openide.loaders/manifest.mf	Wed May 25 16:24:45 2011 +0200
    37.2 +++ b/openide.loaders/manifest.mf	Wed May 25 16:50:33 2011 +0200
    37.3 @@ -1,6 +1,6 @@
    37.4  Manifest-Version: 1.0
    37.5  OpenIDE-Module: org.openide.loaders
    37.6 -OpenIDE-Module-Specification-Version: 7.22
    37.7 +OpenIDE-Module-Specification-Version: 7.23
    37.8  OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
    37.9  OpenIDE-Module-Provides: org.netbeans.modules.templates.v1_0
   37.10  OpenIDE-Module-Layer: org/netbeans/modules/openide/loaders/layer.xml
    38.1 --- a/openide.loaders/src/org/openide/text/DataEditorSupport.java	Wed May 25 16:24:45 2011 +0200
    38.2 +++ b/openide.loaders/src/org/openide/text/DataEditorSupport.java	Wed May 25 16:50:33 2011 +0200
    38.3 @@ -47,9 +47,7 @@
    38.4  
    38.5  import java.beans.PropertyChangeEvent;
    38.6  import java.beans.PropertyChangeListener;
    38.7 -import java.io.BufferedInputStream;
    38.8  import java.io.BufferedOutputStream;
    38.9 -import java.io.BufferedReader;
   38.10  import java.io.CharConversionException;
   38.11  import java.io.FilterOutputStream;
   38.12  import java.io.IOException;
   38.13 @@ -63,7 +61,6 @@
   38.14  import java.io.Reader;
   38.15  import java.io.Writer;
   38.16  import java.lang.ref.Reference;
   38.17 -import java.nio.ByteBuffer;
   38.18  import java.nio.charset.CharacterCodingException;
   38.19  import java.nio.charset.Charset;
   38.20  import java.nio.charset.CharsetDecoder;
   38.21 @@ -74,6 +71,7 @@
   38.22  import java.util.HashSet;
   38.23  import java.util.Map;
   38.24  import java.util.Set;
   38.25 +import java.util.concurrent.Callable;
   38.26  import java.util.logging.Level;
   38.27  import java.util.logging.Logger;
   38.28  import javax.swing.text.BadLocationException;
   38.29 @@ -105,7 +103,7 @@
   38.30  import org.openide.nodes.Node;
   38.31  import org.openide.nodes.NodeAdapter;
   38.32  import org.openide.nodes.NodeListener;
   38.33 -import org.openide.util.Exceptions;
   38.34 +import org.openide.util.Lookup;
   38.35  import org.openide.util.Mutex;
   38.36  import org.openide.util.NbBundle;
   38.37  import org.openide.util.Parameters;
   38.38 @@ -136,7 +134,11 @@
   38.39      * @param env environment to pass to 
   38.40      */
   38.41      public DataEditorSupport (DataObject obj, CloneableEditorSupport.Env env) {
   38.42 -        super (env, new DOEnvLookup (obj));
   38.43 +        this(obj, new DOEnvLookup (obj), env);
   38.44 +    }
   38.45 +    
   38.46 +    DataEditorSupport(DataObject obj, Lookup lkp, CloneableEditorSupport.Env env) {
   38.47 +        super (env, lkp);
   38.48          this.obj = obj;
   38.49      }
   38.50      
   38.51 @@ -168,6 +170,43 @@
   38.52      public static CloneableEditorSupport create (DataObject obj, MultiDataObject.Entry entry, org.openide.nodes.CookieSet set) {
   38.53          return new SimpleES (obj, entry, set);
   38.54      }
   38.55 +
   38.56 +    /** Factory method to create a bit more complicated CloneableEditorSupport for a given
   38.57 +     * entry of a given DataObject. The common use inside DataObject looks like
   38.58 +     * this:
   38.59 +     * <pre>
   38.60 +     *  getCookieSet().add((Node.Cookie) DataEditorSupport.create(
   38.61 +     *    this, getPrimaryEntry(), getCookieSet(),
   38.62 +     *    new Callable<Pane>() { 
   38.63 +     *      public Pane call() {
   38.64 +     *        return new {@link CloneableEditor YourSubclassOfCloneableEditor}(support);
   38.65 +     *      }
   38.66 +     *    }
   38.67 +     *  ));
   38.68 +     * </pre>
   38.69 +     * The method can be used to instantiate <b>multi view</b> editor by returning
   38.70 +     * <a href="@org-netbeans-core-multiview@/org/netbeans/core/api/multiview/MultiViews.html">
   38.71 +     * MultiViews.createCloneableMultiView("text/yourmime", this)</a>.
   38.72 +     *
   38.73 +     * @param obj the data object
   38.74 +     * @param entry the entry to read and write from
   38.75 +     * @param set cookie set to add remove additional cookies (currently only {@link org.openide.cookies.SaveCookie})
   38.76 +     * @param paneFactory callback to create editor(s) for this support
   38.77 +     * @return a subclass of DataEditorSupport that implements at least
   38.78 +     *   {@link org.openide.cookies.OpenCookie}, 
   38.79 +     *   {@link org.openide.cookies.EditCookie}, 
   38.80 +     *   {@link org.openide.cookies.EditorCookie.Observable}, 
   38.81 +     *   {@link org.openide.cookies.PrintCookie}, 
   38.82 +     *   {@link org.openide.cookies.CloseCookie}
   38.83 +     * @since 7.21
   38.84 +     */
   38.85 +    public static CloneableEditorSupport create(
   38.86 +        DataObject obj, MultiDataObject.Entry entry, 
   38.87 +        org.openide.nodes.CookieSet set,
   38.88 +        Callable<CloneableEditorSupport.Pane> paneFactory
   38.89 +    ) {
   38.90 +        return new SimpleES (obj, entry, set, paneFactory);
   38.91 +    }
   38.92      
   38.93      /** Getter of the data object that this support is associated with.
   38.94      * @return data object passed in constructor
    39.1 --- a/openide.loaders/src/org/openide/text/SimpleES.java	Wed May 25 16:24:45 2011 +0200
    39.2 +++ b/openide.loaders/src/org/openide/text/SimpleES.java	Wed May 25 16:50:33 2011 +0200
    39.3 @@ -45,6 +45,7 @@
    39.4  package org.openide.text;
    39.5  
    39.6  import java.io.IOException;
    39.7 +import java.util.concurrent.Callable;
    39.8  import org.openide.cookies.CloseCookie;
    39.9  import org.openide.cookies.EditCookie;
   39.10  import org.openide.cookies.EditorCookie;
   39.11 @@ -55,6 +56,7 @@
   39.12  import org.openide.filesystems.FileLock;
   39.13  import org.openide.loaders.DataObject;
   39.14  import org.openide.loaders.MultiDataObject;
   39.15 +import org.openide.loaders.MultiDataObject.Entry;
   39.16  import org.openide.nodes.CookieSet;
   39.17  import org.openide.nodes.Node.Cookie;
   39.18  import org.openide.windows.CloneableOpenSupport;
   39.19 @@ -70,21 +72,52 @@
   39.20       * data object's cookie set depending on if modification flag was set/unset. */
   39.21      private final SaveCookie saveCookie = new SaveCookie() {
   39.22          /** Implements <code>SaveCookie</code> interface. */
   39.23 +        @Override
   39.24          public void save() throws IOException {
   39.25              SimpleES.this.saveDocument();
   39.26          }
   39.27 +
   39.28 +        @Override
   39.29 +        public String toString() {
   39.30 +            return getDataObject().getPrimaryFile().getNameExt();
   39.31 +        }
   39.32      };
   39.33      
   39.34 -    private CookieSet set;
   39.35 +    private final CookieSet set;
   39.36 +    private final Callable<Pane> factory;
   39.37      
   39.38      /** Constructor. 
   39.39       * @param obj data object to work on
   39.40       * @param set set to add/remove save cookie from
   39.41       */
   39.42      SimpleES (DataObject obj, MultiDataObject.Entry entry, CookieSet set) {
   39.43 -        super(obj, new Environment(obj, entry));
   39.44 +        this(obj, entry, set, null);
   39.45 +    }
   39.46 +
   39.47 +    SimpleES(DataObject obj, Entry entry, CookieSet set, Callable<Pane> paneFactory) {
   39.48 +        super(obj, obj.getLookup(), new Environment(obj, entry));
   39.49          this.set = set;
   39.50 +        this.factory = paneFactory;
   39.51      }
   39.52 +
   39.53 +    @Override
   39.54 +    protected boolean asynchronousOpen() {
   39.55 +        return true;
   39.56 +    }
   39.57 +    
   39.58 +    @Override
   39.59 +    protected Pane createPane() {
   39.60 +        if (factory != null) {
   39.61 +            try {
   39.62 +                return factory.call();
   39.63 +            } catch (Exception ex) {
   39.64 +                throw new IllegalStateException("Cannot create factory for " + getDataObject(), ex);
   39.65 +            }
   39.66 +        }
   39.67 +        return super.createPane();
   39.68 +    }
   39.69 +    
   39.70 +    
   39.71      
   39.72      /** 
   39.73       * Overrides superclass method. Adds adding of save cookie if the document has been marked modified.
    40.1 --- a/openide.loaders/test/unit/src/org/openide/text/SimpleDESTest.java	Wed May 25 16:24:45 2011 +0200
    40.2 +++ b/openide.loaders/test/unit/src/org/openide/text/SimpleDESTest.java	Wed May 25 16:50:33 2011 +0200
    40.3 @@ -44,6 +44,7 @@
    40.4  
    40.5  package org.openide.text;
    40.6  
    40.7 +import java.awt.EventQueue;
    40.8  import java.io.PrintStream;
    40.9  import java.util.logging.Level;
   40.10  import org.netbeans.junit.*;
   40.11 @@ -138,6 +139,7 @@
   40.12          
   40.13          OpenCookie open = obj.getCookie(OpenCookie.class);
   40.14          open.open ();
   40.15 +        waitAWT();
   40.16          
   40.17          javax.swing.text.Document d = c.getDocument();
   40.18          assertNotNull (d);
   40.19 @@ -150,6 +152,14 @@
   40.20          );
   40.21      }
   40.22      
   40.23 +    private void waitAWT() throws Exception {
   40.24 +        EventQueue.invokeAndWait(new Runnable() {
   40.25 +            @Override
   40.26 +            public void run() {
   40.27 +            }
   40.28 +        });
   40.29 +    }
   40.30 +    
   40.31      public void testItIsPossibleToMaskEditCookie () throws Exception {
   40.32          doCookieCheck (false);
   40.33      }
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/openide.loaders/test/unit/src/org/openide/text/SimpleFactoryTest.java	Wed May 25 16:50:33 2011 +0200
    41.3 @@ -0,0 +1,236 @@
    41.4 +/*
    41.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    41.6 + *
    41.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    41.8 + *
    41.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   41.10 + * Other names may be trademarks of their respective owners.
   41.11 + *
   41.12 + * The contents of this file are subject to the terms of either the GNU
   41.13 + * General Public License Version 2 only ("GPL") or the Common
   41.14 + * Development and Distribution License("CDDL") (collectively, the
   41.15 + * "License"). You may not use this file except in compliance with the
   41.16 + * License. You can obtain a copy of the License at
   41.17 + * http://www.netbeans.org/cddl-gplv2.html
   41.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   41.19 + * specific language governing permissions and limitations under the
   41.20 + * License.  When distributing the software, include this License Header
   41.21 + * Notice in each file and include the License file at
   41.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   41.23 + * particular file as subject to the "Classpath" exception as provided
   41.24 + * by Oracle in the GPL Version 2 section of the License file that
   41.25 + * accompanied this code. If applicable, add the following below the
   41.26 + * License Header, with the fields enclosed by brackets [] replaced by
   41.27 + * your own identifying information:
   41.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   41.29 + *
   41.30 + * Contributor(s):
   41.31 + *
   41.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   41.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   41.34 + * Microsystems, Inc. All Rights Reserved.
   41.35 + *
   41.36 + * If you wish your version of this file to be governed by only the CDDL
   41.37 + * or only the GPL Version 2, indicate your decision by adding
   41.38 + * "[Contributor] elects to include this software in this distribution
   41.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   41.40 + * single choice of license, a recipient has the option to distribute
   41.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   41.42 + * to extend the choice of license to its licensees as provided above.
   41.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   41.44 + * Version 2 license, then the option applies only if the new code is
   41.45 + * made subject to such option by the copyright holder.
   41.46 + */
   41.47 +
   41.48 +package org.openide.text;
   41.49 +
   41.50 +import java.awt.Container;
   41.51 +import java.awt.EventQueue;
   41.52 +import java.io.IOException;
   41.53 +import java.util.Enumeration;
   41.54 +import java.util.concurrent.Callable;
   41.55 +import java.util.logging.Level;
   41.56 +import javax.swing.JEditorPane;
   41.57 +import org.netbeans.api.actions.Openable;
   41.58 +import org.netbeans.api.actions.Savable;
   41.59 +import org.netbeans.junit.*;
   41.60 +import org.openide.cookies.EditorCookie;
   41.61 +import org.openide.filesystems.*;
   41.62 +import org.openide.loaders.DataLoader;
   41.63 +import org.openide.loaders.DataObject;
   41.64 +import org.openide.loaders.DataObjectExistsException;
   41.65 +import org.openide.loaders.MultiDataObject;
   41.66 +import org.openide.nodes.CookieSet;
   41.67 +import org.openide.nodes.Node;
   41.68 +import org.openide.text.CloneableEditorSupport.Pane;
   41.69 +import org.openide.util.Lookup;
   41.70 +
   41.71 +/** Check behavior of 
   41.72 + * {@link DataEditorSupport#create(org.openide.loaders.DataObject, org.openide.loaders.MultiDataObject.Entry, org.openide.nodes.CookieSet, java.util.concurrent.Callable)}
   41.73 + * factory method.
   41.74 + *
   41.75 + * @author  Jaroslav Tulach
   41.76 + */
   41.77 +public final class SimpleFactoryTest extends NbTestCase {
   41.78 +    static {
   41.79 +        System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false");
   41.80 +    }
   41.81 +    private FileSystem lfs;
   41.82 +    private DataObject obj;
   41.83 +    
   41.84 +    public SimpleFactoryTest(String name) {
   41.85 +        super(name);
   41.86 +    }
   41.87 +
   41.88 +    @Override
   41.89 +    protected Level logLevel() {
   41.90 +        return Level.FINE;
   41.91 +    }
   41.92 +
   41.93 +    @Override
   41.94 +    protected boolean runInEQ() {
   41.95 +        return false;
   41.96 +    }
   41.97 +    
   41.98 +    @Override
   41.99 +    protected void setUp() throws java.lang.Exception {
  41.100 +        clearWorkDir ();
  41.101 +        
  41.102 +        System.setProperty("org.openide.util.Lookup", "org.openide.text.SimpleFactoryTest$Lkp");
  41.103 +        super.setUp();
  41.104 +        
  41.105 +        LocalFileSystem l = new LocalFileSystem ();
  41.106 +        l.setRootDirectory (getWorkDir ());
  41.107 +        lfs = l;
  41.108 +        
  41.109 +        FileObject fo = FileUtil.createData (lfs.getRoot (), "AA/" + getName () + ".test");
  41.110 +        assertNotNull("file not found", fo);
  41.111 +        obj = DataObject.find(fo);
  41.112 +        
  41.113 +        assertEquals ("The right class", obj.getClass (), SO.class);
  41.114 +    }
  41.115 +
  41.116 +    public void testOurNodeSubclassCreated() throws Exception {
  41.117 +        final EditorCookie ec = obj.getLookup().lookup(EditorCookie.class);
  41.118 +        assertNotNull("Editor", ec);
  41.119 +        Openable open = obj.getLookup().lookup(Openable.class);
  41.120 +        assertNotNull("Open", open);
  41.121 +        open.open();
  41.122 +        
  41.123 +        class GEP implements Runnable {
  41.124 +            JEditorPane[] arr;
  41.125 +            
  41.126 +            @Override
  41.127 +            public void run() {
  41.128 +                arr = ec.getOpenedPanes();
  41.129 +            }
  41.130 +        }
  41.131 +        GEP gep = new GEP();
  41.132 +        EventQueue.invokeAndWait(gep);
  41.133 +        
  41.134 +        assertEquals("One", 1, gep.arr.length);
  41.135 +        
  41.136 +        MyCE mice = null;
  41.137 +        Container c = gep.arr[0];
  41.138 +        for (;;) {
  41.139 +            if (c instanceof MyCE) {
  41.140 +                // OK
  41.141 +                mice = (MyCE)c;
  41.142 +                break;
  41.143 +            }
  41.144 +            if (c instanceof CloneableEditor) {
  41.145 +                fail("Wrong CloneableEditor: " + c);
  41.146 +            }
  41.147 +            if (c == null) {
  41.148 +                fail("No good parent!");
  41.149 +            }
  41.150 +            c = c.getParent();
  41.151 +        }
  41.152 +        
  41.153 +        assertNotNull("MyCE found", mice);
  41.154 +        assertNull("No integers", mice.getLookup().lookup(Integer.class));
  41.155 +        ((SO)obj).addInteger();
  41.156 +        assertEquals("One integer in object", Integer.valueOf(10), obj.getLookup().lookup(Integer.class));
  41.157 +        assertEquals("One integer", Integer.valueOf(10), mice.getLookup().lookup(Integer.class));
  41.158 +        
  41.159 +        Savable sav = obj.getLookup().lookup(Savable.class);
  41.160 +        assertNull("No savable yet", sav);
  41.161 +        
  41.162 +        ec.getDocument().insertString(0, "Ahoj!", null);
  41.163 +        
  41.164 +        sav = obj.getLookup().lookup(Savable.class);
  41.165 +        assertNotNull("Now modified", sav);
  41.166 +        
  41.167 +        assertEquals(obj.getPrimaryFile().getNameExt(), sav.toString());
  41.168 +    }
  41.169 +    
  41.170 +    //
  41.171 +    // Our fake lookup
  41.172 +    //
  41.173 +    public static final class Lkp extends org.openide.util.lookup.AbstractLookup {
  41.174 +        public Lkp () {
  41.175 +            this (new org.openide.util.lookup.InstanceContent ());
  41.176 +        }
  41.177 +        
  41.178 +        private Lkp (org.openide.util.lookup.InstanceContent ic) {
  41.179 +            super (ic);
  41.180 +            ic.add (new DLP ());
  41.181 +        }
  41.182 +    }
  41.183 +    
  41.184 +    private static final class SL extends org.openide.loaders.UniFileLoader {
  41.185 +        public SL () {
  41.186 +            super (SO.class.getName ());
  41.187 +            getExtensions().addExtension("test");
  41.188 +        }
  41.189 +        @Override
  41.190 +        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
  41.191 +            return new SO (primaryFile);
  41.192 +        }
  41.193 +    } // end of SL
  41.194 +    
  41.195 +    private static final class SO extends org.openide.loaders.MultiDataObject 
  41.196 +    implements Callable<CloneableEditorSupport.Pane> {
  41.197 +        private CloneableEditorSupport support = DataEditorSupport.create(this, getPrimaryEntry(), getCookieSet (), this);
  41.198 +        
  41.199 +        
  41.200 +        public SO (FileObject fo) throws org.openide.loaders.DataObjectExistsException {
  41.201 +            super (fo, SL.getLoader(SL.class));
  41.202 +            getCookieSet ().add((Node.Cookie)support);
  41.203 +        }
  41.204 +        
  41.205 +        @Override
  41.206 +        public Lookup getLookup() {
  41.207 +            return getCookieSet().getLookup();
  41.208 +        }
  41.209 +        
  41.210 +        @Override
  41.211 +        public Pane call() throws Exception {
  41.212 +            return new MyCE(support);
  41.213 +        }
  41.214 +        
  41.215 +        public void addInteger() {
  41.216 +            getCookieSet().assign(Integer.class, 10);            
  41.217 +        }
  41.218 +    } // end of SO
  41.219 +    
  41.220 +    private static final class MyCE extends CloneableEditor {
  41.221 +        private MyCE(CloneableEditorSupport support) {
  41.222 +            super(support);
  41.223 +            this.associateLookup(support.getLookup());
  41.224 +        }
  41.225 +    }
  41.226 +
  41.227 +    private static final class DLP extends org.openide.loaders.DataLoaderPool {
  41.228 +
  41.229 +        @Override
  41.230 +        protected Enumeration<? extends DataLoader> loaders() {
  41.231 +            return java.util.Collections.enumeration(
  41.232 +                java.util.Collections.singleton(
  41.233 +                    SL.getLoader (SL.class)
  41.234 +                )
  41.235 +            );
  41.236 +        }
  41.237 +        
  41.238 +    } // end of DataLoaderPool
  41.239 +}
    42.1 --- a/openide.text/apichanges.xml	Wed May 25 16:24:45 2011 +0200
    42.2 +++ b/openide.text/apichanges.xml	Wed May 25 16:50:33 2011 +0200
    42.3 @@ -49,6 +49,63 @@
    42.4  <apidef name="text">Text API</apidef>
    42.5  </apidefs>
    42.6  <changes>
    42.7 +    <change id="CE.closeLast.boolean">
    42.8 +        <api name="text"/>
    42.9 +        <summary>CloneableEditor.closeLast</summary>
   42.10 +        <version major="6" minor="37"/>
   42.11 +        <date day="7" month="4" year="2011"/>
   42.12 +        <author login="jtulach"/>
   42.13 +        <compatibility addition="yes" binary="compatible" deletion="no"
   42.14 +          deprecation="yes" modification="no" semantic="compatible" 
   42.15 +        />
   42.16 +        <description>
   42.17 +            <p>
   42.18 +                <code>CloneableEditor</code> has a new utility method
   42.19 +                <code>closeLast</code>.
   42.20 +            </p>
   42.21 +        </description>
   42.22 +        <class package="org.openide.text" name="CloneableEditor"/>
   42.23 +        <issue number="196810"/>
   42.24 +    </change>
   42.25 +    <change id="CE.associateLookup">
   42.26 +        <api name="text"/>
   42.27 +        <summary>CloneableEditor(associateLookup)</summary>
   42.28 +        <version major="6" minor="37"/>
   42.29 +        <date day="7" month="4" year="2011"/>
   42.30 +        <author login="jtulach"/>
   42.31 +        <compatibility addition="yes" binary="compatible" deletion="no"
   42.32 +          deprecation="yes" modification="no" semantic="compatible" 
   42.33 +        />
   42.34 +        <description>
   42.35 +            <p>
   42.36 +                <code>CloneableEditor</code> offers new constructor
   42.37 +                that will reuse the lookup provided by its 
   42.38 +                <a href="@TOP@/org/openide/text/CloneableEditorSupport.html">CloneableEditorSupport</a>.
   42.39 +            </p>
   42.40 +        </description>
   42.41 +        <class package="org.openide.text" name="CloneableEditor"/>
   42.42 +        <issue number="196810"/>
   42.43 +    </change>
   42.44 +    <change id="initializeBySupport">
   42.45 +        <api name="text"/>
   42.46 +        <summary>CloneableEditor.initializeBySupport</summary>
   42.47 +        <version major="6" minor="37"/>
   42.48 +        <date day="7" month="4" year="2011"/>
   42.49 +        <author login="jtulach"/>
   42.50 +        <compatibility addition="yes" binary="compatible" deletion="no"
   42.51 +          deprecation="yes" modification="no" semantic="compatible" 
   42.52 +        />
   42.53 +        <description>
   42.54 +            <p>
   42.55 +                Subclasses of <code>CloneableEditor</code> can manually request own 
   42.56 +                initialization by calling its
   42.57 +                <a href="@TOP@/org/openide/text/CloneableEditor.html#initializeBySupport()">initializeBySupport</a>
   42.58 +                method.
   42.59 +            </p>
   42.60 +        </description>
   42.61 +        <class package="org.openide.text" name="CloneableEditor"/>
   42.62 +        <issue number="196810"/>
   42.63 +    </change>
   42.64      <change id="NbDocument-Annotatable">
   42.65          <api name="text"/>
   42.66          <summary>NbDocument.Annotatable threading changes</summary>
    43.1 --- a/openide.text/manifest.mf	Wed May 25 16:24:45 2011 +0200
    43.2 +++ b/openide.text/manifest.mf	Wed May 25 16:50:33 2011 +0200
    43.3 @@ -1,7 +1,7 @@
    43.4  Manifest-Version: 1.0
    43.5  OpenIDE-Module: org.openide.text
    43.6  OpenIDE-Module-Install: org/netbeans/modules/openide/text/Installer.class
    43.7 -OpenIDE-Module-Specification-Version: 6.38
    43.8 +OpenIDE-Module-Specification-Version: 6.39
    43.9  OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
   43.10  AutoUpdate-Essential-Module: true
   43.11  
    44.1 --- a/openide.text/src/org/openide/text/CloneableEditor.java	Wed May 25 16:24:45 2011 +0200
    44.2 +++ b/openide.text/src/org/openide/text/CloneableEditor.java	Wed May 25 16:50:33 2011 +0200
    44.3 @@ -143,12 +143,27 @@
    44.4      * @param support support that holds the document and operations above it
    44.5      */
    44.6      public CloneableEditor(CloneableEditorSupport support) {
    44.7 +        this(support, false);
    44.8 +    }
    44.9 +
   44.10 +    /** Creates new editor component associated with
   44.11 +    * support object (possibly also with its 
   44.12 +    * {@link CloneableEditorSupport#CloneableEditorSupport(org.openide.text.CloneableEditorSupport.Env, org.openide.util.Lookup) lookup}.
   44.13 +    * 
   44.14 +    * @param support support that holds the document and operations above it
   44.15 +    * @param associateLookup true, if {@link #getLookup()} should return the lookup
   44.16 +    *   associated with {@link CloneableEditorSupport}.
   44.17 +    */
   44.18 +    public CloneableEditor(CloneableEditorSupport support, boolean associateLookup) {
   44.19          super();
   44.20          this.support = support;
   44.21  
   44.22          updateName();
   44.23          _setCloseOperation();
   44.24          setMinimumSize(new Dimension(10, 10));
   44.25 +        if (associateLookup) {
   44.26 +            associateLookup(support.getLookup());
   44.27 +        }
   44.28      }
   44.29      @SuppressWarnings("deprecation")
   44.30      private void _setCloseOperation() {
   44.31 @@ -241,6 +256,18 @@
   44.32          }
   44.33          return !Boolean.TRUE.equals(getClientProperty("oldInitialize")); // NOI18N
   44.34      }
   44.35 +
   44.36 +    /** Asks the associated {@link CloneableEditorSupport} to initialize
   44.37 +     * this editor via its {@link CloneableEditorSupport#initializeCloneableEditor(org.openide.text.CloneableEditor)}
   44.38 +     * method. By default called from the support on various occasions including
   44.39 +     * shortly after creation and 
   44.40 +     * after the {@link CloneableEditor} has been deserialized.
   44.41 +     * 
   44.42 +     * @since 6.37 
   44.43 +     */
   44.44 +    protected final void initializeBySupport() {
   44.45 +        cloneableEditorSupport().initializeCloneableEditor(this);
   44.46 +    }
   44.47      
   44.48      class AWTQuery implements Runnable {
   44.49          private UserQuestionException ex;
   44.50 @@ -868,14 +895,27 @@
   44.51          }
   44.52      }
   44.53  
   44.54 -    /** When closing last view, also close the document.
   44.55 +    /** When closing last view, also close the document. 
   44.56 +     * Calls {@link #closeLast(boolean) closeLast(true)}.
   44.57       * @return <code>true</code> if close succeeded
   44.58       */
   44.59      @Override
   44.60      protected boolean closeLast() {
   44.61 -        if (!support.canClose()) {
   44.62 -            // if we cannot close the last window
   44.63 -            return false;
   44.64 +        return closeLast(true);
   44.65 +    }
   44.66 +    
   44.67 +    /** Utility method to close the document. 
   44.68 +     * 
   44.69 +     * @param ask verify and ask the user whether a document can be closed or not?
   44.70 +     * @return true if the document was successfully closed
   44.71 +     * @since 6.37
   44.72 +     */
   44.73 +    protected final boolean closeLast(boolean ask) {
   44.74 +        if (ask) {
   44.75 +            if (!support.canClose()) {
   44.76 +                // if we cannot close the last window
   44.77 +                return false;
   44.78 +            }
   44.79          }
   44.80  
   44.81          // close everything and do not ask
   44.82 @@ -1111,6 +1151,7 @@
   44.83          }
   44.84  
   44.85          out.writeObject(new Integer(pos));
   44.86 +        out.writeBoolean(getLookup() == support.getLookup());
   44.87      }
   44.88  
   44.89      @Override
   44.90 @@ -1138,6 +1179,12 @@
   44.91  
   44.92          updateName();
   44.93          isComponentOpened = true;
   44.94 +        if (in.available() > 0) {
   44.95 +            boolean associate = in.readBoolean();
   44.96 +            if (associate && support != null) {
   44.97 +                associateLookup(support.getLookup());
   44.98 +            }
   44.99 +        }
  44.100      }
  44.101  
  44.102      /**
  44.103 @@ -1167,7 +1214,7 @@
  44.104          if (discard()) {
  44.105              throw new java.io.InvalidObjectException("Deserialized component is invalid: " + this); // NOI18N
  44.106          } else {
  44.107 -            support.initializeCloneableEditor(this);
  44.108 +            initializeBySupport();
  44.109  
  44.110              return this;
  44.111          }
    45.1 --- a/openide.text/src/org/openide/text/CloneableEditorSupport.java	Wed May 25 16:24:45 2011 +0200
    45.2 +++ b/openide.text/src/org/openide/text/CloneableEditorSupport.java	Wed May 25 16:50:33 2011 +0200
    45.3 @@ -1324,7 +1324,8 @@
    45.4  
    45.5      /** Creates and initializes
    45.6       * new <code>CloneableEditor</code> component.
    45.7 -     * Typically do not override this method.
    45.8 +     * Typically do not override this method (unless you are dealing with 
    45.9 +     * <a href="@org-netbeans-core-multiview@/overview-summary.html">multiviews</a>).
   45.10       * For creating your own <code>CloneableEditor</code> type component
   45.11       * override {@link #createCloneableEditor} method.
   45.12       *
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/openide.text/test/unit/src/org/openide/text/CloneableEditorAssociateTest.java	Wed May 25 16:50:33 2011 +0200
    46.3 @@ -0,0 +1,245 @@
    46.4 +/*
    46.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    46.6 + *
    46.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    46.8 + *
    46.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   46.10 + * Other names may be trademarks of their respective owners.
   46.11 + *
   46.12 + * The contents of this file are subject to the terms of either the GNU
   46.13 + * General Public License Version 2 only ("GPL") or the Common
   46.14 + * Development and Distribution License("CDDL") (collectively, the
   46.15 + * "License"). You may not use this file except in compliance with the
   46.16 + * License. You can obtain a copy of the License at
   46.17 + * http://www.netbeans.org/cddl-gplv2.html
   46.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   46.19 + * specific language governing permissions and limitations under the
   46.20 + * License.  When distributing the software, include this License Header
   46.21 + * Notice in each file and include the License file at
   46.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   46.23 + * particular file as subject to the "Classpath" exception as provided
   46.24 + * by Oracle in the GPL Version 2 section of the License file that
   46.25 + * accompanied this code. If applicable, add the following below the
   46.26 + * License Header, with the fields enclosed by brackets [] replaced by
   46.27 + * your own identifying information:
   46.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   46.29 + *
   46.30 + * Contributor(s):
   46.31 + *
   46.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   46.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   46.34 + * Microsystems, Inc. All Rights Reserved.
   46.35 + *
   46.36 + * If you wish your version of this file to be governed by only the CDDL
   46.37 + * or only the GPL Version 2, indicate your decision by adding
   46.38 + * "[Contributor] elects to include this software in this distribution
   46.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   46.40 + * single choice of license, a recipient has the option to distribute
   46.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   46.42 + * to extend the choice of license to its licensees as provided above.
   46.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   46.44 + * Version 2 license, then the option applies only if the new code is
   46.45 + * made subject to such option by the copyright holder.
   46.46 + */
   46.47 +
   46.48 +package org.openide.text;
   46.49 +
   46.50 +
   46.51 +import java.beans.*;
   46.52 +import java.io.*;
   46.53 +import java.util.*;
   46.54 +import javax.swing.JEditorPane;
   46.55 +import org.netbeans.junit.NbTestCase;
   46.56 +import org.openide.util.Exceptions;
   46.57 +import org.openide.util.Lookup;
   46.58 +import org.openide.util.io.NbMarshalledObject;
   46.59 +import org.openide.util.lookup.AbstractLookup;
   46.60 +import org.openide.util.lookup.InstanceContent;
   46.61 +import org.openide.windows.*;
   46.62 +
   46.63 +public class CloneableEditorAssociateTest extends NbTestCase
   46.64 +implements CloneableEditorSupport.Env {
   46.65 +    static {
   46.66 +        System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false");
   46.67 +    }
   46.68 +    private transient InstanceContent ic;
   46.69 +    /** the support to work with */
   46.70 +    private transient CES support;
   46.71 +
   46.72 +    // Env variables
   46.73 +    private transient String content = "";
   46.74 +    private transient boolean valid = true;
   46.75 +    private transient boolean modified = false;
   46.76 +    /** if not null contains message why this document cannot be modified */
   46.77 +    private transient String cannotBeModified;
   46.78 +    private transient Date date = new Date ();
   46.79 +    private transient List/*<PropertyChangeListener>*/ propL = new ArrayList ();
   46.80 +    private transient VetoableChangeListener vetoL;
   46.81 +    
   46.82 +    private static CloneableEditorAssociateTest RUNNING;
   46.83 +    
   46.84 +    public CloneableEditorAssociateTest(String s) {
   46.85 +        super(s);
   46.86 +    }
   46.87 +    
   46.88 +    @Override
   46.89 +    protected void setUp () {
   46.90 +        ic = new InstanceContent();
   46.91 +        support = new CES (this, new AbstractLookup(ic));
   46.92 +        RUNNING = this;
   46.93 +    }
   46.94 +    
   46.95 +    @Override
   46.96 +    protected boolean runInEQ() {
   46.97 +        return true;
   46.98 +    }
   46.99 +    
  46.100 +    private Object writeReplace () {
  46.101 +        return new Replace ();
  46.102 +    }
  46.103 +    
  46.104 +    public void testGetOpenedPanesWorksAfterDeserializationIssue39236 () throws Exception {
  46.105 +        support.open ();
  46.106 +
  46.107 +        CloneableEditor ed = (CloneableEditor)support.getRef ().getAnyComponent ();
  46.108 +        ic.add(20);
  46.109 +        assertEquals("twenty", Integer.valueOf(20), ed.getLookup().lookup(Integer.class));
  46.110 +        ic.remove(20);
  46.111 +        assertNull("no twenty", ed.getLookup().lookup(Integer.class));
  46.112 +        
  46.113 +        JEditorPane[] panes = support.getOpenedPanes ();
  46.114 +        assertNotNull (panes);
  46.115 +        assertEquals ("One is there", 1, panes.length);
  46.116 +        
  46.117 +        NbMarshalledObject obj = new NbMarshalledObject (ed);
  46.118 +        ed.close ();
  46.119 +        
  46.120 +        panes = support.getOpenedPanes ();
  46.121 +        assertNull ("No panes anymore", panes);
  46.122 +        
  46.123 +        ed = (CloneableEditor)obj.get ();
  46.124 +        
  46.125 +        panes = support.getOpenedPanes ();
  46.126 +        assertNotNull ("One again", panes);
  46.127 +        assertEquals ("One is there again", 1, panes.length);
  46.128 +        
  46.129 +        ic.add(10);
  46.130 +        assertEquals("ten", Integer.valueOf(10), ed.getLookup().lookup(Integer.class));
  46.131 +    }
  46.132 +    
  46.133 +    //
  46.134 +    // Implementation of the CloneableEditorSupport.Env
  46.135 +    //
  46.136 +    
  46.137 +    public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
  46.138 +        propL.add (l);
  46.139 +    }    
  46.140 +    public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
  46.141 +        propL.remove (l);
  46.142 +    }
  46.143 +    
  46.144 +    public synchronized void addVetoableChangeListener(VetoableChangeListener l) {
  46.145 +        assertNull ("This is the first veto listener", vetoL);
  46.146 +        vetoL = l;
  46.147 +    }
  46.148 +    public void removeVetoableChangeListener(VetoableChangeListener l) {
  46.149 +        assertEquals ("Removing the right veto one", vetoL, l);
  46.150 +        vetoL = null;
  46.151 +    }
  46.152 +    
  46.153 +    public CloneableOpenSupport findCloneableOpenSupport() {
  46.154 +        return RUNNING.support;
  46.155 +    }
  46.156 +    
  46.157 +    public String getMimeType() {
  46.158 +        return "text/plain";
  46.159 +    }
  46.160 +    
  46.161 +    public Date getTime() {
  46.162 +        return date;
  46.163 +    }
  46.164 +    
  46.165 +    public InputStream inputStream() throws IOException {
  46.166 +        return new ByteArrayInputStream (content.getBytes ());
  46.167 +    }
  46.168 +    public OutputStream outputStream() throws IOException {
  46.169 +        class ContentStream extends ByteArrayOutputStream {
  46.170 +            public void close () throws IOException {
  46.171 +                super.close ();
  46.172 +                content = new String (toByteArray ());
  46.173 +            }
  46.174 +        }
  46.175 +        
  46.176 +        return new ContentStream ();
  46.177 +    }
  46.178 +    
  46.179 +    public boolean isValid() {
  46.180 +        return valid;
  46.181 +    }
  46.182 +    
  46.183 +    public boolean isModified() {
  46.184 +        return modified;
  46.185 +    }
  46.186 +
  46.187 +    public void markModified() throws IOException {
  46.188 +        if (cannotBeModified != null) {
  46.189 +            final String notify = cannotBeModified;
  46.190 +            IOException e = new IOException () {
  46.191 +                @Override
  46.192 +                public String getLocalizedMessage () {
  46.193 +                    return notify;
  46.194 +                }
  46.195 +            };
  46.196 +            Exceptions.attachLocalizedMessage(e, cannotBeModified);
  46.197 +            throw e;
  46.198 +        }
  46.199 +        
  46.200 +        modified = true;
  46.201 +    }
  46.202 +    
  46.203 +    public void unmarkModified() {
  46.204 +        modified = false;
  46.205 +    }
  46.206 +
  46.207 +    /** Implementation of the CES */
  46.208 +    private static final class CES extends CloneableEditorSupport {
  46.209 +        public CES (Env env, Lookup l) {
  46.210 +            super (env, l);
  46.211 +        }
  46.212 +        
  46.213 +        public CloneableTopComponent.Ref getRef () {
  46.214 +            return allEditors;
  46.215 +        }
  46.216 +        
  46.217 +        protected String messageName() {
  46.218 +            return "Name";
  46.219 +        }
  46.220 +        
  46.221 +        protected String messageOpened() {
  46.222 +            return "Opened";
  46.223 +        }
  46.224 +        
  46.225 +        protected String messageOpening() {
  46.226 +            return "Opening";
  46.227 +        }
  46.228 +        
  46.229 +        protected String messageSave() {
  46.230 +            return "Save";
  46.231 +        }
  46.232 +        
  46.233 +        protected String messageToolTip() {
  46.234 +            return "ToolTip";
  46.235 +        }
  46.236 +
  46.237 +        @Override
  46.238 +        protected CloneableEditor createCloneableEditor() {
  46.239 +            return new CloneableEditor(this, true);
  46.240 +        }
  46.241 +    }
  46.242 +
  46.243 +    private static final class Replace implements Serializable {
  46.244 +        public Object readResolve () {
  46.245 +            return RUNNING;
  46.246 +        }
  46.247 +    }
  46.248 +}
    47.1 --- a/openide.text/test/unit/src/org/openide/text/CloneableEditorTest.java	Wed May 25 16:24:45 2011 +0200
    47.2 +++ b/openide.text/test/unit/src/org/openide/text/CloneableEditorTest.java	Wed May 25 16:50:33 2011 +0200
    47.3 @@ -50,6 +50,7 @@
    47.4  import java.util.*;
    47.5  import javax.swing.JEditorPane;
    47.6  import org.netbeans.junit.NbTestCase;
    47.7 +import org.openide.nodes.Node;
    47.8  import org.openide.util.Exceptions;
    47.9  import org.openide.util.Lookup;
   47.10  import org.openide.util.io.NbMarshalledObject;
   47.11 @@ -116,6 +117,12 @@
   47.12          assertEquals ("One is there again", 1, panes.length);
   47.13      }
   47.14      
   47.15 +    public void testInitializeBySupport() {
   47.16 +        CloneableEditor ce = new CloneableEditor(support);
   47.17 +        ce.initializeBySupport();
   47.18 +        assertEquals("Nodes changed", Node.EMPTY, ce.getActivatedNodes()[0]);
   47.19 +    }
   47.20 +    
   47.21      public void testEditorPaneActionMapIsParentOfCloneableEditorActionMap() {
   47.22          support.open();
   47.23          
   47.24 @@ -228,6 +235,12 @@
   47.25          protected String messageToolTip() {
   47.26              return "ToolTip";
   47.27          }
   47.28 +
   47.29 +        @Override
   47.30 +        protected void initializeCloneableEditor(CloneableEditor editor) {
   47.31 +            editor.setActivatedNodes(new Node[] { Node.EMPTY });
   47.32 +        }
   47.33 +        
   47.34          
   47.35      }
   47.36