~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to xml/schema/src/org/netbeans/modules/xml/schema/multiview/SchemaABEViewMultiViewElement.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.xml.schema.multiview;
 
43
 
 
44
import java.awt.BorderLayout;
 
45
import java.awt.Color;
 
46
import java.awt.FlowLayout;
 
47
import java.beans.PropertyChangeEvent;
 
48
import java.beans.PropertyChangeListener;
 
49
import java.io.IOException;
 
50
import java.util.Arrays;
 
51
import javax.swing.ActionMap;
 
52
import javax.swing.JPanel;
 
53
import javax.swing.JSeparator;
 
54
import javax.swing.SwingConstants;
 
55
import javax.swing.SwingUtilities;
 
56
import javax.swing.UIManager;
 
57
import javax.swing.text.DefaultEditorKit;
 
58
import org.netbeans.core.spi.multiview.CloseOperationState;
 
59
import org.netbeans.core.spi.multiview.MultiViewElement;
 
60
import org.netbeans.core.spi.multiview.MultiViewElementCallback;
 
61
import org.netbeans.core.spi.multiview.MultiViewFactory;
 
62
import org.netbeans.modules.xml.axi.AXIModel;
 
63
import org.netbeans.modules.xml.axi.AXIModelFactory;
 
64
import org.netbeans.modules.xml.schema.abe.InstanceDesignerPanel;
 
65
import org.netbeans.modules.xml.schema.abe.UIUtilities;
 
66
import org.netbeans.modules.xml.schema.SchemaDataObject;
 
67
import org.netbeans.modules.xml.schema.SchemaEditorSupport;
 
68
import org.netbeans.modules.xml.schema.model.SchemaModel;
 
69
import org.netbeans.modules.xml.validation.ShowCookie;
 
70
import org.netbeans.modules.xml.xam.Component;
 
71
import org.netbeans.modules.xml.xam.Model.State;
 
72
import org.netbeans.modules.xml.xam.spi.Validator.ResultItem;
 
73
import org.netbeans.modules.xml.xam.ui.multiview.ActivatedNodesMediator;
 
74
import org.netbeans.modules.xml.xam.ui.multiview.CookieProxyLookup;
 
75
import org.netbeans.modules.xml.xam.ui.undo.QuietUndoManager;
 
76
import org.openide.util.Lookup;
 
77
import org.openide.windows.TopComponent;
 
78
import org.openide.awt.UndoRedo;
 
79
import org.openide.explorer.ExplorerManager;
 
80
import org.openide.explorer.ExplorerUtils;
 
81
import org.openide.nodes.Node;
 
82
import org.openide.util.HelpCtx;
 
83
import org.openide.util.NbBundle;
 
84
import org.openide.util.WeakListeners;
 
85
import org.openide.util.lookup.Lookups;
 
86
 
 
87
/**
 
88
 *
 
89
 * @author Jeri Lockhart
 
90
 */
 
91
public class SchemaABEViewMultiViewElement extends TopComponent
 
92
        implements  MultiViewElement, PropertyChangeListener,
 
