IDEMPIERE-3997 Attachment panel : ability to download all attachments as zip file. Base on patch from Nicolas Micoud.
This commit is contained in:
parent
54aab6fea3
commit
f4aca34b6e
|
@ -20,12 +20,19 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.Target;
|
||||||
|
import org.apache.tools.ant.taskdefs.Zip;
|
||||||
|
import org.compiere.tools.FileUtil;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
@ -633,4 +640,57 @@ public class MAttachment extends X_AD_Attachment
|
||||||
return attachid;
|
return attachid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File saveAsZip() {
|
||||||
|
if (getEntryCount() < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = MTable.get(Env.getCtx(), getAD_Table_ID()).getTableName() + "_" + getRecord_ID();
|
||||||
|
|
||||||
|
File tempfolder = null;
|
||||||
|
try {
|
||||||
|
Path tempPath = Files.createTempDirectory(name);
|
||||||
|
tempfolder = tempPath.toFile();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new AdempiereException("Unable to create temp folder", e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
File destZipFile = null;
|
||||||
|
try {
|
||||||
|
destZipFile = File.createTempFile(name, ".zip");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new AdempiereException("Unable to create temp file", e);
|
||||||
|
}
|
||||||
|
destZipFile.delete();
|
||||||
|
|
||||||
|
MAttachmentEntry[] entries = getEntries();
|
||||||
|
MAttachmentEntry entry = null;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.length; i++) {
|
||||||
|
entry = entries[i];
|
||||||
|
index = i;
|
||||||
|
File destinationFile = new File(tempfolder, entry.getName());
|
||||||
|
FileUtil.copy(this, destinationFile, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Zip zipper = new Zip();
|
||||||
|
zipper.setDestFile(destZipFile);
|
||||||
|
zipper.setBasedir(tempfolder);
|
||||||
|
zipper.setUpdate(true);
|
||||||
|
zipper.setCompress(true);
|
||||||
|
zipper.setCaseSensitive(false);
|
||||||
|
zipper.setFilesonly(true);
|
||||||
|
zipper.setTaskName("zip");
|
||||||
|
zipper.setTaskType("zip");
|
||||||
|
zipper.setProject(new Project());
|
||||||
|
zipper.setOwningTarget(new Target());
|
||||||
|
zipper.execute();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileUtil.deleteDirectory(tempfolder);
|
||||||
|
} catch (IOException e) {}
|
||||||
|
|
||||||
|
return destZipFile;
|
||||||
|
}
|
||||||
} // MAttachment
|
} // MAttachment
|
||||||
|
|
|
@ -20,13 +20,21 @@ import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
|
import org.compiere.model.MAttachment;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
import org.compiere.util.Util;
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
@ -429,6 +437,13 @@ public class FileUtil
|
||||||
return localFile;
|
return localFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @return true if deleted
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* @Deprecated
|
||||||
|
*/
|
||||||
public static boolean deleteFolderRecursive(File path) throws FileNotFoundException {
|
public static boolean deleteFolderRecursive(File path) throws FileNotFoundException {
|
||||||
if (!path.exists())
|
if (!path.exists())
|
||||||
throw new FileNotFoundException(path.getAbsolutePath());
|
throw new FileNotFoundException(path.getAbsolutePath());
|
||||||
|
@ -441,4 +456,55 @@ public class FileUtil
|
||||||
return ret && path.delete();
|
return ret && path.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy attachment entry to file
|
||||||
|
* @param attachment
|
||||||
|
* @param destinationFile
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public static void copy(MAttachment attachment, File destinationFile, int index)
|
||||||
|
{
|
||||||
|
FileOutputStream destinationFileOutputStream=null;
|
||||||
|
try {
|
||||||
|
destinationFile.createNewFile();
|
||||||
|
destinationFileOutputStream = new FileOutputStream(destinationFile);
|
||||||
|
byte[] buffer = attachment.getEntryData(index);
|
||||||
|
destinationFileOutputStream.write(buffer);
|
||||||
|
}
|
||||||
|
catch( java.io.FileNotFoundException f ) {
|
||||||
|
throw new AdempiereException("File not found exception : " + destinationFile.getName() + " : " + f);
|
||||||
|
}
|
||||||
|
catch( java.io.IOException e ) {
|
||||||
|
throw new AdempiereException("IOException : " + e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (destinationFileOutputStream != null)
|
||||||
|
destinationFileOutputStream.close();
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new AdempiereException("Exception : " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete folder recursively
|
||||||
|
* @param folder
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void deleteDirectory(File folder) throws IOException {
|
||||||
|
Path directory = folder.toPath();
|
||||||
|
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Files.delete(file);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||||
|
Files.delete(dir);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} // FileUtil
|
} // FileUtil
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.adempiere.webui.panel;
|
package org.adempiere.webui.panel;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
@ -25,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.util.Callback;
|
import org.adempiere.util.Callback;
|
||||||
import org.adempiere.webui.AdempiereWebUI;
|
import org.adempiere.webui.AdempiereWebUI;
|
||||||
import org.adempiere.webui.ClientInfo;
|
import org.adempiere.webui.ClientInfo;
|
||||||
|
@ -44,6 +46,7 @@ import org.adempiere.webui.util.ZKUpdateUtil;
|
||||||
import org.adempiere.webui.window.FDialog;
|
import org.adempiere.webui.window.FDialog;
|
||||||
import org.compiere.model.MAttachment;
|
import org.compiere.model.MAttachment;
|
||||||
import org.compiere.model.MAttachmentEntry;
|
import org.compiere.model.MAttachmentEntry;
|
||||||
|
import org.compiere.model.MTable;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
import org.compiere.util.Msg;
|
import org.compiere.util.Msg;
|
||||||
|
@ -76,7 +79,7 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 4311076973993361653L;
|
private static final long serialVersionUID = 8266807399792500541L;
|
||||||
|
|
||||||
private static CLogger log = CLogger.getCLogger(WAttachment.class);
|
private static CLogger log = CLogger.getCLogger(WAttachment.class);
|
||||||
|
|
||||||
|
@ -99,6 +102,7 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
|
|
||||||
private Button bDelete = ButtonFactory.createNamedButton(ConfirmPanel.A_DELETE, false, true);
|
private Button bDelete = ButtonFactory.createNamedButton(ConfirmPanel.A_DELETE, false, true);
|
||||||
private Button bSave = new Button();
|
private Button bSave = new Button();
|
||||||
|
private Button bSaveAllAsZip = new Button();
|
||||||
private Button bDeleteAll = new Button();
|
private Button bDeleteAll = new Button();
|
||||||
private Button bLoad = new Button();
|
private Button bLoad = new Button();
|
||||||
private Button bCancel = ButtonFactory.createNamedButton(ConfirmPanel.A_CANCEL, false, true);
|
private Button bCancel = ButtonFactory.createNamedButton(ConfirmPanel.A_CANCEL, false, true);
|
||||||
|
@ -259,6 +263,7 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
toolBar.appendChild(bLoad);
|
toolBar.appendChild(bLoad);
|
||||||
toolBar.appendChild(bDelete);
|
toolBar.appendChild(bDelete);
|
||||||
toolBar.appendChild(bSave);
|
toolBar.appendChild(bSave);
|
||||||
|
toolBar.appendChild(bSaveAllAsZip);
|
||||||
toolBar.appendChild(cbContent);
|
toolBar.appendChild(cbContent);
|
||||||
toolBar.appendChild(sizeLabel);
|
toolBar.appendChild(sizeLabel);
|
||||||
|
|
||||||
|
@ -281,6 +286,15 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
bSave.setTooltiptext(Msg.getMsg(Env.getCtx(), "AttachmentSave"));
|
bSave.setTooltiptext(Msg.getMsg(Env.getCtx(), "AttachmentSave"));
|
||||||
bSave.addEventListener(Events.ON_CLICK, this);
|
bSave.addEventListener(Events.ON_CLICK, this);
|
||||||
|
|
||||||
|
bSaveAllAsZip.setEnabled(false);
|
||||||
|
bSaveAllAsZip.setSclass("img-btn");
|
||||||
|
if (ThemeManager.isUseFontIconForImage())
|
||||||
|
bSaveAllAsZip.setIconSclass("z-icon-file-zip-o");
|
||||||
|
else
|
||||||
|
bSaveAllAsZip.setImage(ThemeManager.getThemeResource("images/SaveAsZip24.png"));
|
||||||
|
bSaveAllAsZip.setTooltiptext(Msg.getMsg(Env.getCtx(), "ExportZIP"));
|
||||||
|
bSaveAllAsZip.addEventListener(Events.ON_CLICK, this);
|
||||||
|
|
||||||
if (ThemeManager.isUseFontIconForImage())
|
if (ThemeManager.isUseFontIconForImage())
|
||||||
bLoad.setIconSclass("z-icon-Import");
|
bLoad.setIconSclass("z-icon-Import");
|
||||||
else
|
else
|
||||||
|
@ -420,6 +434,7 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
sizeLabel.setText(size.toPlainString() + unit);
|
sizeLabel.setText(size.toPlainString() + unit);
|
||||||
|
|
||||||
bSave.setEnabled(true);
|
bSave.setEnabled(true);
|
||||||
|
bSaveAllAsZip.setEnabled(true);
|
||||||
bDelete.setEnabled(true);
|
bDelete.setEnabled(true);
|
||||||
|
|
||||||
if (autoPreviewList.contains(mimeType))
|
if (autoPreviewList.contains(mimeType))
|
||||||
|
@ -436,6 +451,7 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bSave.setEnabled(false);
|
bSave.setEnabled(false);
|
||||||
|
bSaveAllAsZip.setEnabled(false);
|
||||||
bDelete.setEnabled(false);
|
bDelete.setEnabled(false);
|
||||||
sizeLabel.setText("");
|
sizeLabel.setText("");
|
||||||
return false;
|
return false;
|
||||||
|
@ -572,6 +588,8 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
saveAttachmentToFile();
|
saveAttachmentToFile();
|
||||||
} else if (e.getTarget() == bRefresh) {
|
} else if (e.getTarget() == bRefresh) {
|
||||||
displayData(cbContent.getSelectedIndex(), true);
|
displayData(cbContent.getSelectedIndex(), true);
|
||||||
|
} else if (e.getTarget() == bSaveAllAsZip) {
|
||||||
|
saveAllAsZip();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // onEvent
|
} // onEvent
|
||||||
|
@ -734,4 +752,19 @@ public class WAttachment extends Window implements EventListener<Event>
|
||||||
}
|
}
|
||||||
return "UTF-8";
|
return "UTF-8";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveAllAsZip() {
|
||||||
|
File zipFile = m_attachment.saveAsZip();
|
||||||
|
|
||||||
|
if (zipFile != null) {
|
||||||
|
String name = MTable.get(Env.getCtx(), m_attachment.getAD_Table_ID()).getTableName() + "_" + m_attachment.getRecord_ID();
|
||||||
|
AMedia media = null;
|
||||||
|
try {
|
||||||
|
media = new AMedia(name, null, "application/zip", zipFile, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AdempiereException("Error when converting zip file to media : " + e);
|
||||||
|
}
|
||||||
|
Filedownload.save(media);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in New Issue