public static Map<String, List<ProcessModelBean>> getProcessModelMap(final PageParameter pp) {
    final List<ProcessModelBean> models =
        DataQueryUtils.toList(
            wfpmService.getModelListByDomain(pp.getLDomainId(), EProcessModelStatus.deploy));
    wfpmService.sort(models);

    final Map<String, List<ProcessModelBean>> gmap =
        new LinkedHashMap<String, List<ProcessModelBean>>();
    for (final ProcessModelBean pm : models) {
      final String[] arr = StringUtils.split(pm.getModelText(), ".");
      final String key = arr.length > 1 ? arr[0] : CONST_OTHER;
      List<ProcessModelBean> list = gmap.get(key);
      if (list == null) {
        gmap.put(key, list = new ArrayList<ProcessModelBean>());
      }
      list.add(pm);
    }
    return gmap;
  }
  @Override
  protected String toCategoryHTML(final PageParameter pp) {
    final StringBuilder sb = new StringBuilder();
    final Map<String, Map<String, List<ProcessModelBean>>> gmap2 = getProcessModelMap2(pp);
    final ProcessModelBean cur = WorkflowUtils.getProcessModel(pp);
    final String[] pgroups = getPgroups(pp);
    if (cur != null || (pgroups != null && pgroups.length == 2)) {
      List<ProcessModelBean> l = null;
      String key = null;
      String pgroup = null;
      Map<String, List<ProcessModelBean>> m2 = null;
      if (cur != null) {
        final String[] arr = StringUtils.split(cur.getModelText(), ".");
        key = arr.length > 1 ? arr[0] : CONST_OTHER;
        m2 = gmap2.get(key);
        pgroup = wfpmService.getProcessDocument(cur).getProcessNode().getPgroup();
        if (!StringUtils.hasText(pgroup)) {
          pgroup = CONST_OTHER;
        }
      } else {
        key = pgroups[0];
        m2 = gmap2.get(key);
        pgroup = pgroups[1];
      }
      if (m2 != null) {
        l = m2.get(pgroup);
      }

      final CategoryItems items = CategoryItems.of();
      if (l != null) {
        for (final ProcessModelBean pm : l) {
          final _CategoryItem item =
              (_CategoryItem)
                  new _CategoryItem(pm)
                      .setHref(
                          uFactory.getUrl(pp, MyProcessWorksTPage.class, "modelId=" + pm.getId()));
          if (cur != null) {
            item.setSelected(cur.getId().equals(pm.getId()));
          }
          items.add(item);
        }
      }

      if (cur != null && (l == null || !l.contains(cur))) {
        items.add(
            new _CategoryItem(cur)
                .setHref(uFactory.getUrl(pp, MyProcessWorksTPage.class, "modelId=" + cur.getId()))
                .setSelected(true));
      }

      sb.append("<div class='gtitle'>");
      sb.append(
          new LinkElement($m("MyProcessWorksTPage.9"))
              .setHref(uFactory.getUrl(pp, getOriginalClass())));

      AbstractElement<?> ele;
      if (cur != null) {
        ele =
            new LinkElement(pgroup)
                .setHref(
                    uFactory.getUrl(
                        pp,
                        MyProcessWorksTPage.class,
                        "pgroup="
                            + HttpUtils.encodeUrl(Base64.encodeToString(key + ";" + pgroup))));
      } else {
        ele = new SpanElement(pgroup);
      }
      sb.append(SpanElement.NAV(3)).append(ele);
      sb.append("</div>");
      sb.append(items);
      return sb.toString();
    }

    sb.append("<div class='gtitle'>").append($m("MyProcessWorksTPage.16")).append("</div>");
    sb.append("<div class='gtree'>");
    for (final Map.Entry<String, Map<String, List<ProcessModelBean>>> e : gmap2.entrySet()) {
      final String key = e.getKey();
      sb.append("<div class='gitem");
      if (cur != null && cur.getModelText().startsWith(key)) {
        sb.append(" cur");
      }
      sb.append("'>");
      sb.append(new SpanElement(key).setClassName("glbl"));
      // final int size = gmap.get(key).size();
      // if (size > 0) {
      // sb.append(new SupElement("(" + size + ")").addClassName("gsize"));
      // }
      sb.append(" <div class='psub'>");
      int i = 0;
      for (final Map.Entry<String, List<ProcessModelBean>> e2 : e.getValue().entrySet()) {
        sb.append("<div class='pgroup'");
        if (i++ == 0) {
          sb.append(" style='border-top: 0'");
        }

        sb.append(">")
            .append(
                new SpanElement(e2.getKey())
                    .setOnclick(
                        JS.loc(
                            uFactory.getUrl(
                                pp,
                                MyProcessWorksTPage.class,
                                "pgroup="
                                    + HttpUtils.encodeUrl(
                                        Base64.encodeToString(key + ";" + e2.getKey()))))));
        for (final ProcessModelBean pm : e2.getValue()) {
          sb.append("<div class='pitem'>");
          sb.append(
              new LinkElement(WorkflowUtils.getShortMtext(pm))
                  .setOnclick(
                      JS.loc(
                          uFactory.getUrl(
                              pp, MyProcessWorksTPage.class, "modelId=" + pm.getId()))));
          sb.append("</div>");
        }
        sb.append("</div>");
      }
      sb.append(" </div>");
      sb.append("</div>");
    }
    sb.append("</div>");
    return sb.toString();
  }
  @Override
  public ElementList getRightElements(final PageParameter pp) {
    final ProcessModelBean pm = WorkflowUtils.getProcessModel(pp);
    String params = null;
    if (pm != null) {
      params = "modelId=" + pm.getId();
    } else {
      final String _gstr = pp.getParameter("pgroup");
      if (StringUtils.hasText(_gstr)) {
        params = "pgroup=" + HttpUtils.encodeUrl(_gstr);
      }
    }

    final TabButtons tabs =
        TabButtons.of(
            new TabButton(
                $m("MyProcessWorksTPage.4"),
                uFactory.getUrl(pp, MyProcessWorksTPage.class, params)));
    final IWorkflowWebContext ctx = (IWorkflowWebContext) workflowContext;
    if (pp.isLmember(ctx.getProcessWorks_DeptRole(pp))) {
      final String url = uFactory.getUrl(pp, MyProcessWorks_DeptTPage.class, params);
      final StringBuilder txt = new StringBuilder();
      PermissionDept dept = pp.getDept(ID.of(pp.getParameter("deptId")));
      if (!dept.exists()) {
        dept = pp.getLdept();
      }
      txt.append(dept);
      final List<PermissionDept> depts = pp.getLogin().depts();
      if (depts.size() > 1) {
        final MenuBean menu =
            (MenuBean)
                pp.addComponentBean("MyProcessWorksTPage_depts_menu", MenuBean.class)
                    .setMenuEvent(EMenuEvent.mouseenter)
                    .setSelector(".MyProcessWorksTPage .tool_bar img.depts-menu");
        final MenuItems items = menu.getMenuItems();
        for (final PermissionDept _dept : depts) {
          if (_dept.equals(dept)) {
            continue;
          }
          items.add(
              MenuItem.of(_dept.getText())
                  .setOnclick(
                      "$Actions.loc('"
                          + HttpUtils.addParameters(url, "deptId=" + _dept.getId())
                          + "');"));
        }
        txt.append(
            new ImageElement(
                    pp.getCssResourceHomePath(MyProcessWorksTPage.class) + "/images/down.png")
                .setClassName("depts-menu"));
      }
      tabs.append(new TabButton(txt, url));
    }
    if (pp.isLmember(ctx.getProcessWorks_OrgRole(pp))) {
      tabs.append(
          new TabButton(
              $m("MyProcessWorksTPage.5"),
              uFactory.getUrl(pp, MyProcessWorks_OrgTPage.class, params)));
    }
    return ElementList.of(createTabsElement(pp, tabs));
  }