Josef Rokos 9 years ago
commit 5079d6d55a

@ -1,17 +1,15 @@
package info.bukova.isspst;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.apache.commons.lang.time.DateUtils;
public class DateTimeUtils
{
public static Date getDate(Date value)
{
if (value == null)
{
public class DateTimeUtils {
public static Date getDate(Date value) {
if (value == null) {
return value;
}
@ -19,10 +17,18 @@ public class DateTimeUtils
return DateUtils.truncate(value, Calendar.DAY_OF_MONTH);
}
public static boolean isEqualByDate(Date d1, Date d2)
{
if (d1 != null && d2 != null)
{
public static int getYear(Date value) {
if (value == null) {
return 0;
}
Calendar cal =Calendar.getInstance();
cal.setTime(value);
return cal.get(Calendar.YEAR);
}
public static boolean isEqualByDate(Date d1, Date d2) {
if (d1 != null && d2 != null) {
d1 = DateTimeUtils.getDate(d1);
d2 = DateTimeUtils.getDate(d2);
boolean equals = (d1.compareTo(d2) == 0);
@ -32,27 +38,71 @@ public class DateTimeUtils
return false;
}
public static boolean isEqualByDateForFilter(Date value, Date search)
{
if (search == null)
{
return true;
public static boolean isEqualByYear(Date d1, Date d2) {
if (d1 != null && d2 != null) {
int year1 = DateTimeUtils.getYear(d1);
int year2 = DateTimeUtils.getYear(d2);
boolean equals = (year1 == year2);
return equals;
}
else if (value != null)
{
return false;
}
public static boolean isEqualByDateForFilter(Date value, Date search) {
if (search == null) {
return true;
} else if (value != null) {
return DateTimeUtils.isEqualByDate(value, search);
}
return false;
}
public static Date getCurrDateTime()
{
public static String getFormatedDate(Date value) {
if (value == null) {
return "";
}
SimpleDateFormat sdf = new SimpleDateFormat(StringUtils.localize("DateFormat"));
String result = sdf.format(value);
return result;
}
public static String getFormatedDirDate(Date value) {
if (value == null) {
return "";
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String result = sdf.format(value);
return result;
}
public static String getFormatedDirDateDDMM(Date value) {
if (value == null) {
return "";
}
SimpleDateFormat sdf = new SimpleDateFormat("MMdd");
String result = sdf.format(value);
return result;
}
public static String getFormatedYear(Date value) {
if (value == null) {
return "";
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
String result = sdf.format(value);
return result;
}
public static Date getCurrDateTime() {
return new Date();
}
public static Date getCurrDate()
{
public static Date getCurrDate() {
return DateTimeUtils.getDate(DateTimeUtils.getCurrDateTime());
}

@ -7,11 +7,7 @@ import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.search.annotations.IndexedEmbedded;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -20,6 +16,9 @@ import java.util.List;
@Table(name = "SIGNED_DOCUMENTS")
public class SignedDocument extends BaseData {
@Transient
private String agendaName;
@Column(name = "MODULE_NAME", length = Constants.LEN_TEXT)
private String moduleName;
@ -40,6 +39,9 @@ public class SignedDocument extends BaseData {
@IndexedEmbedded
private List<SignedDocumentItem> items;
public SignedDocument() {
}
public String getModuleName() {
return moduleName;
}
@ -81,6 +83,9 @@ public class SignedDocument extends BaseData {
}
public String getAgendaName() {
if (!StringUtils.isNullOrEmpty(this.agendaName)) {
return this.agendaName;
}
if (StringUtils.isNullOrEmpty(this.moduleName)) {
return "";
@ -95,6 +100,10 @@ public class SignedDocument extends BaseData {
return "";
}
public void setAgendaName(String agendaName) {
this.agendaName = agendaName;
}
public List<SignedDocumentItem> getItems() {
return items;
}

@ -1,9 +1,13 @@
package info.bukova.isspst.services.signeddocs;
import info.bukova.isspst.data.DataModel;
import info.bukova.isspst.data.Member;
import info.bukova.isspst.data.SignedDocument;
import info.bukova.isspst.data.SignedDocumentItem;
import info.bukova.isspst.services.Service;
import info.bukova.isspst.ui.signeddocs.SignedDocsTreeNode;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.TreeNode;
import java.util.List;
@ -17,4 +21,5 @@ public interface SignedDocumentService extends Service<SignedDocument> {
public List<SignedDocument> getActualList();
public List<SignedDocument> getArchiveList();
public TreeModel<TreeNode<SignedDocumentItem>> getTree();
}

@ -4,23 +4,27 @@ import info.bukova.isspst.DateTimeUtils;
import info.bukova.isspst.Module;
import info.bukova.isspst.ModuleUtils;
import info.bukova.isspst.data.DataModel;
import info.bukova.isspst.data.Member;
import info.bukova.isspst.data.SignedDocument;
import info.bukova.isspst.data.SignedDocumentItem;
import info.bukova.isspst.services.AbstractOwnedService;
import info.bukova.isspst.services.LazyLoader;
import info.bukova.isspst.storage.ReportFileStorage;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.*;
import javax.servlet.ServletContext;
import info.bukova.isspst.ui.signeddocs.SignedDocsTreeNode;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.zul.DefaultTreeModel;
import org.zkoss.zul.DefaultTreeNode;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.TreeNode;
public class SignedDocumentServiceImpl extends AbstractOwnedService<SignedDocument> implements SignedDocumentService {
@ -103,7 +107,7 @@ public class SignedDocumentServiceImpl extends AbstractOwnedService<SignedDocume
}
private Date getTresholdDate() {
Date date = DateTimeUtils.getDateDelta(DateTimeUtils.getCurrDate(), Calendar.YEAR, -1);
Date date = DateTimeUtils.getDateDelta(DateTimeUtils.getCurrDate(), Calendar.MONTH, -6);
return date;
}
@ -126,4 +130,113 @@ public class SignedDocumentServiceImpl extends AbstractOwnedService<SignedDocume
q.setParameter("refDate", this.getTresholdDate());
return q.list();
}
@SuppressWarnings("unchecked")
@Override
@Transactional
@PreAuthorize("hasPermission(this, 'PERM_READ')")
public TreeModel<TreeNode<SignedDocumentItem>> getTree() {
Query q = queryDao.getQuery("select item "
+ "from SignedDocumentItem as item left join item.signedDocument as rec "
+ "order by rec.moduleName, rec.signDate desc, item.reportName, item.fileName "
);
List<SignedDocumentItem> list = q.list();
SignedDocumentItem lastItem = null;
SignedDocument lastRec = null;
List<SignedDocsTreeNode> agendaNameList = new LinkedList<SignedDocsTreeNode>();
List<SignedDocsTreeNode> signYearList = new LinkedList<SignedDocsTreeNode>();
List<SignedDocsTreeNode> signDateList = new LinkedList<SignedDocsTreeNode>();
List<SignedDocsTreeNode> filesList = null;
int documentsCount = list.size() - 1;
for (int i = 0; i <= documentsCount; i++) {
SignedDocumentItem item = list.get(i);
SignedDocument rec = item.getSignedDocument();
SignedDocsTreeNode itemNode = new SignedDocsTreeNode(item);
boolean isChangedAgendaName = ((i == 0)
|| (i == documentsCount)
|| !lastRec.getAgendaName().equals(rec.getAgendaName())
);
boolean isChangedSignYear = ((i == 0)
|| (i == documentsCount)
|| isChangedAgendaName
|| !DateTimeUtils.isEqualByYear(lastRec.getSignDate(), rec.getSignDate())
);
boolean isChangedSignDate = ((i == 0)
|| (i == documentsCount)
|| isChangedSignYear
|| !DateTimeUtils.isEqualByDate(lastRec.getSignDate(), rec.getSignDate())
);
if (isChangedAgendaName || isChangedSignYear || isChangedSignDate) {
if (isChangedSignDate) {
if (i > 0) {
SignedDocsTreeNode signDateNode = new SignedDocsTreeNode((i == documentsCount ? item : lastItem), filesList);
signDateList.add(signDateNode);
}
filesList = new LinkedList<SignedDocsTreeNode>();
filesList.add(itemNode);
}
if (isChangedSignYear) {
if (i > 0) {
SignedDocsTreeNode signYearNode = new SignedDocsTreeNode((i == documentsCount ? item : lastItem), signDateList);
signYearList.add(signYearNode);
}
signDateList = new LinkedList<SignedDocsTreeNode>();
}
if (isChangedAgendaName) {
if (i > 0) {
SignedDocsTreeNode agendaNode = new SignedDocsTreeNode((i == documentsCount ? item : lastItem), signYearList);
agendaNameList.add(agendaNode);
}
signYearList = new LinkedList<SignedDocsTreeNode>();
}
} else {
filesList.add(itemNode);
}
lastItem = item;
lastRec = lastItem.getSignedDocument();
}
Collections.sort(agendaNameList, new Comparator<SignedDocsTreeNode>() {
@Override
public int compare(SignedDocsTreeNode nodeL, SignedDocsTreeNode nodeR) {
if ((nodeL != null) && (nodeR != null)) {
SignedDocumentItem itemL = nodeL.getData();
SignedDocumentItem itemR = nodeR.getData();
if ((itemL != null) && (itemR != null)) {
SignedDocument recL = itemL.getSignedDocument();
SignedDocument recR = itemR.getSignedDocument();
if ((recL != null) && (recR != null)) {
String nameL = recL.getAgendaName();
String nameR = recR.getAgendaName();
if ((nameL != null) && (nameR != null)) {
return nameL.compareTo(nameR);
}
}
}
}
return 0;
}
}
);
SignedDocsTreeNode root = new SignedDocsTreeNode(null, agendaNameList);
TreeModel<TreeNode<SignedDocumentItem>> tree = new DefaultTreeModel<SignedDocumentItem>(root);
return tree;
}
}

@ -44,6 +44,11 @@ public class DocumentFileStorageImpl extends AbstractFileStorage<FileMetainfo> i
this.rootPath = rootPath;
}
@Override
public String getRootPath() {
return this.rootPath;
}
@Override
public void saveFile(byte[] data, FileMetainfo fileID) {
String fileName = generateFileName(fileID.getFileName());

@ -9,7 +9,7 @@ import java.io.File;
*/
public interface FileStorage<T> {
// public String getRootPath();
public String getRootPath();
public void saveFile(byte[] data, T fileID);
public void saveFile(File file, T fileId);
public void removeFile(T fileID);

@ -12,6 +12,11 @@ public class LocalFileStorage extends AbstractFileStorage<String> {
this.rootPath = rootPath;
}
@Override
public String getRootPath() {
return this.rootPath;
}
public void setContext(ServletContext ctx) {
this.context = ctx;
}

@ -16,6 +16,11 @@ public class ReportFileStorageImpl extends AbstractFileStorage<SignedDocumentIte
this.rootPath = rootPath;
}
@Override
public String getRootPath() {
return this.rootPath;
}
private String getFilePath(String fileName) {
return rootPath + "/" + fileName;
}

@ -0,0 +1,186 @@
package info.bukova.isspst.ui.signeddocs;
import info.bukova.isspst.DateTimeUtils;
import info.bukova.isspst.data.SignedDocument;
import info.bukova.isspst.data.SignedDocumentItem;
import info.bukova.isspst.storage.ReportFileStorage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.DefaultTreeModel;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.TreeNode;
import java.io.*;
import java.text.Normalizer;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class SignedDocsTreeList extends SignedDocsList {
@SuppressWarnings("unused")
private final static Logger log = LoggerFactory.getLogger(SignedDocsTreeList.class.getName());
@WireVariable
private ReportFileStorage signedDocStorage;
public SignedDocsTreeNode getSelectedNodeItem() {
return selectedNodeItem;
}
public void setSelectedNodeItem(SignedDocsTreeNode selectedNodeItem) {
this.selectedNodeItem = selectedNodeItem;
}
private SignedDocsTreeNode selectedNodeItem;
public SignedDocsTreeList() {
}
@Init(superclass = true)
public void signedDocsTreeListInit() {
}
public TreeModel<TreeNode<SignedDocumentItem>> getTreeBackup() {
try {
return signedDocumentService.getTree();
} catch (AccessDeniedException e) {
// BindUtils.postGlobalCommand(null, null, "disableCentre", null);
// e.printStackTrace();
return new DefaultTreeModel<SignedDocumentItem>(null);
}
}
public static void addToZipFile(String filePath, String zipPath, ZipOutputStream zos) throws FileNotFoundException, IOException {
//System.out.println("Writing '" + filePath + "' to zip file");
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
ZipEntry zipEntry = new ZipEntry(zipPath);
zos.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zos.write(bytes, 0, length);
}
zos.closeEntry();
fis.close();
}
public static String getNormalizedPath(String path) {
String result = path.replaceAll("[ ]", "_");
result = Normalizer.normalize(result, Normalizer.Form.NFD);
result = result.replaceAll("[^-a-zA-Z0-9_./]", "");
return result;
}
public static String getCheckedString(String str, int maxLength) {
String result = "";
if (str != null) {
int len = str.length();
if (len > 0) {
result = str.substring(0, len > maxLength ? maxLength - 1 : len);
result += "-";
}
}
return result;
}
public static String getCheckedString(String str) {
return SignedDocsTreeList.getCheckedString(str, 50);
}
@Command
public void onCreateZipArchive() {
if (this.selectedNodeItem == null) {
return;
}
List<SignedDocsTreeNode> leafs = this.selectedNodeItem.getLeafs();
if (leafs.size() > 0) {
int deep = this.selectedNodeItem.getDeep();
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
for (SignedDocsTreeNode node : leafs) {
SignedDocumentItem item = node.getData();
String pdfFileName = item.getFileName();
SignedDocument doc = item.getSignedDocument();
String zipDirs = "";
String zipFileName = "";
if (deep == 3 || deep == 4) {
zipFileName += SignedDocsTreeList.getCheckedString(DateTimeUtils.getFormatedDirDate(doc.getSignDate()));
}
zipFileName += SignedDocsTreeList.getCheckedString(item.getReportName());
zipFileName += SignedDocsTreeList.getCheckedString(doc.getNumser());
zipFileName += SignedDocsTreeList.getCheckedString(doc.getDescription());
zipFileName += SignedDocsTreeList.getCheckedString(pdfFileName);
if (deep == 1 || deep == 2 || deep == 3) {
zipDirs += doc.getAgendaName();
zipDirs += "/";
}
if (deep == 1) {
zipDirs += DateTimeUtils.getFormatedYear(doc.getSignDate());
zipDirs += "/";
}
if (deep == 1) {
zipDirs += DateTimeUtils.getFormatedDirDateDDMM(doc.getSignDate());
zipDirs += "/";
}
if (deep == 2) {
zipDirs += DateTimeUtils.getFormatedDirDate(doc.getSignDate());
zipDirs += "/";
}
String rootPath = signedDocStorage.getRootPath();
String diskPath = rootPath + "/" + pdfFileName;
String zipPath = zipDirs + zipFileName;
zipPath = SignedDocsTreeList.getNormalizedPath(zipPath);
if (new File(diskPath).isFile()) {
SignedDocsTreeList.addToZipFile(diskPath, zipPath, zos);
} else {
log.warn("Missing file '" + diskPath + "' !!!");
log.warn(doc.getAgendaName());
log.warn(doc.getDescription());
log.warn(item.getReportName());
}
}
zos.close();
bos.close();
Filedownload.save(bos.toByteArray(), "application/zip", "temp" + Long.toString(System.nanoTime()) + ".zip");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

@ -0,0 +1,79 @@
package info.bukova.isspst.ui.signeddocs;
import info.bukova.isspst.data.SignedDocumentItem;
import org.zkoss.zul.DefaultTreeNode;
import org.zkoss.zul.TreeNode;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class SignedDocsTreeNode extends DefaultTreeNode<SignedDocumentItem> {
public SignedDocsTreeNode(SignedDocumentItem data) {
super(data);
}
public SignedDocsTreeNode(SignedDocumentItem data, Collection<? extends TreeNode<SignedDocumentItem>> children) {
super(data, children);
}
public SignedDocsTreeNode getParentNode() {
return (SignedDocsTreeNode) this.getParent();
}
public int getDeep() {
int iDeep = 0;
SignedDocsTreeNode node = this.getParentNode();
while (node != null) {
node = node.getParentNode();
iDeep++;
}
return iDeep;
}
public List<SignedDocsTreeNode> getLeafs() {
List<SignedDocsTreeNode> list = new LinkedList<SignedDocsTreeNode>();
if (!this.isLeaf()) {
List<TreeNode<SignedDocumentItem>> children = this.getChildren();
for (TreeNode<SignedDocumentItem> item : children) {
SignedDocsTreeNode node = (SignedDocsTreeNode) item;
if (node != null) {
if (node.isLeaf()) {
list.add(node);
} else {
list.addAll(node.getLeafs());
}
}
}
}
return list;
}
public int getLeafsCount() {
int count = 0;
if (!this.isLeaf()) {
List<TreeNode<SignedDocumentItem>> children = this.getChildren();
for (TreeNode<SignedDocumentItem> item : children) {
SignedDocsTreeNode node = (SignedDocsTreeNode) item;
if (node != null) {
if (node.isLeaf()) {
count += 1;
} else {
count += node.getLeafsCount();
}
}
}
}
return count;
}
}

@ -0,0 +1,41 @@
package info.bukova.isspst.ui.signeddocs;
import info.bukova.isspst.DateTimeUtils;
import info.bukova.isspst.StringUtils;
import info.bukova.isspst.data.SignedDocument;
import info.bukova.isspst.data.SignedDocumentItem;
import org.zkoss.zul.*;
public class SignedDocsTreeRenderer implements TreeitemRenderer<SignedDocsTreeNode> {
public void render(Treeitem item, SignedDocsTreeNode data, int index) throws Exception {
int deep = data.getDeep();
boolean node1 = (deep == 1);//data.getParent().getParent() == null;
boolean node3 = (deep == 3);//data.isLeaf();
boolean node2 = (deep == 2);//!node1 && !node3;
boolean node4 = (deep == 4);//!node1 && !node3;
SignedDocumentItem signedDocumentItem = data.getData();
SignedDocument signedDocument = signedDocumentItem.getSignedDocument();
Treerow tr = new Treerow();
tr.setContext("popupMenu");
item.appendChild(tr);
tr.appendChild(new Treecell(node1 ? signedDocument.getAgendaName() : ""));
tr.appendChild(new Treecell(node2 ? DateTimeUtils.getFormatedYear(signedDocument.getSignDate()) : ""));
tr.appendChild(new Treecell(node3 ? DateTimeUtils.getFormatedDate(signedDocument.getSignDate()) : ""));
tr.appendChild(new Treecell(node4 ? signedDocument.getNumser() : ""));
tr.appendChild(new Treecell(node4 ? signedDocument.getDescription() : ""));
tr.appendChild(new Treecell(node4 ? signedDocumentItem.getReportName() : data.getLeafsCount() + " souborů"));
// tr.appendChild(new Treecell(node3 ? signedDocumentItem.getFileName() : ""));
switch (deep) {
case 1 : tr.setSclass("signed-doc-agenda"); break;
case 2 : tr.setSclass("signed-doc-year"); break;
case 3 : tr.setSclass("signed-doc-date"); break;
case 4 : tr.setSclass(""); break;
}
}
}

@ -415,6 +415,9 @@ Search=Hledat
Pending = Nevyřízené
Archive = Archiv
Completed = Vyřízeno
Backup = Zálohování
SigningYear = Rok podepsání
DownloadZipArchive = Stáhnout ZIP archiv...
GenerateBillingForPassengers = Generovat společný požadavek a vyúčtování
Passenger = Pasažér

@ -183,7 +183,7 @@
<property name="rootPath" value="${storage.root}"/>
</bean>
<bean id="signeDocStorage" class="info.bukova.isspst.storage.ReportFileStorageImpl">
<bean id="signedDocStorage" class="info.bukova.isspst.storage.ReportFileStorageImpl">
<property name="rootPath" value="${storage.signedDocuments}"/>
</bean>

@ -93,3 +93,15 @@
.user-disabled {
background-color: #fff2dd !important;
}
.signed-doc-agenda {
background-color: #d0d0d0 !important;
}
.signed-doc-year {
background-color: #e0e0e0 !important;
}
.signed-doc-date {
background-color: #f0f0f0 !important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -3,6 +3,9 @@
<listbox
vflex="1"
hflex="60"
mold="paging"
pagingPosition="bottom"
autopaging="true"
selectedItem="@bind(vm.dataBean)"
onSelect="@command('onChangeSelectSignedDocs', ctrl=self)"
model="@load(vm.dataList)">

@ -0,0 +1,12 @@
<zk>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window
vflex="1"
border="none"
apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('info.bukova.isspst.ui.signeddocs.SignedDocsTreeList')">
<include
vflex="1"
src="/lists/signeddocs/treeBackup.zul" />
</window>
</zk>

@ -4,6 +4,7 @@
<zscript>
String gridActual = "/lists/signeddocs/headListActual.zul";
String gridArchive = "/lists/signeddocs/headListArchive.zul";
String treeBackup = "/lists/signeddocs/headListBackup.zul";
</zscript>
<window
vflex="1"

@ -5,6 +5,7 @@
<tabs>
<tab label="${labels.ActualDocuments}" />
<tab label="${labels.Archive}" />
<tab label="${labels.Backup}" />
</tabs>
<tabpanels>
<tabpanel>
@ -13,5 +14,8 @@
<tabpanel>
<include src="${gridArchive}" />
</tabpanel>
<tabpanel>
<include src="${treeBackup}" />
</tabpanel>
</tabpanels>
</tabbox>

@ -0,0 +1,25 @@
<hlayout vflex="1" hflex="max">
<tree id="tree"
vflex="1" hflex="max"
model="@load(vm.treeBackup)"
selectedItem="@bind(vm.selectedNodeItem)"
itemRenderer="info.bukova.isspst.ui.signeddocs.SignedDocsTreeRenderer"
sclass="addScrollbar">
<treecols>
<treecol hflex="7" label="${labels.AgendaName}"/>
<treecol hflex="4" label="${labels.SigningYear}"/>
<treecol hflex="5" label="${labels.SigningDate}"/>
<treecol hflex="5" label="${labels.Number}"/>
<treecol hflex="15" label="${labels.OrderFormDescription}"/>
<treecol hflex="6" label="${labels.ReportReport}"/>
</treecols>
</tree>
<menupopup id="popupMenu">
<menuitem
image="/img/zip-032.png"
label="${labels.DownloadZipArchive}..."
onClick="@command('onCreateZipArchive')"
/>
</menupopup>
</hlayout>
Loading…
Cancel
Save