93
        ExplorerManager.Provider  {
 
94
    
 
95
    private static final long serialVersionUID = -483941387931729295L;
 
96
    private AXIModel axiModel;
 
97
    private String errorMessage;
 
98
    private SchemaDataObject schemaDataObject;
 
99
    private InstanceDesignerPanel abeDesigner;
 
100
    private transient JPanel toolBarPanel;
 
101
    private javax.swing.JLabel errorLabel = new javax.swing.JLabel();
 
102
    private transient MultiViewElementCallback multiViewCallback;
 
103
    private ExplorerManager manager;
 
104
    
 
105
    public SchemaABEViewMultiViewElement() {
 
106
        super();
 
107
        // For deserialization only
 
108
    }
 
109
    
 
110
    public SchemaABEViewMultiViewElement(SchemaDataObject schemaDataObject) {
 
111
        super();
 
112
        this.schemaDataObject = schemaDataObject;
 
113
        initialize();
 
114
    }
 
115
    
 
116
    
 
117
    public void propertyChange(PropertyChangeEvent evt) {
 
118
        String property = evt.getPropertyName();        
 
119
        if(!AXIModel.STATE_PROPERTY.equals(property)) {
 
120
            return;
 
121
        }        
 
122
        State newState = (State)evt.getNewValue();
 
123
        if(newState == AXIModel.State.VALID) {
 
124
            errorMessage = null;
 
125
            recreateUI();
 
126
            return;
 
127
        }
 
128
        
 
129
        if(errorMessage == null)
 
130
            errorMessage = NbBundle.getMessage(
 
131
                    SchemaColumnViewMultiViewElement.class,
 
132
                    "MSG_InvalidSchema");
 
133
        //fix for IZ:116057
 
134
        SwingUtilities.invokeLater(new Runnable() {
 
135
            public void run() {
 
136
                setActivatedNodes(new Node[] {schemaDataObject.getNodeDelegate()});
 
137
            }
 
138
        });
 
139
        emptyUI(errorMessage);
 
140
    }
 
141
    
 
142
    public ExplorerManager getExplorerManager() {
 
143
        return manager;
 
144
    }
 
145
    
 
146
    private void initialize() {
 
147
        // Place the palette controller and some other things into the lookup
 
148
        Node delegate = schemaDataObject.getNodeDelegate();
 
149
        
 
150
        //show cookie
 
151
        ShowCookie showCookie = new ShowCookie() {
 
152
            
 
153
            public void show(ResultItem resultItem) {
 
154
                Component component = resultItem.getComponents();
 
155
                if(component!=null) {
 
156
                    abeDesigner.selectUIComponent(component);
 
157
                }
 
158
            }
 
159
        };
 
160
        
 
161
        ActivatedNodesMediator nodesMediator =
 
162
                new ActivatedNodesMediator(delegate);
 
163
        manager = new ExplorerManager();
 
164
        nodesMediator.setExplorerManager(this);
 
165
        ActionMap map = getActionMap();
 
166
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
 
167
        map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
 
168
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
 
169
        map.put("delete", ExplorerUtils.actionDelete(manager, false));
 
170
        
 
171
        CookieProxyLookup cpl = new CookieProxyLookup(new Lookup[] {
 
172
            nodesMediator.getLookup(),
 
173
            // use a proxy lookup here as the abeDesigner is only
 
174
            // active
 
175
            Lookups.proxy(new Lookup.Provider() {
 
176
                public Lookup getLookup() {
 
177
                    Lookup lookup = Lookup.EMPTY;
 
178
                    if (abeDesigner != null) {
 
179
                        lookup =
 
180
                                Lookups.singleton(abeDesigner.getPaletteController());
 
181
                    }
 
182
                    return lookup;
 
183
                }
 
184
            }),
 
185
            Lookups.fixed(new Object[] {
 
186
                // Need the action map in our custom lookup so actions work.
 
187
                getActionMap(),
 
188
                // Need the data object registered in the lookup so that the
 
189
                // projectui code will close our open editor windows when the
 
190
                // project is closed.
 
191
                schemaDataObject,
 
192
                // The Show Cookie in lookup to show schema component
 
193
                showCookie,
 
194
            }),
 
195
            // The Node delegate Lookup must be the last one in the list
 
196
            // for the CookieProxyLookup to work properly.
 
197
            delegate.getLookup(),
 
198
        }, delegate);
 
199
        associateLookup(cpl);
 
200
        addPropertyChangeListener("activatedNodes", nodesMediator);
 
201
        addPropertyChangeListener("activatedNodes", cpl);
 
202
        //initUI();
 
203
    }
 
204
    
 
205
    
 
206
    /**
 
207
     * Initializes the UI. Here it checks for the state of the underlying
 
208
     * schema model. If valid, draws the UI, else empties the UI with proper
 
209
     * error message.
 
210
     */
 
211
    boolean firsTime = true;
 
212
    private void initUI() {
 
213
        if(firsTime){
 
214
            setLayout(new BorderLayout());
 
215
            //initialize the error label one time.
 
216
            errorLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
 
217
            errorLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
 
218
            Color usualWindowBkg = UIManager.getColor("window"); //NOI18N
 
219
            errorLabel.setBackground(usualWindowBkg != null ? usualWindowBkg :
 
220
                Color.white);
 
221
            errorLabel.setOpaque(true);
 
222
            firsTime = false;
 
223
        }
 
224
        
 
225
        AXIModel model = getAXIModel();
 
226
        if( (model != null) &&
 
227
                (model.getState() == AXIModel.State.VALID) ) {
 
228
            recreateUI();
 
229
            return;
 
230
        }
 
231
        
 
232
        //if it comes here, either the schema is not well-formed or invalid
 
233
        if(errorMessage == null)
 
234
            errorMessage = NbBundle.getMessage(
 
235
                    SchemaColumnViewMultiViewElement.class,
 
236
                    "MSG_InvalidSchema");
 
237
        emptyUI(errorMessage);
 
238
    }
 
239
    
 
240
    /**
 
241
     * Creates the UI. Creates the abeDesigner only if it was null
 
242
     * or the underlying documnet was found modifed externally.
 
243
     */
 
244
    boolean propChangeListenerAdded = false;
 
245
    private void recreateUI() {
 
246
        if(abeDesigner == null){
 
247
            abeDesigner = new InstanceDesignerPanel(getAXIModel(), schemaDataObject, this);
 
248
        }
 
249
        // Add the ABE designer panel
 
250
        if(!isChild(abeDesigner)){
 
251
            add(abeDesigner,BorderLayout.CENTER);
 
252
        }
 
253
        if(!propChangeListenerAdded){
 
254
            abeDesigner.addPropertyChangeListener(this);
 
255
            propChangeListenerAdded = true;
 
256
        }
 
257
        if(errorLabel != null)
 
258
            errorLabel.setVisible(false);
 
259
        abeDesigner.setVisible(true);
 
260
        revalidate();
 
261
        repaint();
 
262
    }
 
263
    
 
264
    /**
 
265
     * Empties the UI, with proper error message, when the underlying
 
266
     * schema model is in INVALID/NOT-WELLFORMED state.
 
267
     */
 
268
    
 
269
    private void emptyUI(String errorMessage) {
 
270
        if(abeDesigner != null)
 
271
            abeDesigner.setVisible(false);
 
272
        errorLabel.setText("<" + errorMessage + ">");
 
273
        if(!isChild(errorLabel))
 
274
            add(errorLabel, BorderLayout.NORTH);
 
275
        if(propChangeListenerAdded){
 
276
            abeDesigner.addPropertyChangeListener(this);
 
277
            propChangeListenerAdded = false;
 
278
        }
 
279
        errorLabel.setVisible(true);
 
280
        revalidate();
 
281
        repaint();
 
282
    }
 
283
    
 
284
    private boolean isChild(java.awt.Component comp){
 
285
        java.awt.Component compArry[] = getComponents();
 
286
        if( (compArry == null) || (compArry.length <= 0) ){
 
287
            return false;
 
288
        }
 
289
        return Arrays.asList(compArry).contains(comp);
 
290
    }
 
291
    
 
292
    /////////////////////////////////////////////////////////////////////////////
 
293
    // MultiViewElement implementation
 
294
    /////////////////////////////////////////////////////////////////////////////
 
295
    
 
296
    /**
 
297
     *
 
298
     *
 
299
     */
 
300
    public int getPersistenceType() {
 
301
        return PERSISTENCE_NEVER;
 
302
    }
 
303
    
 
304
    public void setMultiViewCallback(MultiViewElementCallback callback) {
 
305
        multiViewCallback = callback;
 
306
    }
 
307
    
 
308
    
 
309
    public HelpCtx getHelpCtx() {
 
310
        return new HelpCtx(SchemaABEViewMultiViewDesc.class);
 
311
    }
 
312
    
 
313
    public CloseOperationState canCloseElement() {
 
314
        // if this is not the last cloned xml editor component, closing is OK
 
315
        if (!SchemaMultiViewSupport.isLastView(multiViewCallback.getTopComponent())) {
 
316
            return CloseOperationState.STATE_OK;
 
317
        }
 
318
        // return a placeholder state - to be sure our CloseHandler is called
 
319
        return MultiViewFactory.createUnsafeCloseState(
 
320
                "ID_SCHEMA_ABEVIEW_CLOSING", // dummy ID // NOI18N
 
321
                MultiViewFactory.NOOP_CLOSE_ACTION,
 
322
                MultiViewFactory.NOOP_CLOSE_ACTION);
 
323
    }
 
324
    
 
325
    /**
 
326
     *
 
327
     *
 
328
     */
 
329
    public void componentActivated() {
 
330
        super.componentActivated();
 
331
        ExplorerUtils.activateActions(manager, true);
 
332
        addUndoManager();
 
333
        UIUtilities.hideGlassMessage(true);
 
334
    }
 
335
    
 
336
    
 
337
    /**
 
338
     *
 
339
     *
 
340
     */
 
341
    public void componentClosed() {
 
342
        super.componentClosed();
 
343
        UIUtilities.hideGlassMessage(true);
 
344
        if(abeDesigner != null) {
 
345
            abeDesigner.shutdown();
 
346
            abeDesigner = null;
 
347
        }
 
348
        removeUndoManager();
 
349
        this.removeAll();
 
350
        this.setLayout(null);
 
351
        //associateLookup(Lookup.EMPTY);
 
352
    }
 
353
    
 
354
    
 
355
    /**
 
356
     *
 
357
     *
 
358
     */
 
359
    public void componentDeactivated() {
 
360
        super.componentDeactivated();
 
361
        ExplorerUtils.activateActions(manager, false);
 
362
        UIUtilities.hideGlassMessage(true);
 
363
    }
 
364
    
 
365
    
 
366
    /**
 
367
     *
 
368
     *
 
369
     */
 
370
    public void componentHidden() {
 
371
        super.componentHidden();
 
372
        UIUtilities.hideGlassMessage(true);
 
373
    }
 
374
    
 
375
    
 
376
    /**
 
377
     *
 
378
     *
 
379
     */
 
380
    public void componentOpened() {
 
381
        super.componentOpened();
 
382
        UIUtilities.hideGlassMessage(true);
 
383
    }
 
384
    
 
385
    
 
386
    /**
 
387
     *
 
388
     *
 
389
     */
 
390
    public void componentShowing() {
 
391
        super.componentShowing();
 
392
        initUI();
 
393
        addUndoManager();
 
394
        UIUtilities.hideGlassMessage(true);
 
395
    }
 
396
 
 
397
    @SuppressWarnings("deprecation")
 
398
    public void requestFocus() {
 
399
        super.requestFocus();
 
400
        // For Help to work properly, need to take focus.
 
401
        if (abeDesigner != null) {
 
402
            abeDesigner.requestFocus();
 
403
        }
 
404
    }
 
405
 
 
406
    @SuppressWarnings("deprecation")
 
407
    public boolean requestFocusInWindow() {
 
408
        boolean retVal = super.requestFocusInWindow();
 
409
        // For Help to work properly, need to take focus.
 
410
        if (abeDesigner != null) {
 
411
            return abeDesigner.requestFocusInWindow();
 
412
        }
 
413
        return retVal;
 
414
    }
 
415
 
 
416
    /**
 
417
     *
 
418
     *
 
419
     */
 
420
    public javax.swing.JComponent getToolbarRepresentation() {
 
421
        if (toolBarPanel == null) {
 
422
            toolBarPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
 
423
            
 
424
            //dummy panel for spacing
 
425
            //toolBarPanel.add(new JPanel(), BorderLayout.);
 
426
            
 
427
            JSeparator jsep = new JSeparator(SwingConstants.VERTICAL);
 
428
            toolBarPanel.add(jsep);
 
429
            
 
430
        }
 
431
        return toolBarPanel;
 
432
    }
 
433
    
 
434
    
 
435
    /**
 
436
     * Adds the undo/redo manager to the schema model as an undoable
 
437
     * edit listener, so it receives the edits onto the queue.
 
438
     */
 
439
    private void addUndoManager() {
 
440
        SchemaModel model = getAXIModel().getSchemaModel();
 
441
        if (model != null) {
 
442
            SchemaEditorSupport editor = schemaDataObject.getSchemaEditorSupport();
 
443
            QuietUndoManager undo = editor.getUndoManager();
 
444
            // Ensure the listener is not added twice.
 
445
            model.removeUndoableEditListener(undo);
 
446
            model.addUndoableEditListener(undo);
 
447
            // Ensure the model is sync'd when undo/redo is invoked,
 
448
            // otherwise the edits are added to the queue and eventually
 
449
            // cause exceptions.
 
450
            undo.setModel(model);
 
451
            undo.addWrapperModel(getAXIModel());
 
452
        }
 
453
    }
 
454
    
 
455
    private void removeUndoManager() {
 
456
        SchemaModel model = getAXIModel().getSchemaModel();
 
457
        if (model != null) {
 
458
            SchemaEditorSupport editor = schemaDataObject.getSchemaEditorSupport();
 
459
            QuietUndoManager undo = editor.getUndoManager();
 
460
            model.removeUndoableEditListener(undo);
 
461
            undo.removeWrapperModel(model);
 
462
        }
 
463
    }
 
464
    
 
465
    /**
 
466
     *
 
467
     *
 
468
     */
 
469
    public UndoRedo getUndoRedo() {
 
470
        return schemaDataObject.getSchemaEditorSupport().getUndoManager();
 
471
    }
 
472
    
 
473
    private AXIModel getAXIModel() {
 
474
        if (axiModel != null) {
 
475
            return axiModel;
 
476
        }
 
477
        try {
 
478
            SchemaModel sModel = schemaDataObject.
 
479
                    getSchemaEditorSupport().getModel();
 
480
            axiModel = AXIModelFactory.getDefault().getModel(sModel);
 
481
            if (axiModel != null) {
 
482
                PropertyChangeListener pcl = WeakListeners.
 
483
                        create(PropertyChangeListener.class, this, axiModel);
 
484
                axiModel.addPropertyChangeListener(pcl);
 
485
            }
 
486
        } catch (IOException e) {
 
487
            errorMessage = e.getMessage();
 
488
        }
 
489
        return axiModel;
 
490
    }
 
491
    
 
492
    /**
 
493
     *
 
494
     *
 
495
     */
 
496
    public javax.swing.JComponent getVisualRepresentation() {
 
497
        return this;
 
498
    }
 
499
    
 
500
}