Source code: org/gendiapo/editor/GenericGenDiapoEditPanel.java
1
2 package org.gendiapo.editor;
3
4
5 import javax.swing.*;
6 import javax.swing.text.*;
7 import javax.swing.border.*;
8
9 import java.awt.*;
10 import java.awt.event.*;
11
12 import java.util.*;
13 import java.util.Dictionary.*;
14
15 import matthew.awt.StrutLayout;
16 import java.text.MessageFormat;
17 import java.beans.*;
18
19 import org.merlotxml.merlot.*;
20 import org.merlotxml.merlot.plugin.*;
21 import org.merlotxml.merlot.plugin.dtd.*;
22 import org.merlotxml.util.xml.*;
23
24 import org.gendiapo.editor.*;
25
26 import org.w3c.dom.*;
27
28
29 /*
30 * Gestion des onglets pour un element de l'arbre XML
31 */
32 public class GenericGenDiapoEditPanel extends GenericDOMEditPanel implements GenDiapoEditPanel, MerlotNodeListener, Comparator
33
34 {
35 // id onglet par defaut
36 private static final String ID_DEF = "def";
37
38 // nom onglet par defaut
39 private static final String ONG_NAME = "Attributs";
40
41 // table de panel avec reference en cle
42 protected Hashtable _onglet;
43
44 // table contenant le dernier élément ajouté dans chaque onglet
45 protected Hashtable _last;
46
47 // table contenant boolean vrai si element a ajouter au panel est le premier
48 protected Hashtable _first;
49
50 // onglet contenant les attributs
51 protected JTabbedPane _attributs;
52
53 // Vecteur contenant les references des panels vides de l'onglet
54 protected Vector _disabledPanel;
55
56 // Indique si le noeud vient d'etre effacer
57 protected boolean _hasBeenDeleted;
58
59 /**
60 * Constructeur
61 */
62 public GenericGenDiapoEditPanel(MerlotDOMNode node)
63 {
64 super(node);
65 node.addMerlotNodeListener(this);
66 _hasBeenDeleted = false;
67 }
68
69 protected void buildPanel()
70 {
71 init();
72 setupReadonlyTable();
73 setupHideTable();
74
75 _vetoListeners = new Vector();
76
77 initPanelLayout();
78 setupPanel();
79 addVetoableChangeListener(new StandardAttributeChecker());
80 }
81
82
83 //
84 public void nodeInserted(MerlotDOMNode parent, int[] indices,
85 MerlotDOMNode[] children) {
86 }
87
88 public void nodeRemoved(MerlotDOMNode parent, int[] indices,
89 MerlotDOMNode[] children) {
90 }
91
92 public void nodeDeleted(MerlotDOMNode node) {
93 _hasBeenDeleted = true;
94 }
95
96
97 public void nodeChanged(MerlotDOMNode parent, int[] indices,
98 MerlotDOMNode[] children) {
99 }
100
101 //
102
103 /*
104 * Renvoie onglet contenant les attributs
105 */
106 public JTabbedPane getOngletAttributs(){
107 return _attributs;
108 }
109
110
111 /*
112 * Creation d'un panel pour l'onglet
113 * @param id : reference du panel dans table d'onglet
114 */
115 public JScrollPane createTab(String id)
116 {
117 // Un onglet
118 JPanel temp = new JPanel();
119 temp.setMinimumSize(new Dimension(4,4));
120
121 StrutLayout slay = new StrutLayout();
122 slay.setDefaultStrutLength(10);
123 temp.setLayout(slay);
124
125 JLabel iconLabel = new JLabel(_node.getIcon());
126
127 //Mise à jour _last avec dernier element ajoute pour panel de ref id
128 _last.put(id, iconLabel);
129
130 temp.add(iconLabel);
131
132 //aucun element ajoute au panel
133 _first.put(id, Boolean.TRUE);
134
135 //ajout Panel dans table onglet avec indice : string id
136 _onglet.put(id, temp);
137
138 // ajout reference panel dans _disabledPanel (panel vide par defaut)
139 _disabledPanel.addElement(id);
140
141 // wrap a ScrollPane around it
142 ScrollablePanel scrollPanel = new ScrollablePanel(true,false);
143 StrutLayout lay = new StrutLayout();
144 scrollPanel.setLayout(lay);
145 scrollPanel.add(temp);
146 lay.setSprings(temp, StrutLayout.SPRING_BOTH);
147 scrollPanel.setMinimumSize(new Dimension(4,4));
148 scrollPanel.setBorder(new EmptyBorder(0,0,0,5));
149
150 JScrollPane sp = new JScrollPane(scrollPanel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
151 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
152
153 sp.setMinimumSize(new Dimension(4,4));
154 sp.getViewport().setMinimumSize(new Dimension(4,4));
155
156 // met en propriete identifiant du srollpane identifiant id du panel
157 sp.putClientProperty("identifiant", id);
158
159 //return JScrollPane
160 return sp;
161
162 }
163
164
165 /*
166 * Initialisation des 3 tables : onglet, dernier element et premier element
167 */
168 protected void initTable()
169 {
170 // init _onglet et _last et _first
171 _onglet = new Hashtable();
172 _last = new Hashtable();
173 _first = new Hashtable();
174
175 // init _disabledPanel
176 _disabledPanel = new Vector();
177
178 }
179
180
181 /*
182 * Initialisation physique onglet associé a element de l'arbre
183 */
184 public JTabbedPane initOnglet()
185 {
186 //init onglet
187 JTabbedPane ong = new JTabbedPane();
188
189 //ajoute un onglet
190 ong.addTab(ONG_NAME,createTab(ID_DEF));
191
192 return ong;
193
194 }
195
196
197 /*
198 * Surcharge de la méthode d'initialisation du panel de gauche
199 */
200 protected void initPanelLayout()
201 {
202 // init du panel global
203 _attributePanel = new JPanel();
204 _attributePanel.setMinimumSize(new Dimension(4,4));
205
206 // layout _attributePanel
207 StrutLayout slay = new StrutLayout();
208 slay.setDefaultStrutLength(10);
209 _attributePanel.setLayout(slay);
210
211 // init tables
212 this.initTable();
213
214 // onglet
215 _attributs = initOnglet();
216 _attributePanel.add(_attributs);
217 slay.setSprings(_attributs, StrutLayout.SPRING_BOTH);
218
219
220 StrutLayout lay = new StrutLayout();
221 this.setLayout(lay);
222 this.add(_attributePanel);
223 lay.setSprings(_attributePanel, StrutLayout.SPRING_BOTH);
224
225
226 }
227
228 /*
229 * Surcharge methode
230 * Grise les panels de _attributs contenant aucun attribut
231 */
232 protected void setupPanel()
233 {
234 MerlotDebug.msg("SetupPanel");
235
236 JComponent prev = null;
237 boolean newsubtext = false;
238
239 DTDAttribute a;
240
241 // get all the attributes and create a set of text fields,
242 // and labels
243 Enumeration e = _node.getDTDAttributes();
244 if (e != null) {
245 // MerlotDebug.msg("Got attributes");
246
247 int i = 0;
248 TreeSet attributes = new TreeSet(this);
249
250 while (e.hasMoreElements()) {
251 a = (DTDAttribute)e.nextElement();
252 _dtd_attributes.put(a.getName(),a);
253 attributes.add(a);
254 i++;
255 }
256
257 i = 0;
258 Iterator it = attributes.iterator();
259 while (it.hasNext()) {
260 a = (DTDAttribute) it.next();
261 if (!suppressAttribute(a)) {
262 addAttribute(a);
263 i++;
264 }
265 // MerlotDebug.msg("Added "+c+" to panel");
266 }
267 }
268
269 // see if this node has a #text node possible under it
270 MerlotDOMNode[] children = _node.getChildNodes();
271 for (int i=0; i < children.length; i++) {
272 if (children[i] instanceof MerlotDOMText) {
273 MerlotDOMText textNode = (MerlotDOMText)children[i];
274 // System.out.println("child["+i+"] = "+children[i]+" nodeValue='"+textNode.getText()+"'");
275 if (textNode.isVisible()) {
276 _subtext = textNode;
277 break;
278 }
279 }
280 }
281 // see if #text is a posibility
282 if (_subtext == null) {
283 Enumeration en = _node.getAppendableElements();
284 DTDElement el;
285 String nm;
286
287 while (en != null && en.hasMoreElements()) {
288 el = (DTDElement)en.nextElement();
289 if (el != null) {
290 nm = el.getName();
291 if (nm != null && nm.equals(DTDConstants.PCDATA_KEY)) {
292 newsubtext = true;
293 break;
294 }
295 }
296 }
297 }
298
299 // grise tous les panels de _attributs qui ne contienne pas d'attributs
300 this.disabledPanel();
301
302 }
303
304 protected int compareAttribute(DTDAttribute a, DTDAttribute b) {
305 String aName = a.getName();
306 String bName = b.getName();
307 int aType = a.getDefaultType();
308 int bType = b.getDefaultType();
309 if (aType == bType) {
310 return aName.compareTo(bName);
311 } else {
312 return bType - aType;
313 }
314 }
315
316 public int compare(Object obj, Object obj1) {
317 return compareAttribute((DTDAttribute) obj, (DTDAttribute) obj1);
318 }
319
320 public boolean equals(Object obj) {
321 return this == obj;
322 }
323
324 /*
325 * Renvoie un onglet ou les panels qui ne contiennent pas d'elements sont grisés
326 */
327 protected void disabledPanel()
328 {
329 // faux car grise
330 Boolean grayed = Boolean.FALSE;
331
332 // recherche dans
333 for (int i = 0; i < _disabledPanel.size(); i++) {
334
335 // recuperation du scrollPane
336 // vrai si panel trouve dans onglet
337 Boolean find = Boolean.FALSE;
338 // index du panel dans l'onglet
339 int j = 0;
340
341 while ( (! find.booleanValue() ) & ( j < _attributs.getTabCount() ) ) {
342
343 JScrollPane scroll = (JScrollPane)_attributs.getComponentAt(j);
344
345 String ident = (String)scroll.getClientProperty("identifiant");
346
347 if ( ident.equals((String)_disabledPanel.get(i)) ) {
348 find = Boolean.TRUE;
349 _attributs.setEnabledAt(j,grayed.booleanValue());
350 } else {
351 j += 1;
352 }
353
354 } // end while
355
356
357 } // end for
358
359
360 }
361
362 /*
363 * Renvoie la reference de l'onglet pour un attribut donné
364 * ID_DEF : reference par defaut
365 */
366 public String getTab(DTDAttribute a)
367 {
368 return ID_DEF;
369 }
370
371
372 /*
373 * Surcharge addAttribute de GenericDOMEditPanel
374 * Faire intervenir le numero de l'onglet
375 */
376 protected void addAttribute(DTDAttribute a)
377 {
378 if (a != null) {
379 MerlotDOMEditor editor = _node.getEditor();
380 String label = a.getName();
381 if (editor instanceof GenDiapoEditor) {
382 label = ((GenDiapoEditor) editor).getUserName(_node, a);
383 }
384 if (!label.equals("")) {
385 label += ":";
386 }
387 JLabel l = new JLabel(label,JLabel.TRAILING);
388 if ((a.getDefaultType() == DTDAttribute.REQUIRED) && (!label.equals(""))) {
389 Icon reqIcon = getRequiredAttrIcon();
390 if (reqIcon != null) {
391 l.setIcon(reqIcon);
392 }
393 }
394
395 JComponent c = getEditComponent(a);
396
397 if (c == null) {
398 return;
399 }
400
401 _attrComponents.put(a.getName(),c);
402
403 String s = _node.getNodeName() + "." + a.getName();
404 String t = (String)_readonlyAttrs.get(s);
405 if (t != null) {
406 // System.out.println("disabling component: "+c);
407
408 if (c instanceof JTextComponent) {
409 ((JTextComponent)c).setEditable(false);
410 }
411 c.setEnabled(false);
412 }
413
414 addAttributeComponent(l,c,ALIGN_MIDDLE,getTab(a));
415
416 }
417
418 }
419
420
421 /*
422 * Controle de la descendence
423 * Renvoie tout appel de la fonction vers nouvelle fonction
424 */
425 protected void addAttributeComponent(JLabel l, JComponent c, int align) {
426 addAttributeComponent(l, c, align, ID_DEF);
427 }
428
429
430 /*
431 * Surcharge fonction GenericDOMEditPanel
432 * Ajout du param ref donnant la reference de l'onglet
433 */
434 protected void addAttributeComponent(JLabel l, JComponent c, int align, String ref)
435 {
436 addAttributeComponentTab(l,c,align,ref);
437 }
438
439
440 /*
441 * Insere le composant dans l'onglet donné par la référence
442 */
443 protected void addAttributeComponentTab(JLabel l, JComponent c, int align, String ref)
444 {
445 JPanel tabPanel = null;
446
447 // recuperation du panel ou le composant doit etre ajoute
448 tabPanel = (JPanel)_onglet.get(ref);
449
450 // verif panel non nul
451 if (tabPanel == null) {
452 return;
453 }
454
455 // recuperation dernier composant ajoute a ref
456 JComponent prec = (JComponent)_last.get(ref);
457 //verif non nul
458 if (prec == null) {
459 return;
460 }
461
462 // verification si element est le premier du panel ou non
463 boolean prem = ((Boolean)_first.get(ref)).booleanValue();
464
465 StrutLayout.StrutConstraint strut;
466 StrutLayout.StrutConstraint strut2;
467
468 // premier composant
469 if (prem) {
470
471 strut = new StrutLayout.StrutConstraint(prec,StrutLayout.MID_RIGHT,StrutLayout.MID_LEFT,
472 StrutLayout.SOUTH_EAST,20);
473
474 strut2 = new StrutLayout.StrutConstraint(l,StrutLayout.MID_RIGHT, StrutLayout.MID_LEFT,
475 StrutLayout.EAST);
476
477 tabPanel.add(l,strut);
478 tabPanel.add(c,strut2);
479
480 _first_field = c;
481
482 _first.put(ref, Boolean.FALSE);
483
484 } else {
485
486 strut2 = new StrutLayout.StrutConstraint(prec,StrutLayout.BOTTOM_LEFT,StrutLayout.TOP_LEFT,
487 StrutLayout.SOUTH);
488
489 switch (align) {
490 case ALIGN_TOP: // top
491 strut = new StrutLayout.StrutConstraint(c,StrutLayout.TOP_LEFT, StrutLayout.TOP_RIGHT,
492 StrutLayout.WEST);
493 break;
494 default:
495 case ALIGN_MIDDLE: // middle
496 strut = new StrutLayout.StrutConstraint(c,StrutLayout.MID_LEFT, StrutLayout.MID_RIGHT,
497 StrutLayout.WEST);
498 break;
499 case ALIGN_BOTTOM: // bot
500 strut = new StrutLayout.StrutConstraint(c,StrutLayout.BOTTOM_LEFT, StrutLayout.BOTTOM_RIGHT,
501 StrutLayout.WEST);
502 break;
503 }
504
505 tabPanel.add(c,strut2);
506 tabPanel.add(l,strut);
507
508 }
509
510 // JTextField
511 if (c instanceof JTextField) {
512 ((StrutLayout)tabPanel.getLayout()).setSprings(c,StrutLayout.SPRING_HORIZ);
513 }
514
515 // JScrollPane
516 //if (c instanceof JScrollPane) {
517 if (c instanceof JPanel) {
518 ((StrutLayout)tabPanel.getLayout()).setSprings(c,StrutLayout.SPRING_BOTH);
519 }
520
521 //JComboBox
522 if (c instanceof JComboBox) {
523 ((StrutLayout)tabPanel.getLayout()).setSprings(c,StrutLayout.SPRING_HORIZ);
524 }
525
526 //maj dernier composant ajoute
527 _last.put(ref,c);
528
529
530 // enleve le panel de reference ref de _disabledPanel
531 _disabledPanel.remove(ref);
532
533 }
534
535 /**
536 * Surcharge methode
537 * Vrai si attribut ne doit pas être affiché dans les onglets
538 */
539 protected boolean suppressAttribute(DTDAttribute a)
540 {
541
542 // verifie que attribut pas supprime dans methode pere
543 boolean suppr = super.suppressAttribute(a);
544
545 // s'il est présent d'après la méthode père, test s'il est dans vue stylee (si c'est le cas il est supprimé)
546 GenDiapoEditor edit = (GenDiapoEditor) _node.getEditor();
547 java.util.List attributesInStyledView = edit.attributesInStyledView(_node);
548 if ((! suppr) && (attributesInStyledView != null)) {
549 suppr = attributesInStyledView.contains(a.getName());
550 }
551
552 return suppr;
553
554 }
555
556
557
558 /**
559 * Create a component based on the attribute type, and get the default from
560 * the node, or if the node doesn't have it set, get the default value from
561 * the attribute definition itself
562 */
563 protected JComponent getEditComponent(DTDAttribute attr)
564 {
565 MerlotDebug.msg("getEditComponent("+attr+")");
566
567 int t = attr.getType();
568 JComponent ret = null;
569 String value = null;
570 Attr a = null;
571
572 if (_node_attributes != null) {
573 a = (Attr)_node_attributes.getNamedItem(attr.getName());
574 }
575
576 //System.out.println("a " + a + " : " + a.getValue());
577
578 if (a != null) {
579 value = a.getValue();
580 }
581
582 switch (t) {
583
584 case DTDConstants.NMTOKEN:
585
586 case DTDConstants.CDATA:
587 ret = new JTextField();
588 if (value != null) {
589 ((JTextField)ret).setText(value);
590 }
591 else {
592 value = attr.getDefaultValue();
593 if (value != null) {
594 ((JTextField)ret).setText(value);
595 }
596 }
597 break;
598
599 case DTDConstants.ID:
600 ret = getIdComponent(_node,attr.getName());
601 break;
602
603 case DTDConstants.IDREF:
604 ret = getIdRefComponent(_node,attr.getName());
605 break;
606
607 case DTDConstants.TOKEN_GROUP:
608 Enumeration e = attr.getTokens();
609
610 boolean checkbox = true;
611
612 if (e != null) {
613 Vector v = new Vector();
614 if (attr.getDefaultValue() == null) {
615 v.addElement("");
616 }
617 while (e.hasMoreElements()) {
618 MerlotDebug.msg("v = " + v + " e = " + e);
619 Object o = e.nextElement();
620 String s = o.toString();
621
622 checkbox = checkbox && (s.equals("true") || s.equals("false"));
623
624 v.addElement(new TokenValue(o, getUserName(attr, o)));
625 }
626
627 if (v.size() == 2 && checkbox) {
628 ret = new JCheckBox();
629 ((JCheckBox) ret).setSelected(value != null && value.equals("true"));
630 } else {
631 ret = new JComboBox(v);
632 ((JComboBox)ret).setEditable(false);
633 int i = getIndexInVector(v,value);
634
635 if (i < 0) {
636 i = getIndexInVector(v,attr.getDefaultValue());
637 }
638
639 if (i >= 0) {
640 ((JComboBox)ret).setSelectedIndex(i);
641 }
642 }
643
644 }
645 break;
646
647 case DTDConstants.IDREFS:
648 ret = getIdRefsComponent(_node,attr.getName());
649 break;
650
651 default:
652 JLabel l = new JLabel(MerlotResource.getString(ERR,"xml.attr.type.unknown"));
653 ret = l;
654 break;
655
656 }
657
658 return ret;
659 }
660
661 /*
662 * Returns a panel aimed at editing the IDREFS attribute from a DOM node
663 * targetNode : noeud sélectionné
664 * targetAttrName : Nom de l'attribut
665 */
666 protected JComponent getIdRefsComponent (MerlotDOMNode targetNode, String targetAttrName)
667 {
668
669 // recuperation tableau categories du document
670 CategoryObject[] tmp = getCategories(targetNode.getMerlotDOMDocument(), targetNode, targetAttrName);
671
672 // Panel contenant la liste des checkbox
673 JPanel panel = new JPanel();
674
675 // met en propriete de panel listeCateg
676 // but : recuperer identifiant categories pour la sauvegarde
677 panel.putClientProperty("listeCateg", tmp);
678
679
680 // valeur de l'attribut targetAttrName
681 String value = null;
682
683 // recuperation de la chaine associee à l'attribut targetAttrName
684 Attr targetAttr = (Attr)targetNode.getAttributes().getNamedItem(targetAttrName);
685 if (targetAttr != null) {
686 value = targetAttr.getValue();
687 }
688
689 if (value != null) {
690
691 String temp = "";
692
693 for (int i = 0; i < value.length(); i++) {
694
695 if ( value.charAt(i) == ' ') {
696
697 // recup objet CategoryObject qui a temp comme identifiant
698 CategoryObject cat = getCategObject(temp,tmp);
699
700 // met booleen a true si identifiant existe toujours
701 if ( cat != null ) {
702 cat._boolCategory = Boolean.TRUE;
703 }
704
705 temp = "";
706
707 }else {
708 //caractere differrent espace
709 temp += value.charAt(i);
710 }
711 }
712
713 // traitement dernier element
714 // recup objet CategoryObject qui a temp comme identifiant
715 CategoryObject cat = getCategObject(temp,tmp);
716
717 // met booleen a true si identifiant existe toujours
718 if ( cat != null ) {
719 cat._boolCategory = Boolean.TRUE;
720 }
721
722 }
723
724 // init GridLayout avec taille hashtable
725 GridLayout gridLayout = new GridLayout(tmp.length,1);
726 panel.setLayout(gridLayout);
727
728
729 // init checkbox avec nom des categories
730 for (int i = 0; i < tmp.length; i++) {
731
732 // creation checkbox avec nom categorie et coché si booléen vrai
733 JCheckBox c = new JCheckBox(tmp[i]._nameCategory, tmp[i]._boolCategory == Boolean.TRUE);
734
735 // maj proprietes du checkBox : tableau de booléen et son rang dans le tableau
736 c.putClientProperty("listeCateg", tmp);
737 c.putClientProperty("index", new Integer(i));
738
739 // met listener
740 CheckBoxListener myListener = new CheckBoxListener();
741 c.addItemListener(myListener);
742
743 // met le dernier CheckBox en propriete du panel
744 // But : recuperer le tableau de booleen pour sauvegarde
745 panel.putClientProperty("comp", c);
746
747 // ajoute au panel
748 panel.add(c);
749
750
751 } // end for
752
753 return panel;
754
755 }
756
757
758 /**
759 * Recherche categories
760 * @param doc noeud de depart
761 * @param targetNode
762 * @param targetAttrName attribut pour lequel on recherche les choix d'id
763 */
764 protected CategoryObject[] getCategories(MerlotDOMDocument doc, MerlotDOMNode targetNode, String targetAttrName)
765 {
766 Vector choices = new Vector();
767 Hashtable idAttrs = getIdManager().getIDAttrs(targetNode, targetAttrName);
768 if (idAttrs != null) {
769 Enumeration e = idAttrs.keys();
770 int i = 0;
771 while (e.hasMoreElements()) {
772 Attr attr = (Attr)e.nextElement();
773 MerlotDOMNode node = (MerlotDOMNode)idAttrs.get(attr);
774 String id = getIdForNode( node );
775 if (IdAttributesAreCompatible(targetNode, targetAttrName, node, attr.getName())) {
776 CategoryObject idObject = new CategoryObject(id,
777 getDisplayTextForAttribute(targetNode,
778 targetAttrName,
779 node,
780 attr.getName()));
781 choices.add(idObject);
782 }
783 }
784 }
785 return (CategoryObject[]) choices.toArray(new CategoryObject[choices.size()]);
786 }
787
788
789 /*
790 * renvoie l'index de la categorie
791 * id : identifiant de la catgeorie
792 * tab : tablo d'objet CategoryObject
793 */
794 protected CategoryObject getCategObject(String id , CategoryObject[] tab)
795 {
796 CategoryObject obj = null;
797 int i = 0;
798 Boolean trouve = Boolean.FALSE;
799
800 // non trouve et non fin de tableau
801 while ( !(trouve.booleanValue()) & (i < tab.length) ) {
802
803 CategoryObject cat = tab[i];
804 // test nom de catgeorie
805 if (cat._idCategory.equals(id)) {
806 obj = cat;
807 trouve = Boolean.TRUE;
808 } else {
809 i += 1;
810 }
811
812 }
813
814 if (trouve.booleanValue()) {
815 return obj;
816 } else {
817 return null;
818 }
819
820 }
821
822
823 /**
824 * Surcharge methode pour cas des categories
825 */
826 protected void save(HashMap attributes)
827 throws PropertyVetoException
828 {
829 if (_hasBeenDeleted) {
830 return;
831 }
832
833 if (_text != null) {
834 if (_text.getText().trim().equals("")) {
835 if (_subtext != null) {
836 // it's empty and they didn't create it or edit it
837 // manually... remove it
838 _node.removeChild(_subtext);
839 }
840 } else {
841 if (_subtext == null) {
842 // create a new TextNode
843 MerlotDOMNode nd = _node.newChild(DTDConstants.PCDATA_KEY);
844 if (nd instanceof MerlotDOMText) {
845 _subtext = (MerlotDOMText)nd;
846 }
847 }
848 if (_subtext != null) {
849 _subtext.setText(_text.getText());
850 }
851 }
852 }
853
854 // put together a hashtable of attributes to pass back to the node
855 Enumeration e = _attrComponents.keys();
856 while (e.hasMoreElements()) {
857 String key = (String)e.nextElement();
858 DTDAttribute dtdAttr = (DTDAttribute)_dtd_attributes.get(key);
859 Node oldnode = _node_attributes.getNamedItem(key);
860 String oldval;
861 if (oldnode != null) {
862 oldval = oldnode.getNodeValue();
863 } else {
864 oldval = "";
865 }
866 JComponent c = (JComponent)_attrComponents.get(key);
867
868 String newval = null;
869 if (c instanceof JTextField) {
870
871 newval = ((JTextField)c).getText();
872
873 } else if (c instanceof JComboBox) {
874
875 Object item = ((JComboBox)c).getSelectedItem();
876 if (item != null) {
877 if (item instanceof TokenValue) {
878 newval = ((TokenValue)item).getObject().toString().trim();
879 } else {
880 newval = item.toString().trim();
881 }
882 }
883
884 } else if (c instanceof JCheckBox) {
885 newval = ((JCheckBox) c).isSelected() ? "true" : "false";
886
887 } else if ((c instanceof JPanel) && (c.getClientProperty("comp") instanceof JCheckBox)) {
888
889 // recup checkbox et liste categories
890 JCheckBox box = (JCheckBox)c.getClientProperty("comp");
891
892 // au moins un checkbox
893 CategoryObject[] liste = (CategoryObject[])box.getClientProperty("listeCateg");
894
895 // recherche les categories sauvees
896 for (int i = 0; i < liste.length; i++) {
897
898 if ( liste[i]._boolCategory.toString().equals("true") ) {
899 if ( newval == null ) {
900 newval = ""; // init newval
901 } else {
902 newval = newval + " "; // categs separes par " "
903 }
904 newval = newval + liste[i]._idCategory; // ajoute categ
905 }
906 }
907
908 } else {
909 // nothing to do now
910 MerlotDebug.msg("Unknown editing component in GenericDOMEditPanel.save: "+c);
911 if (attributes.containsKey(key)) {
912 newval = (String)attributes.get(key);
913 }
914 }
915
916 if (newval != null && newval.trim().equals("")) {
917 newval = null;
918 }
919
920 if (newval == null && dtdAttr != null && dtdAttr.getDefaultType() == DTDAttribute.REQUIRED) {
921 String err[] = new String[2];
922 err[0] = _node.getNodeName();
923 err[1] = key;
924 throw new PropertyVetoException(MessageFormat.format(MerlotResource.getString(ERR,"required.field"),err),new PropertyChangeEvent(_node,key,oldval,newval));
925 }
926
927 fireVetoableChange(new PropertyChangeEvent(_node,key,oldval,newval));
928
929 // check if the attribute is already set in the hashtable
930 if (!attributes.containsKey(key)) {
931 attributes.put(key,newval);
932 }
933
934 }
935 _node.setAttributes(attributes);
936 _node.removeMerlotNodeListener(this);
937 }
938
939
940 /*
941 * Listens to the check boxes
942 */
943 class CheckBoxListener implements ItemListener {
944
945 public void itemStateChanged(ItemEvent e) {
946
947 // recuperation checkbox selectionne
948 Object source = e.getItemSelectable();
949 JCheckBox c = (JCheckBox)source;
950
951 // init liste categories et index
952 CategoryObject[] liste = null;
953 java.lang.Integer ind = new Integer(-1);
954
955 // recupere liste categories et index associe au checkbox
956 liste = (CategoryObject[])c.getClientProperty("listeCateg");
957 ind = (java.lang.Integer)c.getClientProperty("index");
958
959 // si selectionne, true dans vecteur sinon false
960 if (c.isSelected() ) {
961 liste[ind.intValue()]._boolCategory = Boolean.TRUE;
962 } else {
963 liste[ind.intValue()]._boolCategory = Boolean.FALSE;
964 }
965
966 // maj vecteur associe au CheckBox et scrollPane
967 c.putClientProperty("listeCateg", liste);
968
969 }
970 }
971
972
973 /**
974 * Checks attributes according to their type. E.g. NMTOKEN is only of the characters specified
975 * by the XML spec
976 */
977 protected class StandardAttributeChecker implements VetoableChangeListener
978 {
979 public void vetoableChange(PropertyChangeEvent evt)
980 throws PropertyVetoException
981 {
982
983 Object n = evt.getSource();
984 if (!(n instanceof MerlotDOMNode)) {
985 return;
986 }
987 MerlotDOMNode node = (MerlotDOMNode)n;
988
989 String attributeName = evt.getPropertyName();
990 Object o = evt.getNewValue();
991 String value = "";
992 if (o instanceof String) {
993 value = ((String)o).trim();
994 }
995
996
997 // [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender
998 // [5] Name ::= (Letter | '_' | ':') (NameChar)*
999 // [6] Names ::= Name (S Name)*
1000// [7] Nmtoken ::= (NameChar)+
1001// [8] Nmtokens ::= Nmtoken (S Nmtoken)*
1002
1003
1004
1005 DTDAttribute attribute = (DTDAttribute)_dtd_attributes.get(attributeName);
1006 if (attribute != null) {
1007 int t = attribute.getType();
1008 char invalid = 0;
1009 switch (t) {
1010 case DTDConstants.NMTOKEN:
1011 // inspect the value and make sure it conforms to the restrictions on NMTOKEN's
1012 /*
1013 if (value.length() == 0) {
1014 throw new PropertyVetoException("NMTOKEN's require a value",evt);
1015 }
1016 */
1017 if (value.length() != 0) {
1018 invalid = checkNmtokenChars(value);
1019 }
1020 break;
1021
1022 case DTDConstants.CDATA:
1023 break;
1024
1025 case DTDConstants.ID:
1026 break;
1027 case DTDConstants.IDREF:
1028 break;
1029 case DTDConstants.TOKEN_GROUP:
1030 break;
1031
1032 }
1033 if (invalid != 0) {
1034 String[] err = new String[3];
1035 err[0] = node.getNodeName();
1036 err[1] = attribute.getName();
1037 err[2] = "'" + invalid + "'";
1038
1039 throw new PropertyVetoException(MessageFormat.format(MerlotResource.getString(ERR,"illegal.value.attr.char"),err),evt);
1040
1041 }
1042
1043 }
1044 }
1045
1046 }
1047
1048
1049 protected String getUserName(DTDAttribute attr, Object o) {
1050 String value = o.toString();
1051 DTDPluginConfig dpc = _node.getDTDPluginConfig();
1052 if (dpc instanceof GD_DTDPluginConfig) {
1053 value = ((GD_DTDPluginConfig) dpc).getValueName(_node.getNodeName(), attr.getName(), o.toString());
1054 }
1055 return value;
1056 }
1057
1058 protected class TokenValue {
1059 Object obj;
1060 String userValue;
1061
1062 public TokenValue(Object o, String userValue) {
1063 this.obj = o;
1064 this.userValue = userValue;
1065 }
1066
1067 public Object getObject() {
1068 return obj;
1069 }
1070
1071 public String toString() {
1072 return userValue;
1073 }
1074
1075 public boolean equals(Object o) {
1076 return o.equals(obj);
1077 }
1078 }
1079
1080}