001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.db.explorer;
043:
044: import java.beans.PropertyChangeEvent;
045: import java.beans.PropertyChangeListener;
046: import java.beans.PropertyChangeSupport;
047: import java.text.MessageFormat;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Comparator;
051: import java.util.List;
052: import java.util.ResourceBundle;
053: import java.util.TreeSet;
054: import java.util.Vector;
055: import java.util.logging.Level;
056: import java.util.logging.Logger;
057: import javax.swing.SwingUtilities;
058:
059: import org.openide.nodes.AbstractNode;
060: import org.openide.nodes.Node;
061: import org.openide.nodes.Children;
062: import org.openide.util.NbBundle;
063: import org.openide.util.RequestProcessor;
064:
065: import org.netbeans.api.db.explorer.DatabaseException;
066: import org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo;
067: import org.netbeans.modules.db.explorer.infos.ProcedureNodeInfo;
068: import org.netbeans.modules.db.explorer.infos.TableNodeInfo;
069: import org.netbeans.modules.db.explorer.infos.ViewNodeInfo;
070: import org.netbeans.modules.db.explorer.nodes.DatabaseNode;
071: import org.openide.DialogDisplayer;
072: import org.openide.NotifyDescriptor;
073:
074: //import org.openide.util.Mutex;
075:
076: // XXX This entire class is junk. Should have a sensible data model independent of
077: // nodes and display it using Children.Keys (or Looks) and everything would be
078: // much easier. -jglick
079:
080: // I totally agree. It was planed to redesign the module and base it on a data model
081: // unfortunately this project was cancelled. Radko
082:
083: public class DatabaseNodeChildren extends Children.Array {
084:
085: private ResourceBundle bundle = NbBundle
086: .getBundle("org.netbeans.modules.db.resources.Bundle"); //NOI18N
087:
088: private TreeSet children;
089: private transient PropertyChangeSupport propertySupport = new PropertyChangeSupport(
090: this );
091: private static Object sync = new Object(); // synchronizing object
092: // synchronized by additionalNodes
093: private boolean initialized = false; // true if the node is displaying its children (not the "Please wait..." node)
094: // synchronized by additionalNodes
095: private List additionalNodes = new ArrayList(); // nodes added by createSubnode() during the "Please wait..." phase
096:
097: private PropertyChangeListener listener = new PropertyChangeListener() {
098: public void propertyChange(PropertyChangeEvent event) {
099: if (event.getPropertyName().equals("finished")) { //NOI18N
100: MUTEX.writeAccess(new Runnable() {
101: public void run() {
102: remove(getNodes()); //remove wait node
103: nodes = getCh(); // change children ...
104: // add additional nodes created during the "Please wait..." phase
105: synchronized (additionalNodes) {
106: nodes.addAll(additionalNodes);
107: initialized = true;
108: }
109: refresh(); // ... and refresh them
110: }
111: });
112: removeListener();
113: }
114: }
115: };
116:
117: protected Collection initCollection() {
118: propertySupport.addPropertyChangeListener(listener);
119:
120: RequestProcessor.getDefault().post(new Runnable() {
121: public void run() {
122: DatabaseNodeInfo nodeinfo = ((DatabaseNode) getNode())
123: .getInfo();
124: java.util.Map nodeord = (java.util.Map) nodeinfo
125: .get(DatabaseNodeInfo.CHILDREN_ORDERING);
126: boolean sort = (nodeinfo.getName().equals("Drivers")
127: || (nodeinfo instanceof TableNodeInfo)
128: || (nodeinfo instanceof ViewNodeInfo) || (nodeinfo instanceof ProcedureNodeInfo)) ? false
129: : true; //NOI18N
130: TreeSet children = new TreeSet(new NodeComparator(
131: nodeord, sort));
132:
133: try {
134:
135: Vector chlist;
136: synchronized (sync) {
137: chlist = nodeinfo.getChildren();
138: }
139:
140: for (int i = 0; i < chlist.size(); i++) {
141: Node snode = null;
142: Object sinfo = chlist.elementAt(i);
143:
144: if (sinfo instanceof DatabaseNodeInfo) {
145: DatabaseNodeInfo dni = (DatabaseNodeInfo) sinfo;
146:
147: // aware! in this method is clone of instance dni created
148: snode = createNode(dni);
149:
150: } else if (sinfo instanceof Node)
151: snode = (Node) sinfo;
152: if (snode != null)
153: children.add(snode);
154: }
155:
156: //commented out for 3.6 release, need to solve for next Studio release
157: // if (getNode() instanceof RootNode) {
158: // // open connection (after initCollection done)
159: // SwingUtilities.invokeLater(new Runnable() {
160: // public void run() {
161: // try {
162: // // add connection (if needed) and make the connection to SAMPLE database connected
163: // PointbasePlus.addOrConnectAccordingToOption();
164: // } catch(Exception ex) {
165: // org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex);
166: // }
167: // }
168: // });
169: // }
170: } catch (Exception e) {
171: Logger.getLogger("global").log(Level.INFO, null, e);
172: showException(e);
173: children.clear();
174: }
175:
176: setCh(children);
177:
178: propertySupport.firePropertyChange("finished", null,
179: null); //NOI18N
180: }
181: }, 0);
182:
183: TreeSet ts = new TreeSet();
184: ts.add(createWaitNode());
185: return ts;
186: }
187:
188: public boolean getChildrenInitialized() {
189: return isInitialized();
190: }
191:
192: /* Creates and returns the instance of the node
193: * representing the status 'WAIT' of the node.
194: * It is used when it spent more time to create elements hierarchy.
195: * @return the wait node.
196: */
197: private Node createWaitNode() {
198: AbstractNode n = new AbstractNode(Children.LEAF);
199: n.setName(bundle.getString("WaitNode")); //NOI18N
200: n.setIconBase("org/netbeans/modules/db/resources/wait"); //NOI18N
201: return n;
202: }
203:
204: private TreeSet getCh() {
205: return children;
206: }
207:
208: private void setCh(TreeSet children) {
209: this .children = children;
210: }
211:
212: private void removeListener() {
213: propertySupport.removePropertyChangeListener(listener);
214: }
215:
216: class NodeComparator implements Comparator {
217: private java.util.Map map = null;
218: private boolean sort;
219:
220: public NodeComparator(java.util.Map map, boolean sort) {
221: this .map = map;
222: this .sort = sort;
223: }
224:
225: public int compare(Object o1, Object o2) {
226: if (!sort)
227: return 1;
228:
229: if (!(o1 instanceof DatabaseNode))
230: return -1;
231: if (!(o2 instanceof DatabaseNode))
232: return 1;
233:
234: int o1val, o2val, diff;
235: Integer o1i = (Integer) map.get(o1.getClass().getName());
236: if (o1i != null)
237: o1val = o1i.intValue();
238: else
239: o1val = Integer.MAX_VALUE;
240: Integer o2i = (Integer) map.get(o2.getClass().getName());
241: if (o2i != null)
242: o2val = o2i.intValue();
243: else
244: o2val = Integer.MAX_VALUE;
245:
246: diff = o1val - o2val;
247: if (diff == 0)
248: return ((DatabaseNode) o1)
249: .getInfo()
250: .getName()
251: .compareTo(
252: ((DatabaseNode) o2).getInfo().getName());
253: return diff;
254: }
255: }
256:
257: public DatabaseNode createNode(DatabaseNodeInfo info) {
258: String nclass = (String) info.get(DatabaseNodeInfo.CLASS);
259: DatabaseNode node = null;
260:
261: try {
262: node = (DatabaseNode) Class.forName(nclass).newInstance();
263: node.setInfo(info); /* makes a copy of info, use node.getInfo() to access it */
264: node.getInfo().setNode(node); /* this is a weak, be cool, baby ;) */
265: } catch (Exception e) {
266: showException(e);
267: }
268:
269: return node;
270: }
271:
272: public void addSubNode(Node subnode) {
273: //workaround for issue #31617, children should be initialized if they are not
274: // getNodes();
275: if (isInitialized()) {
276: synchronized (additionalNodes) {
277: if (initialized) {
278: add(new Node[] { subnode });
279: } else {
280: additionalNodes.add(subnode);
281: }
282: }
283: }
284:
285: }
286:
287: public DatabaseNode createSubnode(DatabaseNodeInfo info,
288: boolean addToChildrenFlag) throws DatabaseException {
289: DatabaseNode subnode = createNode(info);
290: if (subnode != null && addToChildrenFlag) {
291: DatabaseNodeInfo ninfo = ((DatabaseNode) getNode())
292: .getInfo();
293: ninfo.getChildren().add(info);
294:
295: addSubNode(subnode);
296: }
297:
298: return subnode;
299: }
300:
301: public void replaceNodes(Node[] nodes) {
302: if (isInitialized()) {
303: synchronized (additionalNodes) {
304: if (initialized) {
305: this .remove(this .getNodes());
306: this .add(nodes);
307: } else {
308: additionalNodes.clear();
309: for (Node node : nodes) {
310: additionalNodes.add(node);
311: }
312: }
313: }
314: }
315: }
316:
317: private void showException(final Exception e) {
318: SwingUtilities.invokeLater(new Runnable() {
319: public void run() {
320: ResourceBundle bundle = NbBundle
321: .getBundle("org.netbeans.modules.db.resources.Bundle"); //NOI18N
322: String format = bundle.getString("EXC_ConnectionError"); //NOI18N
323: String message = bundle
324: .getString("ReadStructureErrorPrefix")
325: + " "
326: + MessageFormat.format(format, new String[] { e
327: .getMessage() }); //NOI18N
328: DialogDisplayer.getDefault().notify(
329: new NotifyDescriptor.Message(message,
330: NotifyDescriptor.ERROR_MESSAGE));
331: }
332: });
333: }
334: }
|