2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
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]"
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.
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.
42
package org.netbeans.modules.xml.schema.multiview;
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;
89
* @author Jeri Lockhart
91
public class SchemaABEViewMultiViewElement extends TopComponent
92
implements MultiViewElement, PropertyChangeListener,
93
ExplorerManager.Provider {
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;
105
public SchemaABEViewMultiViewElement() {
107
// For deserialization only
110
public SchemaABEViewMultiViewElement(SchemaDataObject schemaDataObject) {
112
this.schemaDataObject = schemaDataObject;
117
public void propertyChange(PropertyChangeEvent evt) {
118
String property = evt.getPropertyName();
119
if(!AXIModel.STATE_PROPERTY.equals(property)) {
122
State newState = (State)evt.getNewValue();
123
if(newState == AXIModel.State.VALID) {
129
if(errorMessage == null)
130
errorMessage = NbBundle.getMessage(
131
SchemaColumnViewMultiViewElement.class,
132
"MSG_InvalidSchema");
134
SwingUtilities.invokeLater(new Runnable() {
136
setActivatedNodes(new Node[] {schemaDataObject.getNodeDelegate()});
139
emptyUI(errorMessage);
142
public ExplorerManager getExplorerManager() {
146
private void initialize() {
147
// Place the palette controller and some other things into the lookup
148
Node delegate = schemaDataObject.getNodeDelegate();
151
ShowCookie showCookie = new ShowCookie() {
153
public void show(ResultItem resultItem) {
154
Component component = resultItem.getComponents();
155
if(component!=null) {
156
abeDesigner.selectUIComponent(component);
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));
171
CookieProxyLookup cpl = new CookieProxyLookup(new Lookup[] {
172
nodesMediator.getLookup(),
173
// use a proxy lookup here as the abeDesigner is only
175
Lookups.proxy(new Lookup.Provider() {
176
public Lookup getLookup() {
177
Lookup lookup = Lookup.EMPTY;
178
if (abeDesigner != null) {
180
Lookups.singleton(abeDesigner.getPaletteController());
185
Lookups.fixed(new Object[] {
186
// Need the action map in our custom lookup so actions work.
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.
192
// The Show Cookie in lookup to show schema component
195
// The Node delegate Lookup must be the last one in the list
196
// for the CookieProxyLookup to work properly.
197
delegate.getLookup(),
199
associateLookup(cpl);
200
addPropertyChangeListener("activatedNodes", nodesMediator);
201
addPropertyChangeListener("activatedNodes", cpl);
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
211
boolean firsTime = true;
212
private void initUI() {
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 :
221
errorLabel.setOpaque(true);
225
AXIModel model = getAXIModel();
226
if( (model != null) &&
227
(model.getState() == AXIModel.State.VALID) ) {
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);
241
* Creates the UI. Creates the abeDesigner only if it was null
242
* or the underlying documnet was found modifed externally.
244
boolean propChangeListenerAdded = false;
245
private void recreateUI() {
246
if(abeDesigner == null){
247
abeDesigner = new InstanceDesignerPanel(getAXIModel(), schemaDataObject, this);
249
// Add the ABE designer panel
250
if(!isChild(abeDesigner)){
251
add(abeDesigner,BorderLayout.CENTER);
253
if(!propChangeListenerAdded){
254
abeDesigner.addPropertyChangeListener(this);
255
propChangeListenerAdded = true;
257
if(errorLabel != null)
258
errorLabel.setVisible(false);
259
abeDesigner.setVisible(true);
265
* Empties the UI, with proper error message, when the underlying
266
* schema model is in INVALID/NOT-WELLFORMED state.
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;
279
errorLabel.setVisible(true);
284
private boolean isChild(java.awt.Component comp){
285
java.awt.Component compArry[] = getComponents();
286
if( (compArry == null) || (compArry.length <= 0) ){
289
return Arrays.asList(compArry).contains(comp);
292
/////////////////////////////////////////////////////////////////////////////
293
// MultiViewElement implementation
294
/////////////////////////////////////////////////////////////////////////////
300
public int getPersistenceType() {
301
return PERSISTENCE_NEVER;
304
public void setMultiViewCallback(MultiViewElementCallback callback) {
305
multiViewCallback = callback;
309
public HelpCtx getHelpCtx() {
310
return new HelpCtx(SchemaABEViewMultiViewDesc.class);
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;
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);
329
public void componentActivated() {
330
super.componentActivated();
331
ExplorerUtils.activateActions(manager, true);
333
UIUtilities.hideGlassMessage(true);
341
public void componentClosed() {
342
super.componentClosed();
343
UIUtilities.hideGlassMessage(true);
344
if(abeDesigner != null) {
345
abeDesigner.shutdown();
350
this.setLayout(null);
351
//associateLookup(Lookup.EMPTY);
359
public void componentDeactivated() {
360
super.componentDeactivated();
361
ExplorerUtils.activateActions(manager, false);
362
UIUtilities.hideGlassMessage(true);
370
public void componentHidden() {
371
super.componentHidden();
372
UIUtilities.hideGlassMessage(true);
380
public void componentOpened() {
381
super.componentOpened();
382
UIUtilities.hideGlassMessage(true);
390
public void componentShowing() {
391
super.componentShowing();
394
UIUtilities.hideGlassMessage(true);
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();
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();
420
public javax.swing.JComponent getToolbarRepresentation() {
421
if (toolBarPanel == null) {
422
toolBarPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
424
//dummy panel for spacing
425
//toolBarPanel.add(new JPanel(), BorderLayout.);
427
JSeparator jsep = new JSeparator(SwingConstants.VERTICAL);
428
toolBarPanel.add(jsep);
436
* Adds the undo/redo manager to the schema model as an undoable
437
* edit listener, so it receives the edits onto the queue.
439
private void addUndoManager() {
440
SchemaModel model = getAXIModel().getSchemaModel();
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
450
undo.setModel(model);
451
undo.addWrapperModel(getAXIModel());
455
private void removeUndoManager() {
456
SchemaModel model = getAXIModel().getSchemaModel();
458
SchemaEditorSupport editor = schemaDataObject.getSchemaEditorSupport();
459
QuietUndoManager undo = editor.getUndoManager();
460
model.removeUndoableEditListener(undo);
461
undo.removeWrapperModel(model);
469
public UndoRedo getUndoRedo() {
470
return schemaDataObject.getSchemaEditorSupport().getUndoManager();
473
private AXIModel getAXIModel() {
474
if (axiModel != null) {
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);
486
} catch (IOException e) {
487
errorMessage = e.getMessage();
496
public javax.swing.JComponent getVisualRepresentation() {