private static synchronized Dimension getFontSize(Font f) {
    Dimension size = cFontSizes.get(f);
    if (size == null) {
      size = new Dimension(getFontAverageCharWidth(f), getFontHeight(f));
      cFontSizes.put(f, size);
    }

    return size;
  }
  // --------------------------------------------------------------------------------
  private void drawItem(String parentFieldName, TreeItem parentItem, List data, boolean expand) {
    for (int i = 0; i < data.size(); ++i) {
      TreeItem newItem = new TreeItem(parentItem, SWT.NONE);
      Object value = data.get(i);
      newItem.setText(1, getClassName(value));

      String fieldName = parentFieldName + "." + i;
      if (fieldName.startsWith(".")) {
        fieldName = fieldName.substring(1);
      }
      newItem.setData("fieldName", fieldName);
      newItem.setData("value", value);
      fieldNameTreeItemMap.put(fieldName, newItem);

      if (value instanceof Map) {
        newItem.setText("[" + i + "]");
        newItem.setImage(mapImage);
        drawItem(fieldName, newItem, (Map) value, expand);
      } else if (value instanceof List) {
        newItem.setText("[" + i + "]");
        newItem.setImage(listImage);
        drawItem(fieldName, newItem, (List) value, expand);
      } else {
        setItemInfo(newItem, "[" + i + "]", value);
      }

      if (expand) {
        parentItem.setExpanded(expand);
        newItem.setExpanded(expand);
      }
    }
  }
  // --------------------------------------------------------------------------------
  private void onEditField(final MEditFieldAction action) {
    MSystemUtil.sleep(100);

    final String fieldName = action.getFieldName();
    editingFieldName = fieldName;
    final TreeItem item = (TreeItem) fieldNameTreeItemMap.get(fieldName);
    if (item == null) {
      debug("item not found");
      // debug( fieldNameTreeItemMap );
      return;
    }
    // Object document = dataManager.getLastEditedDocument();

    final MDocumentEditor view = this;

    shell
        .getDisplay()
        .asyncExec(
            new Runnable() {
              public void run() { // *****

                if (action.getOriginView() != view) {
                  tree.select(item);
                }

                if (fieldName.equals("_id")) {
                  valueText.setEditable(false);
                  valueText.setEnabled(true);
                  typeCombo.setEnabled(false);
                  nameText.setText(fieldName);
                  editingData = item.getData("value");
                  valueText.setText(editingData + "");
                  typeCombo.select(
                      ((Integer) typeComboIndexMap.get(editingData.getClass())).intValue());
                  updateButton.setEnabled(false);
                } else {
                  valueText.setEditable(true);
                  valueText.setEnabled(true);
                  typeCombo.setEnabled(true);
                  nameText.setText(fieldName);
                  editingData = item.getData("value");
                  valueText.setText(editingData + "");
                  if (editingData == null) {
                    typeCombo.select(11);
                    verifyData();
                  } else {
                    typeCombo.select(
                        ((Integer) typeComboIndexMap.get(editingData.getClass())).intValue());
                    verifyData();
                  }
                }
              }
            }); // ********

    // valueText.setText( docum )
  }
  // --------------------------------------------------------------------------------
  private void drawItem(String parentFieldName, TreeItem parentItem, Map data, boolean expand) {
    Iterator p = data.keySet().iterator();
    while (p.hasNext()) {
      String key = (String) p.next();
      if (!data.containsKey(key)) {
        continue;
      }
      Object value = data.get(key);

      TreeItem newItem = new TreeItem(parentItem, SWT.NONE);
      newItem.setText(1, getClassName(value));

      String fieldName = parentFieldName + "." + key;
      if (fieldName.startsWith(".")) {
        fieldName = fieldName.substring(1);
      }
      newItem.setData("fieldName", fieldName);
      newItem.setData("value", value);
      fieldNameTreeItemMap.put(fieldName, newItem);

      if (value == null) {
        newItem.setText(key + " : null");
        newItem.setImage(nullImage);
      } else if (value instanceof Map) {
        newItem.setText(key);
        newItem.setImage(mapImage);
        drawItem(fieldName, newItem, (Map) value, expand);
      } else if (value instanceof List) {
        newItem.setText(key);
        newItem.setImage(listImage);
        drawItem(fieldName, newItem, (List) value, expand);
      } else {
        setItemInfo(newItem, key, value);
      }

      if (expand) {
        parentItem.setExpanded(expand);
        newItem.setExpanded(expand);
      }
    }
  }
  // --------------------------------------------------------------------------------
  private void drawTreeRoot(Tree _tree, DBObject data) {
    // reset tree
    _tree.removeAll();

    if (data != null) {
      TreeItem root = new TreeItem(_tree, SWT.NONE);
      root.setText(data.get("_id") + "");
      root.setImage(documentImage);
      root.setData("fieldName", "");
      root.setData("value", data.get("_id"));
      fieldNameTreeItemMap.put("", root);

      boolean expand = (data.keySet().size() < 35);
      drawItem("", root, data.toMap(), expand);
    }

    nameText.setText("");
    typeCombo.select(0);
    typeCombo.setEnabled(false);
    valueText.setText("");
    updateButton.setEnabled(false);
  }
  // --------------------------------------------------------------------------------
  public void init2() {
    parent.setLayout(new FormLayout());

    sashForm = new SashForm(parent, SWT.SMOOTH | SWT.VERTICAL);
    FormData fd_sashForm1 = new FormData();
    fd_sashForm1.top = new FormAttachment(0, 1);
    fd_sashForm1.left = new FormAttachment(0, 1);
    fd_sashForm1.right = new FormAttachment(100, -1);
    fd_sashForm1.bottom = new FormAttachment(100, -1);
    sashForm.setLayoutData(fd_sashForm1);

    tree = new Tree(sashForm, SWT.BORDER | SWT.FULL_SELECTION);
    tree.setHeaderVisible(true);

    FormData d1 = new FormData();
    d1.top = new FormAttachment(0, 1);
    d1.left = new FormAttachment(0, 1);
    d1.right = new FormAttachment(100, -1);
    d1.bottom = new FormAttachment(100, -1);
    tree.setLayoutData(d1);

    TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
    TreeColumn column2 = new TreeColumn(tree, SWT.LEFT);
    column2.setText("Data Type");

    editorComposite = new Composite(sashForm, SWT.BORDER);
    editorComposite.addControlListener(
        new ControlAdapter() {
          public void controlResized(ControlEvent e) {
            onSashResize();
          }
        });

    FormData fd_composite1 = new FormData();
    fd_composite1.top = new FormAttachment(0, 1);
    fd_composite1.bottom = new FormAttachment(0, 35);
    fd_composite1.right = new FormAttachment(100, -1);
    fd_composite1.left = new FormAttachment(0, 1);
    editorComposite.setLayoutData(fd_composite1);
    editorComposite.setLayout(new FormLayout());
    Label nameLabel = new Label(editorComposite, SWT.NONE);
    FormData fd_nameLabel = new FormData();
    fd_nameLabel.right = new FormAttachment(0, 66);
    fd_nameLabel.bottom = new FormAttachment(0, 32);
    fd_nameLabel.top = new FormAttachment(0, 12);
    fd_nameLabel.left = new FormAttachment(0, 10);
    nameLabel.setLayoutData(fd_nameLabel);
    nameLabel.setText("Name :");
    Label valueLabel = new Label(editorComposite, SWT.NONE);
    FormData fd_valueLabel = new FormData();
    fd_valueLabel.top = new FormAttachment(nameLabel, 15);
    fd_valueLabel.left = new FormAttachment(0, 10);
    fd_valueLabel.bottom = new FormAttachment(nameLabel, 34, SWT.BOTTOM);
    fd_valueLabel.right = new FormAttachment(nameLabel, 0, SWT.RIGHT);
    valueLabel.setLayoutData(fd_valueLabel);
    valueLabel.setText("Value :");

    valueText =
        new Text(
            editorComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
    valueText.addModifyListener(
        new ModifyListener() {
          public void modifyText(ModifyEvent e) {
            verifyData();
          }
        });
    valueText.setEnabled(false);
    valueText.setEditable(false);
    FormData fd_valueText = new FormData();
    fd_valueText.top = new FormAttachment(nameLabel, 5);
    fd_valueText.bottom = new FormAttachment(100, -80);
    fd_valueText.right = new FormAttachment(100, -20);
    fd_valueText.left = new FormAttachment(valueLabel, 0, SWT.RIGHT);
    valueText.setLayoutData(fd_valueText);

    updateButton = new Button(editorComposite, SWT.NONE);
    updateButton.addSelectionListener(
        new SelectionAdapter() {
          public void widgetSelected(SelectionEvent e) {
            onUpdateButtonSelect();
          }
        });
    updateButton.setEnabled(false);
    FormData fd_updateButton = new FormData();
    fd_updateButton.left = new FormAttachment(100, -120);
    fd_updateButton.right = new FormAttachment(valueText, 0, SWT.RIGHT);
    updateButton.setLayoutData(fd_updateButton);
    updateButton.setText("Update");

    typeCombo = new Combo(editorComposite, SWT.READ_ONLY);
    fd_updateButton.top = new FormAttachment(typeCombo, 10);
    typeCombo.setEnabled(false);
    FormData fd_typeList = new FormData();
    fd_typeList.left = new FormAttachment(valueText, 0, SWT.LEFT);
    fd_typeList.top = new FormAttachment(valueText, 5, SWT.BOTTOM);
    // fd_typeList.bottom = new FormAttachment(valueText, 30, SWT.BOTTOM);
    fd_typeList.right = new FormAttachment(valueText, 170, SWT.LEFT);
    typeCombo.setLayoutData(fd_typeList);

    typeCombo.add("Double");
    typeCombo.add("Integer");
    typeCombo.add("Long");
    typeCombo.add("String");
    typeCombo.add("List (BasicDBList)");
    typeCombo.add("Map (BasicDBObject)");
    typeCombo.add("Date");
    typeCombo.add("ObjectId");
    typeCombo.add("JavaScript code");
    typeCombo.add("Binary data");
    typeCombo.add("Boolean");
    typeCombo.add("Null");
    typeCombo.add("Regular expression");
    typeCombo.add("Symbol");
    typeCombo.add("JavaScript code with scope");
    typeCombo.add("Timestamp");
    typeCombo.add("Min key");
    typeCombo.add("Max key");

    typeCombo.addListener(SWT.Selection, this);

    typeComboIndexMap.put(Double.class, new Integer(0));
    typeComboIndexMap.put(Integer.class, new Integer(1));
    typeComboIndexMap.put(Long.class, new Integer(2));
    typeComboIndexMap.put(String.class, new Integer(3));
    typeComboIndexMap.put(com.mongodb.BasicDBList.class, new Integer(4));
    typeComboIndexMap.put(com.mongodb.BasicDBObject.class, new Integer(5));
    typeComboIndexMap.put(java.util.Date.class, new Integer(6));
    typeComboIndexMap.put(org.bson.types.ObjectId.class, new Integer(7));
    typeComboIndexMap.put(org.bson.types.Code.class, new Integer(8));
    typeComboIndexMap.put(byte[].class, new Integer(9));
    typeComboIndexMap.put(Boolean.class, new Integer(10));
    typeComboIndexMap.put(java.util.regex.Pattern.class, new Integer(12));
    typeComboIndexMap.put(org.bson.types.Symbol.class, new Integer(13));
    typeComboIndexMap.put(org.bson.types.CodeWScope.class, new Integer(14));
    typeComboIndexMap.put(org.bson.types.BSONTimestamp.class, new Integer(15));
    typeComboIndexMap.put(org.bson.types.MinKey.class, new Integer(16));
    typeComboIndexMap.put(org.bson.types.MaxKey.class, new Integer(17));

    Label typeLabel = new Label(editorComposite, SWT.NONE);
    FormData fd_typeLabel = new FormData();
    fd_typeLabel.top = new FormAttachment(typeCombo, 3, SWT.TOP);
    fd_typeLabel.left = new FormAttachment(nameLabel, 0, SWT.LEFT);
    typeLabel.setLayoutData(fd_typeLabel);
    typeLabel.setText("Type :");

    nameText = new Text(editorComposite, SWT.READ_ONLY);
    nameText.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND));
    FormData fd_nameText = new FormData();
    fd_nameText.top = new FormAttachment(nameLabel, -2, SWT.TOP);
    fd_nameText.left = new FormAttachment(valueText, 0, SWT.LEFT);
    fd_nameText.right = new FormAttachment(valueText, 0, SWT.RIGHT);
    nameText.setLayoutData(fd_nameText);

    MSwtUtil.getTreeColumnWidthFromProperties("documentTree", tree, prop, new int[] {150, 150});

    // listeners
    tree.addListener(SWT.MouseDoubleClick, this);
    tree.addListener(SWT.Selection, this);
    tree.addListener(SWT.KeyDown, this);
    MSwtUtil.addListenerToTreeColumns2(tree, this);

    documentImage = MUtil.getImage(parent.getShell().getDisplay(), "table.png");
    oidImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_star.png");
    intImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_blue.png");
    longImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_red.png");
    doubleImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_orange.png");
    stringImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_green.png");
    dateImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_white.png");
    boolImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_yellow.png");
    listImage = MUtil.getImage(parent.getShell().getDisplay(), "stop_blue.png");
    mapImage = MUtil.getImage(parent.getShell().getDisplay(), "stop_green.png");
    nullImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_black.png");
    jsImage = MUtil.getImage(parent.getShell().getDisplay(), "bullet_right.png");

    if (prop.containsKey(DOCUMENT_COMPOSITE_WEIGHT)) {

      (new Thread() {
            public void run() {
              // System.out.println( "e" );
              MSystemUtil.sleep(0);
              // System.out.println( "a" );
              shell
                  .getDisplay()
                  .asyncExec(
                      new Runnable() {
                        public void run() { // ----
                          // debug( "--" + prop.getIntArrayProperty( DOCUMENT_COMPOSITE_WEIGHT )[ 0
                          // ] );
                          sashForm.setWeights(prop.getIntArrayProperty(DOCUMENT_COMPOSITE_WEIGHT));
                        }
                      }); // ----
            }
          })
          .start();

    } else {
      sashForm.setWeights(new int[] {70, 30});
    }
    initializedTime = System.currentTimeMillis();
  }