001: /*
002: * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
003: * NETSCAPE COMMUNICATIONS CORPORATION
004: *
005: * Copyright (c) 1996 Netscape Communications Corporation.
006: * All Rights Reserved.
007: * Use of this Source Code is subject to the terms of the applicable
008: * license agreement from Netscape Communications Corporation.
009: */
010:
011: package components;
012:
013: import communications.PostConnection;
014: import graphical.Header;
015: import graphical.HyperTextFilter;
016: import graphical.TreeView;
017: import soif.CSID;
018: import soif.SOIF;
019: import soif.SOIFParser;
020: import soif.Taxonomy;
021: import soif.TaxonomyNode;
022: import soif.TaxonomyGetter;
023: import util.BinaryTree;
024: import util.BTreeNode;
025: import util.ReportError;
026:
027: import java.awt.Dimension;
028:
029: import netscape.application.Color;
030: import netscape.application.ContainerView;
031: import netscape.application.ListItem;
032: import netscape.application.Size;
033: import netscape.application.Target;
034: import netscape.application.TextField;
035: import netscape.application.View;
036:
037: public class TaxonomyTreeView extends TreeView {
038: public Taxonomy taxonomy;
039:
040: public TextField descLabel;
041: public TextField description;
042: public TextField matchLabel;
043: public TextField matchingRule;
044:
045: private String CGILocation;
046: private String CGITarget;
047: private String CGIRead;
048: private String CGIWrite;
049: private CSID csid;
050: private boolean pro;
051:
052: public ContainerView detailView;
053: public Target notifyOfSelect;
054: public Target notifyOfChange;
055:
056: private TaxonomyGetter tg;
057:
058: // SGP: hack to support correct deletion of entire tree
059: public applications.TaxonomyEdit te;
060: public applications.Desktop dt;
061:
062: private boolean changed;
063:
064: /**
065: * Construct instance of TaxonomyTreeView.
066: * @param CGILocation cgi location
067: * @param CGITarget cgi target
068: * @param CGIRead cgi read argument
069: * @param CGIWrite cgi write argument
070: * @param csid csid
071: * @param editable editable or not
072: * @param x x
073: * @param y y
074: * @param w width
075: * @param h height
076: * @param dragSourcePolicy drag source policy
077: * @param dragDestinationPolicy drag destination policy
078: * @param sizeForWindow size for containment in a window or a view
079: * @param nameSpace url for space image
080: * @param nameDocumentSel url for selected document image
081: * @param nameDocument url for document image
082: * @param nameFolderSel url for selected folder image
083: * @param nameFolder url for folder image
084: * @param nameBranchOpenSel url for selected branch open image
085: * @param nameBranchOpen url for branch open image
086: * @param nameBranchClosedSel url for selected branch closed image
087: * @param nameBranchClosed url for branch closed image
088: */
089: public TaxonomyTreeView(String CGILocation, String CGITarget,
090: String CGIRead, String CGIWrite, CSID csid, boolean pro,
091: boolean editable, int x, int y, int w, int h,
092: int dragSourcePolicy, int dragDestinationPolicy,
093: boolean sizeForWindow, String nameSpace,
094: String nameDocumentSel, String nameDocument,
095: String nameFolderSel, String nameFolder,
096: String nameBranchOpenSel, String nameBranchOpen,
097: String nameBranchClosedSel, String nameBranchClosed) {
098: super (null, editable, x, y, w, h, dragSourcePolicy,
099: dragDestinationPolicy, sizeForWindow, nameSpace,
100: nameDocumentSel, nameDocument, nameFolderSel,
101: nameFolder, nameBranchOpenSel, nameBranchOpen,
102: nameBranchClosedSel, nameBranchClosed);
103:
104: this .CGILocation = CGILocation;
105: this .CGITarget = CGITarget;
106: this .CGIRead = CGIRead;
107: this .CGIWrite = CGIWrite;
108: this .csid = csid;
109: this .pro = pro;
110:
111: obtainTaxonomy();
112: commonConstruction();
113: }
114:
115: /**
116: * Construct instance of TaxonomyTreeView.
117: * @param CGILocation cgi location
118: * @param CGITarget cgi target
119: * @param CGIRead cgi read argument
120: * @param CGIWrite cgi write argument
121: * @param csid csid
122: * @param editable editable or not
123: * @param x x
124: * @param y y
125: * @param w width
126: * @param h height
127: * @param dragSourcePolicy drag source policy
128: * @param dragDestinationPolicy drag destination policy
129: * @param sizeForWindow size for containment in a window or a view
130: * @param arraySpace pixel array for space
131: * @param arrayDocumentSel pixel array for selected document
132: * @param arrayDocument pixel array for document
133: * @param arrayFolderSel pixel array for selected folder
134: * @param arrayFolder pixel array for folder
135: * @param arrayBranchOpenSel pixel array for selected branch open
136: * @param arrayBranchOpen pixel array for branch open
137: * @param arrayBranchClosedSel pixel array for selected branch closed
138: * @param arrayBranchClosed pixel array for branch closed
139: */
140: public TaxonomyTreeView(String CGILocation, String CGITarget,
141: String CGIRead, String CGIWrite, CSID csid, boolean pro,
142: boolean editable, int x, int y, int w, int h,
143: int dragSourcePolicy, int dragDestinationPolicy,
144: boolean sizeForWindow, int arraySpace[],
145: int arrayDocumentSel[], int arrayDocument[],
146: int arrayFolderSel[], int arrayFolder[],
147: int arrayBranchOpenSel[], int arrayBranchOpen[],
148: int arrayBranchClosedSel[], int arrayBranchClosed[],
149: Dimension imageSize, int pixelCount) {
150: super (null, editable, x, y, w, h, dragSourcePolicy,
151: dragDestinationPolicy, sizeForWindow, arraySpace,
152: arrayDocumentSel, arrayDocument, arrayFolderSel,
153: arrayFolder, arrayBranchOpenSel, arrayBranchOpen,
154: arrayBranchClosedSel, arrayBranchClosed, imageSize,
155: pixelCount);
156:
157: this .CGILocation = CGILocation;
158: this .CGITarget = CGITarget;
159: this .CGIRead = CGIRead;
160: this .CGIWrite = CGIWrite;
161: this .csid = csid;
162: this .pro = pro;
163:
164: obtainTaxonomy();
165: commonConstruction();
166: }
167:
168: /**
169: * Construct instance of TaxonomyTreeView.
170: * @param taxonomy taxonomy
171: * @param editable editable or not
172: * @param x x
173: * @param y y
174: * @param w width
175: * @param h height
176: * @param dragSourcePolicy drag source policy
177: * @param dragDestinationPolicy drag destination policy
178: * @param sizeForWindow size for containment in a window or a view
179: * @param nameSpace url for space image
180: * @param nameDocumentSel url for selected document image
181: * @param nameDocument url for document image
182: * @param nameFolderSel url for selected folder image
183: * @param nameFolder url for folder image
184: * @param nameBranchOpenSel url for selected branch open image
185: * @param nameBranchOpen url for branch open image
186: * @param nameBranchClosedSel url for selected branch closed image
187: * @param nameBranchClosed url for branch closed image
188: */
189: public TaxonomyTreeView(Taxonomy taxonomy, boolean editable, int x,
190: int y, int w, int h, int dragSourcePolicy,
191: int dragDestinationPolicy, boolean sizeForWindow,
192: String nameSpace, String nameDocumentSel,
193: String nameDocument, String nameFolderSel,
194: String nameFolder, String nameBranchOpenSel,
195: String nameBranchOpen, String nameBranchClosedSel,
196: String nameBranchClosed) {
197: super (null, editable, x, y, w, h, dragSourcePolicy,
198: dragDestinationPolicy, sizeForWindow, nameSpace,
199: nameDocumentSel, nameDocument, nameFolderSel,
200: nameFolder, nameBranchOpenSel, nameBranchOpen,
201: nameBranchClosedSel, nameBranchClosed);
202:
203: this .taxonomy = taxonomy;
204:
205: this .CGILocation = null;
206: this .CGITarget = null;
207: this .CGIRead = null;
208: this .CGIWrite = null;
209: this .csid = null;
210:
211: tg = null;
212:
213: commonConstruction();
214: }
215:
216: /**
217: * Construct instance of TaxonomyTreeView.
218: * @param taxonomy taxonomy
219: * @param editable editable or not
220: * @param x x
221: * @param y y
222: * @param w width
223: * @param h height
224: * @param dragSourcePolicy drag source policy
225: * @param dragDestinationPolicy drag destination policy
226: * @param sizeForWindow size for containment in a window or a view
227: * @param arraySpace pixel array for space
228: * @param arrayDocumentSel pixel array for selected document
229: * @param arrayDocument pixel array for document
230: * @param arrayFolderSel pixel array for selected folder
231: * @param arrayFolder pixel array for folder
232: * @param arrayBranchOpenSel pixel array for selected branch open
233: * @param arrayBranchOpen pixel array for branch open
234: * @param arrayBranchClosedSel pixel array for selected branch closed
235: * @param arrayBranchClosed pixel array for branch closed
236: */
237: public TaxonomyTreeView(Taxonomy taxonomy, boolean editable, int x,
238: int y, int w, int h, int dragSourcePolicy,
239: int dragDestinationPolicy, boolean sizeForWindow,
240: int arraySpace[], int arrayDocumentSel[],
241: int arrayDocument[], int arrayFolderSel[],
242: int arrayFolder[], int arrayBranchOpenSel[],
243: int arrayBranchOpen[], int arrayBranchClosedSel[],
244: int arrayBranchClosed[], Dimension imageSize, int pixelCount) {
245: super (null, editable, x, y, w, h, dragSourcePolicy,
246: dragDestinationPolicy, sizeForWindow, arraySpace,
247: arrayDocumentSel, arrayDocument, arrayFolderSel,
248: arrayFolder, arrayBranchOpenSel, arrayBranchOpen,
249: arrayBranchClosedSel, arrayBranchClosed, imageSize,
250: pixelCount);
251:
252: this .taxonomy = taxonomy;
253:
254: this .CGILocation = null;
255: this .CGITarget = null;
256: this .CGIRead = null;
257: this .CGIWrite = null;
258: this .csid = null;
259:
260: tg = null;
261:
262: commonConstruction();
263: }
264:
265: private void commonConstruction() {
266: // setLook( NSLOOK );
267: // setFeel( NSFEEL );
268:
269: changed = false;
270: te = null;
271: dt = null;
272: notifyOfSelect = null;
273: description = new TextField();
274: descLabel = TextField.createLabel(Messages.LBL_DESCRIPTION
275: + ":");
276: if (pro) {
277: matchingRule = new TextField();
278: matchLabel = TextField
279: .createLabel(Messages.LBL_AUTOCLASSIFYRULE + ":");
280: }
281:
282: detailView = new ContainerView();
283:
284: setDupePeerNamesAllowed(false);
285:
286: if (editable()) {
287: HyperTextFilter htf = HyperTextFilter
288: .createI18NAlphaNumericFilter(
289: util.Key.I18NALPHANUMERIC_COUNT + 19, true);
290: htf.put(new Integer(10), new Character(' ')); // return, enter
291: htf.put(new Integer(32), new Character(' '));
292: htf.put(new Integer(33), new Character('!'));
293: htf.put(new Integer(38), new Character('&'));
294: htf.put(new Integer(39), new Character('\''));
295: htf.put(new Integer(44), new Character(','));
296: htf.put(new Integer(45), new Character('-'));
297: htf.put(new Integer(46), new Character('.'));
298: htf.put(new Integer(47), new Character('/'));
299: htf.put(new Integer(63), new Character('?'));
300: htf.put(new Integer(95), new Character('_'));
301:
302: // SGP: push nav stuff into HyperTextFilter
303: htf.put(new Integer(8), new Character('\010')); // bs
304: htf.put(new Integer(127), new Character('\177')); // del
305: htf.put(new Integer(1000), new Character(' ')); // home
306: htf.put(new Integer(1001), new Character(' ')); // end
307: htf.put(new Integer(1006), new Character(' ')); // left arrow
308: htf.put(new Integer(1007), new Character(' ')); // right arrow
309: textField.setFilter(htf);
310: // htf.debug = true;
311:
312: // note that the following is organized
313: // to be easy to understand and maintain,
314: // not to try to achieve the most efficient
315: // solution.
316:
317: // set the label size and add it
318: descLabel.setBounds(graphical.Header.WIDGETHGAP
319: + graphical.Header.ALIGNTREEHGAP,
320: graphical.Header.WIDGETVGAP,
321: descLabel.minSize().width,
322: descLabel.minSize().height);
323: detailView.addSubview(descLabel);
324:
325: // first, move the detailView (makes size
326: // calc a little less dazzling).
327: detailView.moveTo(graphical.Header.WIDGETHGAP, scrollGroup
328: .height()
329: + scrollGroup.y() + graphical.Header.WIDGETVGAP);
330:
331: // now, size based on cancelBtn position
332: detailView.sizeTo(cancelBtn.x() - detailView.x()
333: - graphical.Header.WIDGETHGAP, description
334: .minSize().height
335: + graphical.Header.WIDGETVGAP
336: * 2
337: + (pro ? matchingRule.minSize().height
338: + graphical.Header.WIDGETVGAP : 0));
339: addSubview(detailView);
340:
341: detailView.setHorizResizeInstruction(View.WIDTH_CAN_CHANGE);
342: detailView
343: .setVertResizeInstruction(View.TOP_MARGIN_CAN_CHANGE);
344:
345: // now, position the description
346: description.moveTo(descLabel.x() + descLabel.width()
347: + graphical.Header.WIDGETHGAP, descLabel.y());
348:
349: // size description to fit w/in detail
350: description.sizeTo(detailView.width() - description.x() - 2
351: * graphical.Header.WIDGETHGAP, description
352: .minSize().height);
353: description
354: .setHorizResizeInstruction(View.WIDTH_CAN_CHANGE);
355: detailView.addSubview(description);
356:
357: if (pro) {
358:
359: // set the matchLabel geometry
360: matchLabel.moveTo(descLabel.x(), descLabel.x()
361: + descLabel.height()
362: + graphical.Header.WIDGETVGAP);
363: matchLabel.sizeTo(matchLabel.minSize().width,
364: matchLabel.minSize().height);
365: detailView.addSubview(matchLabel);
366:
367: // set the matchingRule geometry
368: matchingRule.moveTo(matchLabel.x() + matchLabel.width()
369: + graphical.Header.WIDGETHGAP, matchLabel.y());
370: matchingRule.sizeTo(detailView.width()
371: - matchingRule.x() - 2
372: * graphical.Header.WIDGETHGAP, matchingRule
373: .minSize().height);
374: detailView.addSubview(matchingRule);
375:
376: matchingRule
377: .setHorizResizeInstruction(View.WIDTH_CAN_CHANGE);
378: }
379:
380: // hide the buttons
381: saveBtn.moveTo(Integer.MIN_VALUE, saveBtn.y());
382: cancelBtn.moveTo(Integer.MIN_VALUE, cancelBtn.y());
383:
384: // adjust to take into account the new detail
385: // size needs.
386: int hdiff = detailView.height() - saveBtn.height();
387: scrollGroup.sizeTo(scrollGroup.width(), scrollGroup
388: .height()
389: - hdiff);
390: detailView.moveTo(detailView.x(), detailView.y() - hdiff);
391:
392: // up to this point, detailView is sized to
393: // be a snug fit around it's components but
394: // sized to leave WIDGETHGAP between it and
395: // cancelBtn. now it will adjust out to
396: // scrollGroup.width(). don't know what's
397: // up w/ the HGAP subtraction.
398: detailView.sizeTo(scrollGroup.width()
399: - graphical.Header.WIDGETHGAP, detailView.height());
400: }
401:
402: if (tg != null) {
403: tg.waitFor();
404: taxonomy = tg.getTaxonomy();
405: }
406:
407: if (taxonomy != null) {
408: setBinaryTree(taxonomy.binaryTree);
409: }
410:
411: if (editable()) {
412: setEditListItem();
413: setDragDroppedNotificationCommand(Messages.CMD_DROPPED);
414: setDragDroppedNotificationTarget(this );
415: }
416: }
417:
418: public void hideEditButtons() {
419: int hdiff = (scrollGroup.y() - newPeerBtn.y())
420: - graphical.Header.WIDGETVGAP;
421: detailView.moveTo(detailView.x(), detailView.y() - hdiff);
422: scrollGroup.sizeTo(scrollGroup.width(), scrollGroup.height()
423: - hdiff);
424: super .hideEditButtons();
425: }
426:
427: private void obtainTaxonomy() {
428: taxonomy = null;
429:
430: if ((CGILocation != null) && (CGITarget != null)
431: && (csid != null)) {
432: tg = new TaxonomyGetter(CGILocation, CGITarget + CGIRead,
433: csid);
434: tg.start();
435: } else {
436: ReportError.reportError(ReportError.ADMIN,
437: "TaxonomyTreeView", "obtainTaxonomy",
438: Messages.INSUFFICIENTTAXONOMYOBTAINPARAMS);
439: }
440: }
441:
442: /**
443: * Write the taxonomy to the server.
444: */
445: public String writeTaxonomy() {
446: return PostConnection.doWrite(CGILocation + CGITarget
447: + CGIWrite, taxonomy.toSOIF());
448: }
449:
450: // SGP: the whole synchronization problem is not solved
451: // well in here.
452:
453: public void newPeerBtnPress() {
454: setData();
455: ListItem li = getCurrentListItem();
456: if (li == null) {
457: return;
458: }
459:
460: String key = (String) ((BTreeNode) li.data()).getKey();
461: TaxonomyNode tn = (TaxonomyNode) ((BTreeNode) li.data())
462: .getValue();
463: boolean pRoot = (tn.getParentId() == null);
464: TaxonomyNode ntn = new TaxonomyNode((String) ((pRoot) ? key
465: : tn.getParentId() + ":" + key), tn.getParentId(),
466: taxonomy.getTaxonomyId(), "");
467:
468: newPeer(new BTreeNode(graphical.Messages.NEW, ntn));
469: getData();
470: }
471:
472: public void newChildBtnPress() {
473: setData();
474: ListItem li = getCurrentListItem();
475: if (li == null) {
476: return;
477: }
478: BTreeNode btn = (BTreeNode) li.data();
479:
480: String key = (String) btn.getKey();
481: TaxonomyNode tn = (TaxonomyNode) btn.getValue();
482: boolean pRoot = (tn.getParentId() == null);
483: TaxonomyNode ntn = new TaxonomyNode((String) ((pRoot) ? key
484: : tn.getId() + ":" + key), (String) ((pRoot) ? "ROOT"
485: : tn.getId()), taxonomy.getTaxonomyId(), "");
486:
487: newChild(new BTreeNode(graphical.Messages.NEW, ntn));
488: getData();
489: }
490:
491: public void delBtnPress() {
492: ListItem li = getCurrentListItem();
493: if (li == null) {
494: return;
495: }
496: BTreeNode btn = (BTreeNode) li.data();
497: BTreeNode pbtn = btn.getParent();
498:
499: if (pbtn == null) {
500: // whacking the top of the tree
501: setCurrentListItem(null);
502: taxonomy = new Taxonomy();
503: taxonomy.binaryTree.resetEnumeration();
504: if (taxonomy.binaryTree.hasMoreElements(true)) {
505: taxonomy.binaryTree.nextElement(true);
506: }
507: setBinaryTree(taxonomy.binaryTree);
508: listView.selectItemAt(0);
509: buttonEnablement();
510: setEditListItem();
511: if (te != null) {
512: te.taxonomy = taxonomy;
513: } // SGP
514: if (dt != null) {
515: dt.taxonomy = taxonomy;
516: } // SGP
517: if (getTreeViewGroup() != null) {
518: getTreeViewGroup().sendAction((TreeView) this ,
519: graphical.TreeViewGroup.CLEAR, null);
520: }
521: } else {
522: super .delBtnPress();
523: }
524:
525: getData();
526: }
527:
528: public void setDetailDisabled() {
529: description.setEditable(false);
530: description.setStringValue("");
531: description.setBackgroundColor(graphical.Header.INACTIVECOLOR);
532: if (pro) {
533: matchingRule.setEditable(false);
534: matchingRule.setStringValue("");
535: matchingRule
536: .setBackgroundColor(graphical.Header.INACTIVECOLOR);
537: }
538: }
539:
540: public void setDetailDirty() {
541: description.setDirty(true);
542: if (pro)
543: matchingRule.setDirty(true);
544:
545: }
546:
547: public void setData() {
548: ListItem li = getCurrentListItem();
549:
550: if (li != null) {
551: BTreeNode btn = (BTreeNode) li.data();
552: TaxonomyNode tn = (TaxonomyNode) btn.getValue();
553: taxonomy.synchId(btn, textField.stringValue());
554: tn.update("description", description.stringValue());
555: if (pro) {
556: tn.update("matching-rule", matchingRule.stringValue());
557: }
558:
559: }
560: }
561:
562: /**
563: * Set the detail data description TextField based on the description
564: * in the TaxonomyNode, if any.
565: */
566: public void getData() {
567: ListItem li = getCurrentListItem();
568:
569: if (li != null) {
570: Object o = li.data();
571: if (o instanceof BTreeNode) {
572: o = ((BTreeNode) o).getValue();
573: if (o instanceof TaxonomyNode) {
574: description.setEditable(true);
575: description
576: .setBackgroundColor(graphical.Header.ACTIVECOLOR);
577: description.setStringValue(((TaxonomyNode) o)
578: .getValue("description"));
579: if (pro) {
580: matchingRule.setEditable(true);
581: matchingRule
582: .setBackgroundColor(graphical.Header.ACTIVECOLOR);
583: matchingRule.setStringValue(((TaxonomyNode) o)
584: .getValue("matching-rule"));
585: }
586:
587: return;
588: }
589: }
590: }
591:
592: description.setStringValue("");
593: if (pro)
594: matchingRule.setStringValue("");
595: }
596:
597: public void textEditingDidEnd(TextField textfield,
598: int endCondition, boolean contentsChanged) {
599: super .textEditingDidEnd(textfield, endCondition,
600: contentsChanged);
601: setData();
602: }
603:
604: public void textWasModified(TextField textfield) {
605: super .textWasModified(textfield);
606: }
607:
608: // SGP: ooze from bottom of swamp.
609: /*
610: private void setChanged()
611: {
612: changed = true;
613: // if ( te != null ) { te.changed = true; } // SGP
614: // if ( dt != null ) { dt.changed = true; } // SGP
615: }
616:
617: public boolean getChanged()
618: {
619: return changed;
620: }
621:
622: public void clearChanged()
623: {
624: changed = false;
625: }
626: */
627:
628: public boolean clickCommand() {
629: if (editable()) {
630: setData();
631: super .clickCommand();
632: getData();
633: } else
634: // support TaxonomyBrowse
635: if (notifyOfSelect != null) {
636: ListItem prevli = getCurrentListItem();
637: // If super returns true, tree manipulated, don't reposition
638: // browser. If false, then a node was selected, go to it.
639: if (super .clickCommand() == true) {
640: return true;
641: }
642:
643: ListItem li = listView.selectedItem();
644: BTreeNode btn = (BTreeNode) li.data();
645: BTreeNode pbtn = btn.getParent();
646: TaxonomyNode tn = (TaxonomyNode) btn.getValue();
647:
648: String s1 = "";
649: if (prevli != null) {
650: s1 = (String) ((TaxonomyNode) ((BTreeNode) prevli
651: .data()).getValue()).getId();
652: }
653: String s2 = tn.getId();
654: if (s1.equals(s2)) {
655: // same place, don't request navigation
656: } else if (pbtn == null) {
657: notifyOfSelect
658: .performCommand("CLASSIFICATIONTOP", null);
659: } else {
660: notifyOfSelect.performCommand("CLASSIFICATIONSELECT",
661: (Object) tn.getId());
662: }
663: } else {
664: super .clickCommand();
665: }
666:
667: return false;
668: }
669:
670: public void performCommand(String command, Object arg) {
671: if (Messages.CMD_DROPPED.equals(command)) { // Nodes dropped?
672: ListItem li = (ListItem) arg; // Get dropped node
673:
674: if (li != null) {
675: BTreeNode btn = (BTreeNode) li.data();
676: TaxonomyNode tn = (TaxonomyNode) btn.getValue();
677: taxonomy.synchTree(btn); // Update taxonomy
678: }
679:
680: return;
681: }
682:
683: super.performCommand(command, arg);
684: }
685: }
|